diff options
author | Jonas Gunz <himself@jonasgunz.de> | 2020-05-25 20:09:04 +0200 |
---|---|---|
committer | Jonas Gunz <himself@jonasgunz.de> | 2020-05-25 20:09:04 +0200 |
commit | 4440a86cfa359b8e40a484a2cd46d33db5455d8a (patch) | |
tree | f5c0c59aebf0058ae97e7ef8b5fb8017f459a05a | |
download | ircd-4440a86cfa359b8e40a484a2cd46d33db5455d8a.tar.gz |
Initial
207 files changed, 69923 insertions, 0 deletions
diff --git a/common/bsd.c b/common/bsd.c new file mode 100644 index 0000000..69b66e7 --- /dev/null +++ b/common/bsd.c @@ -0,0 +1,192 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/bsd.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 rcsid[] = "@(#)$Id: bsd.c,v 1.3 1998/12/13 00:02:33 kalt Exp $"; +#endif + +#include "os.h" +#ifndef CLIENT_COMPILE +# include "s_defines.h" +#else +# include "c_defines.h" +#endif +#define BSD_C +#ifndef CLIENT_COMPILE +# include "s_externs.h" +#else +# include "c_externs.h" +#endif +#undef BSD_C + +#ifdef DEBUGMODE +int writecalls = 0, writeb[10] = {0,0,0,0,0,0,0,0,0,0}; +#endif +RETSIGTYPE dummy(s) +int s; +{ +#ifndef HAVE_RELIABLE_SIGNALS + (void)signal(SIGALRM, dummy); + (void)signal(SIGPIPE, dummy); +# ifndef HPUX /* Only 9k/800 series require this, but don't know how to.. */ +# ifdef SIGWINCH + (void)signal(SIGWINCH, dummy); +# endif +# endif +#else +# if POSIX_SIGNALS + struct sigaction act; + + act.sa_handler = dummy; + act.sa_flags = 0; + (void)sigemptyset(&act.sa_mask); + (void)sigaddset(&act.sa_mask, SIGALRM); + (void)sigaddset(&act.sa_mask, SIGPIPE); +# ifdef SIGWINCH + (void)sigaddset(&act.sa_mask, SIGWINCH); +# endif + (void)sigaction(SIGALRM, &act, (struct sigaction *)NULL); + (void)sigaction(SIGPIPE, &act, (struct sigaction *)NULL); +# ifdef SIGWINCH + (void)sigaction(SIGWINCH, &act, (struct sigaction *)NULL); +# endif +# endif +#endif +} + + +/* +** deliver_it +** Attempt to send a sequence of bytes to the connection. +** Returns +** +** < 0 Some fatal error occurred, (but not EWOULDBLOCK). +** This return is a request to close the socket and +** clean up the link. +** +** >= 0 No real error occurred, returns the number of +** bytes actually transferred. EWOULDBLOCK and other +** possibly similar conditions should be mapped to +** zero return. Upper level routine will have to +** decide what to do with those unwritten bytes... +** +** *NOTE* alarm calls have been preserved, so this should +** work equally well whether blocking or non-blocking +** mode is used... +*/ +int deliver_it(cptr, str, len) +aClient *cptr; +int len; +char *str; + { + int retval; + aClient *acpt = cptr->acpt; + +#ifdef DEBUGMODE + writecalls++; +#endif +#ifndef NOWRITEALARM + (void)alarm(WRITEWAITDELAY); +#endif +#ifdef INET6 + retval = sendto(cptr->fd, str, len, 0, 0, 0); +#else + retval = send(cptr->fd, str, len, 0); +#endif + /* + ** Convert WOULDBLOCK to a return of "0 bytes moved". This + ** should occur only if socket was non-blocking. Note, that + ** all is Ok, if the 'write' just returns '0' instead of an + ** error and errno=EWOULDBLOCK. + ** + ** ...now, would this work on VMS too? --msa + */ + if (retval < 0 && (errno == EWOULDBLOCK || errno == EAGAIN || +#ifdef EMSGSIZE + errno == EMSGSIZE || +#endif + errno == ENOBUFS)) + { + retval = 0; + cptr->flags |= FLAGS_BLOCKED; + } + else if (retval > 0) + cptr->flags &= ~FLAGS_BLOCKED; + +#ifndef NOWRITEALARM + (void )alarm(0); +#endif +#ifdef DEBUGMODE + if (retval < 0) { + writeb[0]++; + Debug((DEBUG_ERROR,"write error (%s) to %s", + sys_errlist[errno], cptr->name)); +#ifndef CLIENT_COMPILE + hold_server(cptr); +#endif + } else if (retval == 0) + writeb[1]++; + else if (retval < 16) + writeb[2]++; + else if (retval < 32) + writeb[3]++; + else if (retval < 64) + writeb[4]++; + else if (retval < 128) + writeb[5]++; + else if (retval < 256) + writeb[6]++; + else if (retval < 512) + writeb[7]++; + else if (retval < 1024) + writeb[8]++; + else + writeb[9]++; +#endif + if (retval > 0) + { +#if defined(DEBUGMODE) && defined(DEBUG_WRITE) + Debug((DEBUG_WRITE, "send = %d bytes to %d[%s]:[%*.*s]\n", + retval, cptr->fd, cptr->name, retval, retval, str)); +#endif + cptr->sendB += retval; + me.sendB += retval; + if (cptr->sendB > 1023) + { + cptr->sendK += (cptr->sendB >> 10); + cptr->sendB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */ + } + if (acpt != &me) + { + acpt->sendB += retval; + if (acpt->sendB > 1023) + { + acpt->sendK += (acpt->sendB >> 10); + acpt->sendB &= 0x03ff; + } + } + else if (me.sendB > 1023) + { + me.sendK += (me.sendB >> 10); + me.sendB &= 0x03ff; + } + } + return(retval); +} diff --git a/common/bsd_ext.h b/common/bsd_ext.h new file mode 100644 index 0000000..e1ec689 --- /dev/null +++ b/common/bsd_ext.h @@ -0,0 +1,41 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/bsd_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in common/bsd.c. + */ + +/* External definitions for global variables. + */ +#ifndef BSD_C +#ifdef DEBUGMODE +extern int writecalls, writeb[]; +#endif /* DEBUGMODE */ +#endif /* BSD_C */ + +/* External definitions for global functions. + */ +#ifndef BSD_C +#define EXTERN extern +#else /* BSD_C */ +#define EXTERN +#endif /* BSD_C */ +EXTERN RETSIGTYPE dummy __P((int s)); +EXTERN int deliver_it __P((aClient *cptr, char *str, int len)); +#undef EXTERN diff --git a/common/class_def.h b/common/class_def.h new file mode 100644 index 0000000..743b672 --- /dev/null +++ b/common/class_def.h @@ -0,0 +1,58 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/class_def.h + * 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. + */ + +typedef struct Class { + int class; + int conFreq; + int pingFreq; + int maxLinks; + long maxSendq; + int maxHLocal; + int maxUHLocal; + int maxHGlobal; + int maxUHGlobal; + int links; + struct Class *next; +} aClass; + +#define Class(x) ((x)->class) +#define ConFreq(x) ((x)->conFreq) +#define PingFreq(x) ((x)->pingFreq) +#define MaxLinks(x) ((x)->maxLinks) +#define MaxSendq(x) ((x)->maxSendq) +#define MaxHLocal(x) ((x)->maxHLocal) +#define MaxUHLocal(x) ((x)->maxUHLocal) +#define MaxHGlobal(x) ((x)->maxHGlobal) +#define MaxUHGlobal(x) ((x)->maxUHGlobal) +#define Links(x) ((x)->links) +#define IncSendq(x) MaxSendq(x) = (int)((float)MaxSendq(x) * 1.1) + +#define ConfLinks(x) (Class(x)->links) +#define ConfMaxLinks(x) (Class(x)->maxLinks) +#define ConfClass(x) (Class(x)->class) +#define ConfConFreq(x) (Class(x)->conFreq) +#define ConfPingFreq(x) (Class(x)->pingFreq) +#define ConfSendq(x) (Class(x)->maxSendq) +#define ConfMaxHLocal(x) (Class(x)->maxHLocal) +#define ConfMaxUHLocal(x) (Class(x)->maxUHLocal) +#define ConfMaxHGlobal(x) (Class(x)->maxHGlobal) +#define ConfMaxUHGlobal(x) (Class(x)->maxUHGlobal) + +#define FirstClass() classes +#define NextClass(x) ((x)->next) diff --git a/common/common_def.h b/common/common_def.h new file mode 100644 index 0000000..dff2150 --- /dev/null +++ b/common/common_def.h @@ -0,0 +1,88 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/common_def.h + * Copyright (C) 1990 Armin Gruner + * + * 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. + */ + +#ifdef SPRINTF +#undef SPRINTF +#endif +#if ! USE_STDARG +#define SPRINTF (void) irc_sprintf +#else +#define SPRINTF (void) sprintf +#endif + +#define DupString(x,y) do {x = (char *)MyMalloc(strlen((char *)y) + 1);\ + (void)strcpy((char *)x, (char *)y);\ + } while(0) + +#undef tolower +#define tolower(c) (tolowertab[(u_char)(c)]) + +#undef toupper +#define toupper(c) (touppertab[(u_char)(c)]) + +#undef isalpha +#undef isdigit +#undef isxdigit +#undef isalnum +#undef isprint +#undef isascii +#undef isgraph +#undef ispunct +#undef islower +#undef isupper +#undef isspace + +#define PRINT 1 +#define CNTRL 2 +#define ALPHA 4 +#define PUNCT 8 +#define DIGIT 16 +#define SPACE 32 + +#define isalpha(c) (char_atribs[(u_char)(c)]&ALPHA) +#define isspace(c) (char_atribs[(u_char)(c)]&SPACE) +#define islower(c) ((char_atribs[(u_char)(c)]&ALPHA) && \ + ((u_char)(c) > (u_char)0x5f)) +#define isupper(c) ((char_atribs[(u_char)(c)]&ALPHA) && \ + ((u_char)(c) < (u_char)0x60)) +#define isdigit(c) (char_atribs[(u_char)(c)]&DIGIT) +#define isxdigit(c) (isdigit(c) || \ + ((u_char)'a' <= (u_char)(c) && \ + (u_char)(c) <= (u_char)'f') || \ + ((u_char)'A' <= (u_char)(c) && \ + (u_char)(c) <= (u_char)'F')) +#define isalnum(c) (char_atribs[(u_char)(c)]&(DIGIT|ALPHA)) +#define isprint(c) (char_atribs[(u_char)(c)]&PRINT) +#define isascii(c) (/*((u_char)(c) >= (u_char)'\0') &&*/ \ + ((u_char)(c) <= (u_char)0x7f)) +#define isgraph(c) ((char_atribs[(u_char)(c)]&PRINT) && \ + ((u_char)(c) != (u_char)0x20)) +#define ispunct(c) (!(char_atribs[(u_char)(c)]&(CNTRL|ALPHA|DIGIT))) + +#ifdef DEBUGMODE +# define Debug(x) debug x +# define DO_DEBUG_MALLOC +#else +# define Debug(x) ; +# define LOGFILE "/dev/null" +#endif + +#if defined(CHKCONF_COMPILE) || defined(CLIENT_COMPILE) +#undef ZIP_LINKS +#endif diff --git a/common/dbuf.c b/common/dbuf.c new file mode 100644 index 0000000..fbb8d97 --- /dev/null +++ b/common/dbuf.c @@ -0,0 +1,532 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/dbuf.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. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: dbuf.c,v 1.8 1997/09/03 17:45:13 kalt Exp $"; +#endif + +/* +** For documentation of the *global* functions implemented here, +** see the header file (dbuf.h). +** +*/ + +#include "os.h" +#ifndef CLIENT_COMPILE +# include "s_defines.h" +#else +# include "c_defines.h" +#endif +#define DBUF_C +#ifndef CLIENT_COMPILE +# include "s_externs.h" +#else +# include "c_externs.h" +#endif +#undef DBUF_C + +#undef VALLOC + +#if !defined(VALLOC) && !defined(valloc) +#define valloc malloc +#endif + +#ifdef CLIENT_COMPILE +/* kind of ugly, eh? */ +u_int dbufalloc = 0; +#endif + +u_int poolsize = (BUFFERPOOL > 1500000) ? BUFFERPOOL : 1500000; +dbufbuf *freelist = NULL; + +/* dbuf_init--initialize a stretch of memory as dbufs. + Doing this early on should save virtual memory if not real memory.. + at the very least, we get more control over what the server is doing + + mika@cs.caltech.edu 6/24/95 +*/ + +void dbuf_init() +{ + dbufbuf *dbp; + int i = 0, nb; + + nb = poolsize / sizeof(dbufbuf); + freelist = (dbufbuf *)valloc(nb * sizeof(dbufbuf)); + if (!freelist) + return; /* screw this if it doesn't work */ + dbp = freelist; +#ifndef CLIENT_COMPILE + for( ; i < (nb - 1); i++, dbp++, istat.is_dbufnow++) +#else + for( ; i < (nb - 1); i++, dbp++) +#endif + dbp->next = (dbp + 1); + dbp->next = NULL; +#ifndef CLIENT_COMPILE + istat.is_dbufnow++; + istat.is_dbuf = istat.is_dbufnow; +#endif +} + +/* +** dbuf_alloc - allocates a dbufbuf structure either from freelist or +** creates a new one. +** Return: 0 on success, -1 on fatal alloc error, -2 on pool exceeding +*/ +static int dbuf_alloc(dbptr) +dbufbuf **dbptr; +{ +#if defined(VALLOC) && !defined(DEBUGMODE) + Reg dbufbuf *db2ptr; + Reg int num; +#endif + +#ifndef CLIENT_COMPILE + if (istat.is_dbufuse++ == istat.is_dbufmax) + istat.is_dbufmax = istat.is_dbufuse; +#else + dbufalloc++; +#endif + if ((*dbptr = freelist)) + { + freelist = freelist->next; + return 0; + } +#ifndef CLIENT_COMPILE + if (istat.is_dbufuse * DBUFSIZ > poolsize) +#else + if (dbufalloc * DBUFSIZ > poolsize) +#endif + { +#ifndef CLIENT_COMPILE + istat.is_dbufuse--; +#else + dbufalloc--; +#endif + return -2; /* Not fatal, go back and increase poolsize */ + } + +#if defined(_SC_PAGE_SIZE) && !defined(_SC_PAGESIZE) +#define _SC_PAGESIZE _SC_PAGE_SIZE +#endif +#if defined(VALLOC) && !defined(DEBUGMODE) +# if defined(SOL20) || defined(_SC_PAGESIZE) + num = sysconf(_SC_PAGESIZE)/sizeof(dbufbuf); +# else + num = getpagesize()/sizeof(dbufbuf); +# endif + if (num < 0) + num = 1; + +#ifndef CLIENT_COMPILE + istat.is_dbufnow += num; +#endif + + *dbptr = (dbufbuf *)valloc(num*sizeof(dbufbuf)); + if (!*dbptr) + return -1; + + num--; + for (db2ptr = *dbptr; num; num--) + { + db2ptr = (dbufbuf *)((char *)db2ptr + sizeof(dbufbuf)); + db2ptr->next = freelist; + freelist = db2ptr; + } + return 0; +#else +#ifndef CLIENT_COMPILE + istat.is_dbufnow++; +#endif + if (!(*dbptr = (dbufbuf *)MyMalloc(sizeof(dbufbuf)))) + return -1; + return 0; +#endif +} +/* +** dbuf_free - return a dbufbuf structure to the freelist +*/ +static void dbuf_free(ptr) +Reg dbufbuf *ptr; +{ +#ifndef CLIENT_COMPILE + istat.is_dbufuse--; +#else + dbufalloc--; +#endif + ptr->next = freelist; + freelist = ptr; +} +/* +** This is called when malloc fails. Scrap the whole content +** of dynamic buffer and return -1. (malloc errors are FATAL, +** there is no reason to continue this buffer...). After this +** the "dbuf" has consistent EMPTY status... ;) +*/ +int dbuf_malloc_error(dyn) +dbuf *dyn; + { + dbufbuf *p; + + dyn->length = 0; + dyn->offset = 0; + while ((p = dyn->head) != NULL) + { + dyn->head = p->next; + dbuf_free(p); + } +#ifdef DBUF_TAIL + dyn->tail = dyn->head; +#endif + return -1; + } + + +/* +** dbuf_put +** Append the number of bytes to the buffer, allocating more +** memory as needed. Bytes are copied into internal buffers +** from users buffer. +** +** returns > 0, if operation successfull +** < 0, if failed (due memory allocation problem) +*/ +int dbuf_put(dyn, buf, length) +dbuf *dyn; /* Dynamic buffer header */ +char *buf; /* Pointer to data to be stored */ +int length; /* Number of bytes to store */ +{ + Reg dbufbuf **h; + dbufbuf *d; +#ifdef DBUF_TAIL + dbufbuf *dtail; + Reg int off; +#else + Reg int nbr, off; +#endif + Reg int chunk, i, dlength; + + dlength = dyn->length; + + off = (dyn->offset + dyn->length) % DBUFSIZ; +#ifdef DBUF_TAIL + dtail = dyn->tail; + if (!dyn->length) + h = &(dyn->head); + else + { + if (off) + h = &(dyn->tail); + else + h = &(dyn->tail->next); + } +#else + /* + ** Locate the last non-empty buffer. If the last buffer is + ** full, the loop will terminate with 'd==NULL'. This loop + ** assumes that the 'dyn->length' field is correctly + ** maintained, as it should--no other check really needed. + */ + nbr = (dyn->offset + dyn->length) / DBUFSIZ; + for (h = &(dyn->head); (d = *h) && --nbr >= 0; h = &(d->next)); +#endif + /* + ** Append users data to buffer, allocating buffers as needed + */ + chunk = DBUFSIZ - off; + dyn->length += length; + for ( ;length > 0; h = &(d->next)) + { + if ((d = *h) == NULL) + { + if ((i = dbuf_alloc(&d))) + { + if (i == -1) /* out of memory, cleanup */ + /* modifies dyn->tail */ + dbuf_malloc_error(dyn); + else + /* If we run out of bufferpool, visit upper + * level to increase it and retry. -Vesa + */ + { + /* + ** Cancel this dbuf_put as well, + ** since it is incomplete. -krys + */ + dyn->length = dlength; +#ifdef DBUF_TAIL + dyn->tail = dtail; +#endif + } + return i; + } +#ifdef DBUF_TAIL + dyn->tail = d; +#endif + *h = d; + d->next = NULL; + } + if (chunk > length) + chunk = length; + bcopy(buf, d->data + off, chunk); + length -= chunk; + buf += chunk; + off = 0; + chunk = DBUFSIZ; + } + return 1; + } + + +/* +** dbuf_map, dbuf_delete +** These functions are meant to be used in pairs and offer +** a more efficient way of emptying the buffer than the +** normal 'dbuf_get' would allow--less copying needed. +** +** map returns a pointer to a largest contiguous section +** of bytes in front of the buffer, the length of the +** section is placed into the indicated "long int" +** variable. Returns NULL *and* zero length, if the +** buffer is empty. +** +** delete removes the specified number of bytes from the +** front of the buffer releasing any memory used for them. +** +** Example use (ignoring empty condition here ;) +** +** buf = dbuf_map(&dyn, &count); +** <process N bytes (N <= count) of data pointed by 'buf'> +** dbuf_delete(&dyn, N); +** +** Note: delete can be used alone, there is no real binding +** between map and delete functions... +*/ +char *dbuf_map(dyn,length) +dbuf *dyn; /* Dynamic buffer header */ +int *length; /* Return number of bytes accessible */ + { + if (dyn->head == NULL) + { +#ifdef DBUF_TAIL + dyn->tail = NULL; +#endif + *length = 0; + return NULL; + } + *length = DBUFSIZ - dyn->offset; + if (*length > dyn->length) + *length = dyn->length; + return (dyn->head->data + dyn->offset); + } + +int dbuf_delete(dyn,length) +dbuf *dyn; /* Dynamic buffer header */ +int length; /* Number of bytes to delete */ + { + dbufbuf *d; + int chunk; + + if (length > dyn->length) + length = dyn->length; + chunk = DBUFSIZ - dyn->offset; + while (length > 0) + { + if (chunk > length) + chunk = length; + length -= chunk; + dyn->offset += chunk; + dyn->length -= chunk; + if (dyn->offset == DBUFSIZ || dyn->length == 0) + { + if ((d = dyn->head)) + { /* What did I do? A memory leak.. ? */ + dyn->head = d->next; + dbuf_free(d); + } + dyn->offset = 0; + } + chunk = DBUFSIZ; + } + if (dyn->head == (dbufbuf *)NULL) +#ifdef DBUF_TAIL + { + dyn->tail = NULL; +#endif + dyn->length = 0; +#ifdef DBUF_TAIL + } +#endif + return 0; + } + +/* +** dbuf_get +** Remove number of bytes from the buffer, releasing dynamic +** memory, if applicaple. Bytes are copied from internal buffers +** to users buffer. +** +** returns the number of bytes actually copied to users buffer, +** if >= 0, any value less than the size of the users +** buffer indicates the dbuf became empty by this operation. +** +** Return 0 indicates that buffer was already empty. +** +** Negative return values indicate some unspecified +** error condition, rather fatal... +*/ +int dbuf_get(dyn, buf, length) +dbuf *dyn; /* Dynamic buffer header */ +char *buf; /* Pointer to buffer to receive the data */ +int length; /* Max amount of bytes that can be received */ + { + int moved = 0; + int chunk; + char *b; + + while (length > 0 && (b = dbuf_map(dyn, &chunk)) != NULL) + { + if (chunk > length) + chunk = length; + bcopy(b, buf, (int)chunk); + (void)dbuf_delete(dyn, chunk); + buf += chunk; + length -= chunk; + moved += chunk; + } + return moved; + } + +/* +int dbuf_copy(dyn, buf, length) +dbuf *dyn; +register char *buf; +int length; +{ + register dbufbuf *d = dyn->head; + register char *s; + register int chunk, len = length, dlen = dyn->length; + + s = d->data + dyn->offset; + chunk = MIN(DBUFSIZ - dyn->offset, dlen); + + while (len > 0) + { + if (chunk > dlen) + chunk = dlen; + if (chunk > len) + chunk = len; + + bcopy(s, buf, chunk); + buf += chunk; + len -= chunk; + dlen -= chunk; + + if (dlen > 0 && (d = d->next)) + { + chunk = DBUFSIZ; + s = d->data; + } + else + break; + } + return length - len; +} +*/ + +/* +** dbuf_getmsg +** +** Check the buffers to see if there is a string which is terminted with +** either a \r or \n prsent. If so, copy as much as possible (determined by +** length) into buf and return the amount copied - else return 0. +*/ +int dbuf_getmsg(dyn, buf, length) +dbuf *dyn; +char *buf; +register int length; +{ + dbufbuf *d; + register char *s; + register int dlen; + register int i; + int copy; + +getmsg_init: + d = dyn->head; + dlen = dyn->length; + i = DBUFSIZ - dyn->offset; + if (i <= 0) + return -1; + copy = 0; + if (d && dlen) + s = dyn->offset + d->data; + else + return 0; + + if (i > dlen) + i = dlen; + while (length > 0 && dlen > 0) + { + dlen--; + if (*s == '\n' || *s == '\r') + { + copy = dyn->length - dlen; + /* + ** Shortcut this case here to save time elsewhere. + ** -avalon + */ + if (copy == 1) + { + (void)dbuf_delete(dyn, 1); + goto getmsg_init; + } + break; + } + length--; + if (!--i) + { + if ((d = d->next)) + { + s = d->data; + i = MIN(DBUFSIZ, dlen); + } + } + else + s++; + } + + if (copy <= 0) + return 0; + + /* + ** copy as much of the message as wanted into parse buffer + */ + i = dbuf_get(dyn, buf, MIN(copy, length)); + /* + ** and delete the rest of it! + */ + if (copy - i > 0) + (void)dbuf_delete(dyn, copy - i); + if (i >= 0) + *(buf+i) = '\0'; /* mark end of messsage */ + + return i; +} diff --git a/common/dbuf_def.h b/common/dbuf_def.h new file mode 100644 index 0000000..1295d2d --- /dev/null +++ b/common/dbuf_def.h @@ -0,0 +1,96 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/dbuf_def.h + * 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. + */ + +#define DBUF_TAIL + +/* +** dbuf is a collection of functions which can be used to +** maintain a dynamic buffering of a byte stream. +** Functions allocate and release memory dynamically as +** required [Actually, there is nothing that prevents +** this package maintaining the buffer on disk, either] +*/ + +/* +** These structure definitions are only here to be used +** as a whole, *DO NOT EVER REFER TO THESE FIELDS INSIDE +** THE STRUCTURES*! It must be possible to change the internal +** implementation of this package without changing the +** interface. +*/ +#if !defined(_SEQUENT_) +typedef struct dbuf + { + u_int length; /* Current number of bytes stored */ + u_int offset; /* Offset to the first byte */ + struct dbufbuf *head; /* First data buffer, if length > 0 */ +#ifdef DBUF_TAIL + /* added by mnystrom@mit.edu: */ + struct dbufbuf *tail; /* last data buffer, if length > 0 */ +#endif + } dbuf; +#else +typedef struct dbuf + { + uint length; /* Current number of bytes stored */ + uint offset; /* Offset to the first byte */ + struct dbufbuf *head; /* First data buffer, if length > 0 */ +#ifdef DBUF_TAIL + /* added by mnystrom@mit.edu: */ + struct dbufbuf *tail; /* last data buffer, if length > 0 */ +#endif + } dbuf; +#endif +/* +** And this 'dbufbuf' should never be referenced outside the +** implementation of 'dbuf'--would be "hidden" if C had such +** keyword... +** If it was possible, this would compile to be exactly 1 memory +** page in size. 2048 bytes seems to be the most common size, so +** as long as a pointer is 4 bytes, we get 2032 bytes for buffer +** data after we take away a bit for malloc to play with. -avalon +*/ +typedef struct dbufbuf + { + struct dbufbuf *next; /* Next data buffer, NULL if this is last */ + char data[2032]; /* Actual data stored here */ + } dbufbuf; + +/* +** DBufLength +** Return the current number of bytes stored into the buffer. +** (One should use this instead of referencing the internal +** length field explicitly...) +*/ +#define DBufLength(dyn) ((dyn)->length) + +/* +** DBufClear +** Scratch the current content of the buffer. Release all +** allocated buffers and make it empty. +*/ +#define DBufClear(dyn) dbuf_delete((dyn),DBufLength(dyn)) + +/* This is a dangerous define because a broken compiler will set DBUFSIZ +** to 4, which will work but will be very inefficient. However, there +** are other places where the code breaks badly if this is screwed +** up, so... -- Wumpus +*/ + +#define DBUFSIZ sizeof(((dbufbuf *)0)->data) diff --git a/common/dbuf_ext.h b/common/dbuf_ext.h new file mode 100644 index 0000000..da0a659 --- /dev/null +++ b/common/dbuf_ext.h @@ -0,0 +1,49 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/dbuf_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in common/dbuf.c. + */ + +/* External definitions for global variables. + */ +#ifndef DBUF_C +#ifdef CLIENT_COMPILE +extern u_int dbufalloc; +#endif +extern u_int poolsize; +extern dbufbuf *freelist; +#endif /* DBUF_C */ + +/* External definitions for global functions. + */ +#ifndef DBUF_C +#define EXTERN extern +#else /* DBUF_C */ +#define EXTERN +#endif /* DBUF_C */ +EXTERN void dbuf_init(); +EXTERN int dbuf_malloc_error __P((dbuf *dyn)); +EXTERN int dbuf_put __P((dbuf *dyn, char *buf, int length)); +EXTERN char *dbuf_map __P((dbuf *dyn, int *length)); +EXTERN int dbuf_delete __P((dbuf *dyn, int length)); +EXTERN int dbuf_get __P((dbuf *dyn, char *buf, int length)); +EXTERN int dbuf_copy __P((dbuf *dyn, register char *buf, int length)); +EXTERN int dbuf_getmsg __P((dbuf *dyn, char *buf, register int length)); +#undef EXTERN diff --git a/common/match.c b/common/match.c new file mode 100644 index 0000000..ad2bda6 --- /dev/null +++ b/common/match.c @@ -0,0 +1,314 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/match.c + * 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. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: match.c,v 1.5 1999/02/05 22:00:25 kalt Exp $"; +#endif + +#include "os.h" +#ifndef CLIENT_COMPILE +# include "s_defines.h" +#else +# include "c_defines.h" +#endif +#define MATCH_C +#ifndef CLIENT_COMPILE +# include "s_externs.h" +#else +# include "c_externs.h" +#endif +#undef MATCH_C + +unsigned char tolowertab[] = + { 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, + 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, + ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', + '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ':', ';', '<', '=', '>', '?', + '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', + '_', + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', + 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', + 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', + 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, + 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, + 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; + +unsigned char touppertab[] = + { 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, + 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, + 0x1e, 0x1f, + ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')', + '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ':', ';', '<', '=', '>', '?', + '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', + 0x5f, + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', + 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', + 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', + 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, + 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, + 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, + 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, + 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, + 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, + 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, + 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, + 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; + +unsigned char char_atribs[] = { +/* 0-7 */ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, +/* 8-12 */ CNTRL, CNTRL|SPACE, CNTRL|SPACE, CNTRL|SPACE, CNTRL|SPACE, +/* 13-15 */ CNTRL|SPACE, CNTRL, CNTRL, +/* 16-23 */ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, +/* 24-31 */ CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, CNTRL, +/* space */ PRINT|SPACE, +/* !""#$%&'( */ PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, +/* )*+,-./ */ PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, PRINT, +/* 0123 */ PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, +/* 4567 */ PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, PRINT|DIGIT, +/* 89:; */ PRINT|DIGIT, PRINT|DIGIT, PRINT, PRINT, +/* <=>? */ PRINT, PRINT, PRINT, PRINT, +/* @ */ PRINT, +/* ABC */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* DEF */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* GHI */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* JKL */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* MNO */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* PQR */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* STU */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* VWX */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* YZ[ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* \]^ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* _ */ PRINT, +/* abc */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* def */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* ghi */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* jkl */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* mno */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* pqr */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* stu */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* vwx */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* yz{ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* \}~ */ PRINT|ALPHA, PRINT|ALPHA, PRINT|ALPHA, +/* del */ 0, +/* 80-8f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* 90-9f */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* a0-af */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* b0-bf */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* c0-cf */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* d0-df */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* e0-ef */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/* f0-ff */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + +#define MAX_ITERATIONS 512 +/* +** Compare if a given string (name) matches the given +** mask (which can contain wild cards: '*' - match any +** number of chars, '?' - match any single character. +** +** return 0, if match +** 1, if no match +*/ + +/* +** match() +** Iterative matching function, rather than recursive. +** Written by Douglas A Lewis (dalewis@acsu.buffalo.edu) +*/ + +int match(mask, name) +char *mask, *name; +{ + Reg u_char *m = (u_char *)mask, *n = (u_char *)name; + char *ma = mask, *na = name; + int wild = 0, q = 0, calls = 0; + + while (1) + { +#ifdef MAX_ITERATIONS + if (calls++ > MAX_ITERATIONS) + break; +#endif + + if (*m == '*') + { + while (*m == '*') + m++; + wild = 1; + ma = (char *)m; + na = (char *)n; + } + + if (!*m) + { + if (!*n) + return 0; + for (m--; (m > (u_char *)mask) && (*m == '?'); m--) + ; + if ((m > (u_char *)mask) && (*m == '*') && + (m[-1] != '\\')) + return 0; + if (!wild) + return 1; + m = (u_char *)ma; + n = (u_char *)++na; + } + else if (!*n) + return 1; + if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?'))) + { + m++; + q = 1; + } + else + q = 0; + + if ((tolower(*m) != tolower(*n)) && ((*m != '?') || q)) + { + if (!wild) + return 1; + m = (u_char *)ma; + n = (u_char *)++na; + } + else + { + if (*m) + m++; + if (*n) + n++; + } + } + + return 1; +} + + +/* +** collapse a pattern string into minimal components. +** This particular version is "in place", so that it changes the pattern +** which is to be reduced to a "minimal" size. +*/ +char *collapse(pattern) +char *pattern; +{ + Reg char *s = pattern, *s1, *t; + + if (BadPtr(pattern)) + return pattern; + /* + * Collapse all \** into \*, \*[?]+\** into \*[?]+ + */ + for (; *s; s++) + if (*s == '\\') + if (!*(s + 1)) + break; + else + s++; + else if (*s == '*') + { + if (*(t = s1 = s + 1) == '*') + while (*t == '*') + t++; + else if (*t == '?') + for (t++, s1++; *t == '*' || *t == '?'; t++) + if (*t == '?') + *s1++ = *t; + while ((*s1++ = *t++)) + ; + } + return pattern; +} + + +/* +** Case insensitive comparison of two NULL terminated strings. +** +** returns 0, if s1 equal to s2 +** <0, if s1 lexicographically less than s2 +** >0, if s1 lexicographically greater than s2 +*/ +int mycmp(s1, s2) +char *s1; +char *s2; + { + Reg unsigned char *str1 = (unsigned char *)s1; + Reg unsigned char *str2 = (unsigned char *)s2; + Reg int res; + + while ((res = toupper(*str1) - toupper(*str2)) == 0) + { + if (*str1 == '\0') + return 0; + str1++; + str2++; + } + return (res); + } + + +int myncmp(str1, str2, n) +char *str1; +char *str2; +int n; + { + Reg unsigned char *s1 = (unsigned char *)str1; + Reg unsigned char *s2 = (unsigned char *)str2; + Reg int res; + + while ((res = toupper(*s1) - toupper(*s2)) == 0) + { + s1++; s2++; n--; + if (n == 0 || (*s1 == '\0' && *s2 == '\0')) + return 0; + } + return (res); + } diff --git a/common/match_ext.h b/common/match_ext.h new file mode 100644 index 0000000..4953bcf --- /dev/null +++ b/common/match_ext.h @@ -0,0 +1,43 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/match_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in common/match.c. + */ + +/* External definitions for global variables. + */ +#ifndef MATCH_C +extern unsigned char tolowertab[]; +extern unsigned char touppertab[]; +extern unsigned char char_atribs[]; +#endif /* MATCH_C */ + +/* External definitions for global functions. + */ +#ifndef MATCH_C +#define EXTERN extern +#else /* MATCH_C */ +#define EXTERN +#endif /* MATCH_C */ +EXTERN int match __P((char *mask, char *name)); +EXTERN char *collapse __P((char *pattern)); +EXTERN int mycmp __P((char *s1, char *s2)); +EXTERN int myncmp __P((char *str1, char *str2, int n)); +#undef EXTERN diff --git a/common/msg_def.h b/common/msg_def.h new file mode 100644 index 0000000..9d6096d --- /dev/null +++ b/common/msg_def.h @@ -0,0 +1,77 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/msg_def.h + * 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. + */ + +#define MSG_PRIVATE "PRIVMSG" /* PRIV */ +#define MSG_WHO "WHO" /* WHO -> WHOC */ +#define MSG_WHOIS "WHOIS" /* WHOI */ +#define MSG_WHOWAS "WHOWAS" /* WHOW */ +#define MSG_USER "USER" /* USER */ +#define MSG_NICK "NICK" /* NICK */ +#define MSG_SERVER "SERVER" /* SERV */ +#define MSG_LIST "LIST" /* LIST */ +#define MSG_TOPIC "TOPIC" /* TOPI */ +#define MSG_INVITE "INVITE" /* INVI */ +#define MSG_VERSION "VERSION" /* VERS */ +#define MSG_QUIT "QUIT" /* QUIT */ +#define MSG_SQUIT "SQUIT" /* SQUI */ +#define MSG_KILL "KILL" /* KILL */ +#define MSG_INFO "INFO" /* INFO */ +#define MSG_LINKS "LINKS" /* LINK */ +#define MSG_SUMMON "SUMMON" /* SUMM */ +#define MSG_STATS "STATS" /* STAT */ +#define MSG_USERS "USERS" /* USER -> USRS */ +#define MSG_HELP "HELP" /* HELP */ +#define MSG_ERROR "ERROR" /* ERRO */ +#define MSG_AWAY "AWAY" /* AWAY */ +#define MSG_CONNECT "CONNECT" /* CONN */ +#define MSG_PING "PING" /* PING */ +#define MSG_PONG "PONG" /* PONG */ +#define MSG_OPER "OPER" /* OPER */ +#define MSG_PASS "PASS" /* PASS */ +#define MSG_WALLOPS "WALLOPS" /* WALL */ +#define MSG_TIME "TIME" /* TIME */ +#define MSG_NAMES "NAMES" /* NAME */ +#define MSG_ADMIN "ADMIN" /* ADMI */ +#define MSG_TRACE "TRACE" /* TRAC */ +#define MSG_NOTICE "NOTICE" /* NOTI */ +#define MSG_JOIN "JOIN" /* JOIN */ +#define MSG_NJOIN "NJOIN" /* NJOIN */ +#define MSG_PART "PART" /* PART */ +#define MSG_LUSERS "LUSERS" /* LUSE */ +#define MSG_MOTD "MOTD" /* MOTD */ +#define MSG_MODE "MODE" /* MODE */ +#define MSG_UMODE "UMODE" /* UMOD */ +#define MSG_KICK "KICK" /* KICK */ +#define MSG_RECONECT "RECONNECT" /* RECONNECT -> RECO */ +#define MSG_SERVICE "SERVICE" /* SERV -> SRVI */ +#define MSG_USERHOST "USERHOST" /* USER -> USRH */ +#define MSG_ISON "ISON" /* ISON */ +#define MSG_NOTE "NOTE" /* NOTE */ +#define MSG_SQUERY "SQUERY" /* SQUE */ +#define MSG_SERVLIST "SERVLIST" /* SERV -> SLIS */ +#define MSG_SERVSET "SERVSET" /* SERV -> SSET */ +#define MSG_REHASH "REHASH" /* REHA */ +#define MSG_RESTART "RESTART" /* REST */ +#define MSG_CLOSE "CLOSE" /* CLOS */ +#define MSG_DIE "DIE" +#define MSG_HASH "HAZH" /* HASH */ +#define MSG_DNS "DNS" /* DNS -> DNSS */ + +#define MAXPARA 15 diff --git a/common/numeric_def.h b/common/numeric_def.h new file mode 100644 index 0000000..c1b095c --- /dev/null +++ b/common/numeric_def.h @@ -0,0 +1,337 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/numeric_def.h + * 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. + */ + +/* + * -- Avalon -- 1 Sep 1992 + * + * Added RPL_TRACELOG, RPL_STATSOLINE + */ + +/* + * -- Avalon -- 13 Aug 1992 + * + * Added ERR_BADCHANNELKEY, ERR_KEYSET + */ + +/* + * -- Avalon -- 10 Aug 1992 + * + * Added RPL_SUMMONING + */ + +/* + * -- Avalon -- 5 Jul 1992 + * + * Added ERR_NICKCOLLISION + */ + +/* + * -- Avalon -- 14 Jul 1992 + * + * Added RPL_UNAWAY, RPL_NOWAWAY, ERR_NOORIGIN, ERR_FILEERROR, ERR_NOLOGIN, + * ERR_SUMMONDISABLED, ERR_USERSDISABLED, RPL_USERSSTART, RPL_USERS, + * RPL_ENDOFUSERS, RPL_NOUSERS + */ + +/* + * -- Avalon -- 12 Jul 1992 + * + * Added RPL_CLOSING RPL_CLOSEEND + */ + +/* + * -- Avalon -- 10-11 Jul 1992 + * + * Added RPL_MOTD, RPL_MOTDSTART, RPL_ENDOFMOTD, ERR_NOMOTD, + * RPL_INFO, RPL_INFOSTART, RPL_ENDOFINFO, ERR_CANTKILLSERVER, + * RPL_LUSERCLIENT, RPL_LUSEROP, RPL_LUSERUNKNOWN, RPL_LUSERCHAN, RPL_LUSERME, + * RPL_STATSUPTIME, RPL_ADMINLOC1, RPL_ADMINLOC2, RPL_ADMINME, + * RPL_ADMINEMAIL, ERR_NOADMININFO + */ + +/* + * -- Avalon -- 28 Jun 1992 + * + * Added ERR_BADCHANMASK and RPL_ENDOFWHOWAS + */ + +/* + * -- Avalon -- 13 May 1992 + * + * Added RPL_STATSLLINE + */ + +/* + * -- Avalon -- 12 Jan 1992 + * + * Added RPL_TRACELINK + */ + +/* + * -- Wumpus -- 30 Nov 1991 + * + * It's very important that you never change what a numeric means -- + * you can delete old ones (maybe) and add new ones, but never ever + * take a number and make it suddenly mean something else, or change + * an old number just for the hell of it. + */ + +/* + * -- avalon -- 19 Nov 1991 + * Added ERR_USERSDONTMATCH + * + * -- avalon -- 06 Nov 1991 + * Added RPL_BANLIST, RPL_BANLISTEND, ERR_BANNEDFROMCHAN + * + * -- avalon -- 15 Oct 1991 + * Added RPL_TRACEs (201-209) + * Added RPL_STATSs (211-219) + */ + +/* -- Jto -- 16 Jun 1990 + * A couple of new numerics added... + */ + +/* -- Jto -- 03 Jun 1990 + * Added ERR_YOUWILLBEBANNED and Check defines (sigh, had to put 'em here..) + * Added ERR_UNKNOWNMODE... + * Added ERR_CANNOTSENDTOCHAN... + */ + +/* + * Reserve numerics 000-099 for server-client connections where the client + * is local to the server. If any server is passed a numeric in this range + * from another server then it is remapped to 100-199. -avalon + */ +#define RPL_WELCOME 001 +#define RPL_YOURHOST 002 +#define RPL_CREATED 003 +#define RPL_MYINFO 004 +#define RPL_BOUNCE 005 + +/* + * Errors are in the range from 400-599 currently and are grouped by what + * commands they come from. + */ +#define ERR_NOSUCHNICK 401 +#define ERR_NOSUCHSERVER 402 +#define ERR_NOSUCHCHANNEL 403 +#define ERR_CANNOTSENDTOCHAN 404 +#define ERR_TOOMANYCHANNELS 405 +#define ERR_WASNOSUCHNICK 406 +#define ERR_TOOMANYTARGETS 407 +#define ERR_NOSUCHSERVICE 408 +#define ERR_NOORIGIN 409 + +#define ERR_NORECIPIENT 411 +#define ERR_NOTEXTTOSEND 412 +#define ERR_NOTOPLEVEL 413 +#define ERR_WILDTOPLEVEL 414 +#define ERR_BADMASK 415 +#define ERR_TOOMANYMATCHES 416 + +#define ERR_UNKNOWNCOMMAND 421 +#define ERR_NOMOTD 422 +#define ERR_NOADMININFO 423 +#define ERR_FILEERROR 424 + +#define ERR_NONICKNAMEGIVEN 431 +#define ERR_ERRONEUSNICKNAME 432 +#define ERR_NICKNAMEINUSE 433 +#define ERR_SERVICENAMEINUSE 434 +#define ERR_SERVICECONFUSED 435 +#define ERR_NICKCOLLISION 436 +#define ERR_UNAVAILRESOURCE 437 +/* #define ERR_DEAD 438 reserved for later use -krys */ + +#define ERR_USERNOTINCHANNEL 441 +#define ERR_NOTONCHANNEL 442 +#define ERR_USERONCHANNEL 443 +#define ERR_NOLOGIN 444 +#define ERR_SUMMONDISABLED 445 +#define ERR_USERSDISABLED 446 + +#define ERR_NOTREGISTERED 451 + +#define ERR_NEEDMOREPARAMS 461 +#define ERR_ALREADYREGISTRED 462 +#define ERR_NOPERMFORHOST 463 +#define ERR_PASSWDMISMATCH 464 +#define ERR_YOUREBANNEDCREEP 465 +#define ERR_YOUWILLBEBANNED 466 +#define ERR_KEYSET 467 + +#define ERR_CHANNELISFULL 471 +#define ERR_UNKNOWNMODE 472 +#define ERR_INVITEONLYCHAN 473 +#define ERR_BANNEDFROMCHAN 474 +#define ERR_BADCHANNELKEY 475 +#define ERR_BADCHANMASK 476 +#define ERR_NOCHANMODES 477 +#define ERR_BANLISTFULL 478 + +#define ERR_NOPRIVILEGES 481 +#define ERR_CHANOPRIVSNEEDED 482 +#define ERR_CANTKILLSERVER 483 +#define ERR_RESTRICTED 484 +#define ERR_UNIQOPRIVSNEEDED 485 + +#define ERR_NOOPERHOST 491 +#define ERR_NOSERVICEHOST 492 + +#define ERR_UMODEUNKNOWNFLAG 501 +#define ERR_USERSDONTMATCH 502 + +/* + * Numberic replies from server commands. + * These are currently in the range 200-399. + */ +#define RPL_NONE 300 +#define RPL_AWAY 301 +#define RPL_USERHOST 302 +#define RPL_ISON 303 +#define RPL_TEXT 304 +#define RPL_UNAWAY 305 +#define RPL_NOWAWAY 306 + +#define RPL_WHOISUSER 311 +#define RPL_WHOISSERVER 312 +#define RPL_WHOISOPERATOR 313 + +#define RPL_WHOWASUSER 314 +/* rpl_endofwho below (315) */ +#define RPL_ENDOFWHOWAS 369 + +#define RPL_WHOISCHANOP 316 /* redundant and not needed but reserved */ +#define RPL_WHOISIDLE 317 + +#define RPL_ENDOFWHOIS 318 +#define RPL_WHOISCHANNELS 319 + +#define RPL_LISTSTART 321 +#define RPL_LIST 322 +#define RPL_LISTEND 323 +#define RPL_CHANNELMODEIS 324 +#define RPL_UNIQOPIS 325 + +#define RPL_NOTOPIC 331 +#define RPL_TOPIC 332 + +#define RPL_INVITING 341 +#define RPL_SUMMONING 342 + +#define RPL_INVITELIST 346 +#define RPL_ENDOFINVITELIST 347 + +#define RPL_EXCEPTLIST 348 +#define RPL_ENDOFEXCEPTLIST 349 + +#define RPL_VERSION 351 + +#define RPL_WHOREPLY 352 +#define RPL_ENDOFWHO 315 +#define RPL_NAMREPLY 353 +#define RPL_ENDOFNAMES 366 + +#define RPL_KILLDONE 361 +#define RPL_CLOSING 362 +#define RPL_CLOSEEND 363 +#define RPL_LINKS 364 +#define RPL_ENDOFLINKS 365 +/* rpl_endofnames above (366) */ +#define RPL_BANLIST 367 +#define RPL_ENDOFBANLIST 368 +/* rpl_endofwhowas above (369) */ + +#define RPL_INFO 371 +#define RPL_MOTD 372 +#define RPL_INFOSTART 373 +#define RPL_ENDOFINFO 374 +#define RPL_MOTDSTART 375 +#define RPL_ENDOFMOTD 376 + +#define RPL_YOUREOPER 381 +#define RPL_REHASHING 382 +#define RPL_YOURESERVICE 383 +#define RPL_MYPORTIS 384 +#define RPL_NOTOPERANYMORE 385 + +#define RPL_TIME 391 +#define RPL_USERSSTART 392 +#define RPL_USERS 393 +#define RPL_ENDOFUSERS 394 +#define RPL_NOUSERS 395 + +#define RPL_TRACELINK 200 +#define RPL_TRACECONNECTING 201 +#define RPL_TRACEHANDSHAKE 202 +#define RPL_TRACEUNKNOWN 203 +#define RPL_TRACEOPERATOR 204 +#define RPL_TRACEUSER 205 +#define RPL_TRACESERVER 206 +#define RPL_TRACESERVICE 207 +#define RPL_TRACENEWTYPE 208 +#define RPL_TRACECLASS 209 +#define RPL_TRACERECONNECT 210 + +#define RPL_STATSLINKINFO 211 +#define RPL_STATSCOMMANDS 212 +#define RPL_STATSCLINE 213 +#define RPL_STATSNLINE 214 +#define RPL_STATSILINE 215 +#define RPL_STATSKLINE 216 +#define RPL_STATSQLINE 217 +#define RPL_STATSYLINE 218 +#define RPL_ENDOFSTATS 219 + +#define RPL_UMODEIS 221 + +#define RPL_SERVICEINFO 231 +#define RPL_ENDOFSERVICES 232 +#define RPL_SERVICE 233 +#define RPL_SERVLIST 234 +#define RPL_SERVLISTEND 235 + +#define RPL_STATSIAUTH 239 +#define RPL_STATSVLINE 240 +#define RPL_STATSLLINE 241 +#define RPL_STATSUPTIME 242 +#define RPL_STATSOLINE 243 +#define RPL_STATSHLINE 244 +#define RPL_STATSSLINE 245 +#define RPL_STATSPING 246 +#define RPL_STATSBLINE 247 +#define RPL_STATSDEFINE 248 +#define RPL_STATSDEBUG 249 +#define RPL_STATSDLINE 250 + +#define RPL_LUSERCLIENT 251 +#define RPL_LUSEROP 252 +#define RPL_LUSERUNKNOWN 253 +#define RPL_LUSERCHANNELS 254 +#define RPL_LUSERME 255 +#define RPL_ADMINME 256 +#define RPL_ADMINLOC1 257 +#define RPL_ADMINLOC2 258 +#define RPL_ADMINEMAIL 259 + +#define RPL_TRACELOG 261 +#define RPL_TRACEEND 262 +#define RPL_TRYAGAIN 263 + diff --git a/common/os.h b/common/os.h new file mode 100644 index 0000000..a556764 --- /dev/null +++ b/common/os.h @@ -0,0 +1,765 @@ +/************************************************************************ + * IRC - Internet Relay Chat, include/os.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains the various system-relative "#include" lines needed for + getting all system types, macros, external variables and functions defined. + + This file also contains definitions of types, constants, macros, external + variables and functions that are missing in the include files of some OS, + or need to be redefined for various reasons. + */ + +#include "setup.h" + +#if HAVE_STDIO_H +# include <stdio.h> +#endif + +#if HAVE_STDLIB_H +# include <stdlib.h> +#endif + +#if HAVE_SYS_TYPES_H +# include <sys/types.h> +#endif + +#if HAVE_SYS_BITYPES_H +# include <sys/bitypes.h> +#endif + +#if HAVE_STDDEF_H +# include <stddef.h> +#endif + +#if USE_STDARG +# include <stdarg.h> +#endif + +#if HAVE_UNISTD_H +# include <unistd.h> +#endif + +#if HAVE_CTYPE_H +# include <ctype.h> +#endif + +#if HAVE_MEMORY_H +# include <memory.h> +#endif + +#if HAVE_VFORK_H +# include <vfork.h> +#endif + +#if HAVE_ERRNO_H +# include <errno.h> +#endif + +#if HAVE_SYS_ERRNO_H +# include <sys/errno.h> +#endif + +#if HAVE_SYS_SYSCALL_H +# include <sys/syscall.h> +#endif + +#if HAVE_PWD_H +# include <pwd.h> +#endif + +#if HAVE_MATH_H +# include <math.h> +#endif + +#if HAVE_UTMP_H +# include <utmp.h> +#endif + +#if HAVE_FCNTL_H +# include <fcntl.h> +#endif + +#if HAVE_SIGNAL_H +# include <signal.h> +#endif + +#if HAVE_SYS_WAIT_H +# include <sys/wait.h> +#endif + +#if HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif + +#if HAVE_SYS_FILE_H +# include <sys/file.h> +#endif + +#if HAVE_SYS_FILIO_H +# include <sys/filio.h> +#endif + +#if HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif + +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif + +#if HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif + +#if HAVE_SYS_POLL_H +# if linux +/* Linux is just soooo broken */ +# define _GNU_SOURCE 1 +# endif +# include <sys/poll.h> +# if linux && !defined(POLLRDNORM) +/* Linux 2.1.xx supports poll(), header files are not upto date yet */ +# define POLLRDNORM 0x0040 +# endif +#endif + +#if HAVE_STROPTS_H +# include <stropts.h> +#endif + +#if HAVE_NETDB_H +# if BAD___CONST_NETDB_H +# ifndef __const +# define __const +# include <netdb.h> +# undef __const +# else +# include <netdb.h> +# endif +# else +# include <netdb.h> +# endif +#endif + +#if HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#if HAVE_SYS_UN_H +# include <sys/un.h> +#endif + +#if HAVE_ARPA_INET_H +# include <arpa/inet.h> +#endif + +#if HAVE_SYS_PARAM_H +# include <sys/param.h> +#endif + +#if HAVE_SYS_SYSLOG_H +# include <sys/syslog.h> +#else +# if HAVE_SYSLOG_H +# include <syslog.h> +# endif +#endif + +#if HAVE_STRING_H +# include <string.h> +#else +# if HAVE_STRINGS_H +# include <strings.h> +# endif +#endif + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#if HAVE_SYS_RESOURCE_H +# include <sys/resource.h> +#endif + +#if HAVE_SYS_TIMES_H +# include <sys/times.h> +#endif + +#if HAVE_NETINET_IN_SYSTM_H +# include <netinet/in_systm.h> +#endif + +#if HAVE_NETINFO_NI_H +# include <netinfo/ni.h> +#endif + +#if USE_ZLIB && !defined(CLIENT_COMPILE) && !defined(CHKCONF_COMPILE) && \ + !defined(CONTRIB_COMPILE) +# include <zlib.h> +#endif + +#if defined(INET6) && defined(CLIENT_COMPILE) +# if (defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(__osf__)) && \ + HAVE_RESOLV_H +# include <resolv.h> +# endif +# if HAVE_ARPA_NAMESER_H +# include <arpa/nameser.h> +# endif +#endif + +#if defined(HAVE_DLFCN_H) +# include <dlfcn.h> +#endif + +#if (defined(__FreeBSD__) ||\ + defined(__OpenBSD__) ||\ + defined(__NetBSD__) ) && !defined(__ELF__) +# define DLSYM_NEEDS_UNDERSCORE +#endif + +/* Some special include files for a special OS. :) + */ + +#ifdef ISC +# include <sys/bsdtypes.h> +# include <sys/sioctl.h> +# include <sys/stream.h> +# include <net/errno.h> +#endif + +/* Definition of __P for handling possible prototype-syntax problems. + */ + +#ifdef __P +# undef __P +#endif +#if __STDC__ +# define __P(x) x +#else +# define __P(x) () +#endif + +/* Some additional system-relative defines that make the code easier. + * + * Note. In fact, the C code should never use system-specific tests; as you + * know, numerous people worked on it in the past, so now it is + * difficult for me to know why such tests are used in the code. But I + * still hope this part of the include file will be cleaned up in + * further releases. -- Alain.Nissen@ulg.ac.be + */ + +#if defined(ultrix) || defined(__ultrix) || defined(__ultrix__) +# ifdef ULTRIX +# undef ULTRIX +# endif +# define ULTRIX +#endif + +#if defined(aix) || defined(_AIX) +# ifdef AIX +# undef AIX +# endif +# define AIX +#endif + +#if defined(sgi) || defined(__sgi) || defined(__sgi__) +# ifdef SGI +# undef SGI +# endif +# define SGI +#endif + +#ifdef NeXT +# ifdef NEXT +# undef NEXT +# endif +# define NEXT +#endif + +#if defined(hpux) || defined(__hpux) +# ifdef HPUX +# undef HPUX +# endif +# define HPUX +#endif + +#if defined(_SVR4) || defined(__SVR4) || defined(__SVR4__) || defined(__svr4__) +# ifdef SVR4 +# undef SVR4 +# endif +# define SVR4 +#endif + +#ifdef __osf__ +# ifdef OSF +# undef OSF +# endif +# define OSF +# ifndef BSD +# define BSD 1 +# endif +#endif + +#if defined(sequent) || defined(__sequent) || defined(__sequent) +# ifdef _SEQUENT_ +# undef _SEQUENT_ +# endif +# define _SEQUENT_ +# undef BSD +# define SYSV +# define DYNIXPTX +#endif + +#if defined(mips) || defined(PCS) +#undef SYSV +#endif + +#ifdef MIPS +#undef BSD +#define BSD 1 /* mips only works in bsd43 environment */ +#endif + +#define Reg register + +/* Strings and memory functions portability problems. + */ + +#if HAVE_MEMCMP && MEMCMP_BROKEN +# define memcmp irc_memcmp +#endif + +#if HAVE_STRCHR +# ifdef index +# undef index +# endif +# define index strchr +#endif + +#if HAVE_STRRCHR +# ifdef rindex +# undef rindex +# endif +# define rindex strrchr +#endif + +#if ! HAVE_STRCHR && HAVE_INDEX +# ifdef strchr +# undef strchr +# endif +# define strchr index +#endif + +#if ! HAVE_STRRCHR && HAVE_RINDEX +# ifdef strrchr +# undef strrchr +# endif +# define strrchr rindex +#endif + +#if HAVE_MEMCMP +# ifdef bcmp +# undef bcmp +# endif +# define bcmp memcmp +#endif + +#if HAVE_MEMSET +# ifdef bzero +# undef bzero +# endif +# define bzero(a,b) memset((a),0,(b)) +#endif + +#if HAVE_MEMMOVE +# ifdef bcopy +# undef bcopy +# endif +# define bcopy(a,b,c) memmove((b),(a),(c)) +#endif + +#if ! HAVE_MEMCMP && HAVE_BCMP +# ifdef memcmp +# undef memcmp +# endif +# define memcmp bcmp +#endif + +#if ! HAVE_MEMCPY && HAVE_BCOPY +# ifdef memcpy +# undef memcpy +# endif +# define memcpy(d,s,n) bcopy((s),(d),(n)) +#endif + +#define strcasecmp mycmp +#define strncasecmp myncmp + +/* inet_ntoa(), inet_aton(), inet_addr() and inet_netof() portability + * problems. + * + * The undefs and prototypes are "needed" because of the way Paul Vixie + * majorly screws up system's include files with Bind. In this case, it's + * Bind 8.x installing /usr[/local]/include/arpa/inet.h -krys + */ + +#if HAVE_INET_NTOA +# ifdef inet_ntoa +# undef inet_ntoa +extern char *inet_ntoa __P((struct in_addr in)); +# endif +# define inetntoa(x) inet_ntoa(*(struct in_addr *)(x)) +#endif +#if HAVE_INET_ATON +# ifdef inet_aton +# undef inet_aton +extern int inet_aton __P((const char *cp, struct in_addr *addr)); +# endif +# define inetaton inet_aton +#endif +#if HAVE_INET_ADDR +# ifdef inet_addr +# undef inet_addr +extern unsigned long int inet_addr __P((const char *cp)); +# endif +# define inetaddr inet_addr +#endif +#if HAVE_INET_NETOF +# ifdef inet_netof +# undef inet_netof +extern int inet_netof __P((struct in_addr in)); +# endif +# define inetnetof inet_netof +#endif +#if ! HAVE_ARPA_INET_H +extern unsigned long int inet_addr __P((const char *cp)); +extern int inet_aton __P((const char *cp, struct in_addr *addr)); +extern int inet_netof __P((struct in_addr in)); +extern char *inet_ntoa __P((struct in_addr in)); +#endif + +/* Signals portability problems. + */ + +#ifdef HPUX +# ifndef SIGWINCH /*pre 9.0*/ +# define SIGWINCH SIGWINDOW +# endif +#endif + +#if BSD_RELIABLE_SIGNALS || POSIX_SIGNALS +#define HAVE_RELIABLE_SIGNALS +#endif + +/* Curses/Termcap portability problems (client only). + */ + +#ifdef CLIENT_COMPILE +#if USE_NCURSES || USE_CURSESX || USE_CURSES +# define DOCURSES +# if USE_CURSESX && HAVE_CURSESX_H +# include <cursesX.h> +# endif +# if (USE_NCURSES || USE_CURSES) && HAVE_CURSES_H +# if HAVE_NCURSES_H +# include <ncurses.h> +# else +# include <curses.h> +# endif +# endif +#else +# undef DOCURSES +#endif /* USE_NCURSES || ... */ + +#if USE_TERMCAP +# define DOTERMCAP +# if HAVE_SGTTY_H +# include <sgtty.h> +# endif +#else +# undef DOTERMCAP +#endif /* USE_TERMCAP */ +#endif /* CLIENT_COMPILE */ + +/* ctime portability problems. + */ + +#if defined(HPUX) && __STDC__ +# define ctime(x) (ctime((const time_t *)(x))) +#endif + +/* getsockopt portability problems. + */ + +#ifdef apollo +# undef IP_OPTIONS /* Defined in /usr/include/netinet/in.h but doesn't work */ +#endif + +/* setlinebuf portability problems. + */ + +#if defined(HPUX) && !defined(SYSV) && !defined(SVR4) || defined(__CYGWIN32__) +# define setlinebuf(x) (setvbuf((x), NULL, _IOLBF, BUFSIZ)) +#endif + + +/* gethostbyname portability problems. + */ + +#if SOLARIS_2_0_2_1_2_2 +/* + * On Solaris 2.0, 2.1 and 2.2 (SunOS 5.0, 5.1 and 5.2) systems, + * gethostbyname() has a bug, it always returns null in h->aliases. + * Workaround: use the undocumented __switch_gethostbyname(...). + */ +extern struct hostent *__switch_gethostbyname __P((const char *name)); +#define gethostbyname __switch_gethostbyname +#endif + +#if SOLARIS_2_3 +/* + * On Solaris 2.3 (SunOS 5.3) systems, gethostbyname() has a bug, it always + * returns null in h->aliases. Workaround: use the undocumented + * _switch_gethostbyname_r(...). + */ +extern struct hostent *_switch_gethostbyname_r __P((const char *name, + struct hostent *hp, + char *buf, int size, + int *h_errno)); +#define gethostbyname solaris_gethostbyname +#endif + +/* Resolver portability problems. + */ + +#ifdef __m88k__ +# define __BIND_RES_TEXT +#endif + +#ifndef NETDB_INTERNAL /* defined in latest BIND's <netdb.h> */ +# define NETDB_INTERNAL -1 /* but not in every vendors' <netdb.h> */ +#endif + +/* getrusage portability problems. + */ + +#if defined(HPUX) && ! HAVE_GETRUSAGE +# define getrusage(a,b) (syscall(SYS_GETRUSAGE, (a), (b))) +# define HAVE_GETRUSAGE 1 +#endif + +/* select portability problems - some systems do not define FD_... macros; on + * some systems (for example HPUX), select uses an int * instead of an + * fd_set * for its 2nd, 3rd and 4th arguments. + * + * Note. This test should be more portable and put in configure ... but I've + * no idea on how to build a test for configure that will guess if the + * system uses int * or fd_set * inside select(). If you've some idea, + * please tell it to me. :) -- Alain.Nissen@ulg.ac.be + */ + +#if ! USE_POLL +# ifndef FD_ZERO +# define FD_ZERO(set) (((set)->fds_bits[0]) = 0) +# define FD_SET(s1, set) (((set)->fds_bits[0]) |= 1 << (s1)) +# define FD_ISSET(s1, set) (((set)->fds_bits[0]) & (1 << (s1))) +# define FD_SETSIZE 30 +# endif /* FD_ZERO */ +# if defined(HPUX) && (! defined(_XPG4_EXTENDED) || (defined(_XPG4_EXTENDED) && defined(__INCLUDE_FROM_TIME_H) && !defined(_XOPEN_SOURCE_EXTENDED))) +# define SELECT_FDSET_TYPE int +# else +# define SELECT_FDSET_TYPE fd_set +# endif +#else /* should not be here - due to irc/c_bsd.c that does not support poll */ +# define SELECT_FDSET_TYPE fd_set +#endif /* USE_POLL */ + +/* <sys/wait.h> POSIX.1 portability problems - HAVE_SYS_WAIT_H is defined + * only if <sys/wait.h> is compatible with POSIX.1 - if not included, a + * prototype must be supplied for wait (wait3 and waitpid are unused here). + */ + +#if ! HAVE_SYS_WAIT_H +# if USE_UNION_WAIT +extern pid_t wait __P((union wait *)); +# else +extern pid_t wait __P((int *)); +# endif +#endif + +/* <sys/socket.h> portability problems - X/Open SPEC 1170 specifies that + * the length parameter of socket operations must be a size_t + * (resp. size_t *), instead of an int (resp. int *); the problem is that + * only a few systems (for example AIX 4.2) follow this specification; others + * systems still use int (resp. int *), which is not always equal to size_t + * (resp. size_t *). + * + * Note. This test should be more portable and put in configure ... but I've + * no idea on how to build a test for configure that will guess if the + * system uses size_t or int for their socket operations. If you've some + * idea, please tell it to me. :) -- Alain.Nissen@ulg.ac.be + */ + +#if defined(AIX) && defined(_XOPEN_SOURCE_EXTENDED) && _XOPEN_SOURCE_EXTENDED +# define SOCK_LEN_TYPE size_t +#else +# define SOCK_LEN_TYPE int +#endif + +/* Stupid typo in AIX 3.2's <sys/stropts.h>. + */ + +#if AIX_3_2 +# ifdef _IO +# undef _IO +# endif +# define _IO(x,y) (IOC_VOID|((x)<<8)|(y)) +#endif + +/* These macros may be broken. + */ + +#if STAT_MACROS_BROKEN +# ifdef S_ISFIFO +# undef S_ISFIFO +# endif +# define S_ISFIFO(m) (((m)&(_S_IFMT)) == (_S_IFIFO)) +# ifdef S_ISDIR +# undef S_ISDIR +# endif +# define S_ISDIR(m) (((m)&(_S_IFMT)) == (_S_IFDIR)) +# ifdef S_ISCHR +# undef S_ISCHR +# endif +# define S_ISCHR(m) (((m)&(_S_IFMT)) == (_S_IFCHR)) +# ifdef S_ISBLK +# undef S_ISBLK +# endif +# define S_ISBLK(m) (((m)&(_S_IFMT)) == (_S_IFBLK)) +# ifdef S_ISREG +# undef S_ISREG +# endif +# define S_ISREG(m) (((m)&(_S_IFMT)) == (_S_IFREG)) +#endif + +/* These constants may be missing. + */ + +#ifndef NULL +#define NULL 0 +#endif +#ifdef FALSE +#undef FALSE +#endif +#define FALSE (0) +#ifdef TRUE +#undef TRUE +#endif +#define TRUE (!FALSE) + +/* These macros may be missing. + */ + +#ifndef MAX +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* These external may be missing. + */ + +#if ! SYS_ERRLIST_DECLARED +extern char *sys_errlist[]; +#endif + +#if ! SYS_NERR_DECLARED +extern int sys_nerr; +#endif + +#if ! ERRNO_DECLARED +extern int errno; +#endif + +#if ! H_ERRNO_DECLARED +extern int h_errno; +#endif + +/* + * IPv4 or IPv6 structures? + */ + +#ifdef INET6 + +# define AND16(x) ((x)[0]&(x)[1]&(x)[2]&(x)[3]&(x)[4]&(x)[5]&(x)[6]&(x)[7]&(x)[8]&(x)[9]&(x)[10]&(x)[11]&(x)[12]&(x)[13]&(x)[14]&(x)[15]) +static unsigned char minus_one[]={ 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 0}; +# define WHOSTENTP(x) ((x)[0]|(x)[1]|(x)[2]|(x)[3]|(x)[4]|(x)[5]|(x)[6]|(x)[7]|(x)[8]|(x)[9]|(x)[10]|(x)[11]|(x)[12]|(x)[13]|(x)[14]|(x)[15]) + +# define AFINET AF_INET6 +# define SOCKADDR_IN sockaddr_in6 +# define SOCKADDR sockaddr +# define SIN_FAMILY sin6_family +# define SIN_PORT sin6_port +# define SIN_ADDR sin6_addr +# define S_ADDR s6_addr +# define IN_ADDR in6_addr + +# ifndef uint32_t +# define uint32_t __u32 +# endif + +# define MYDUMMY_SIZE 128 +char mydummy[MYDUMMY_SIZE]; +char mydummy2[MYDUMMY_SIZE]; + +# if defined(linux) || defined(__NetBSD__) || defined(__FreeBSD__) || defined(bsdi) +# ifndef s6_laddr +# define s6_laddr s6_addr32 +# endif +# endif + +# if defined(linux) +static const struct in6_addr in6addr_any={ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0}; +# endif + +# define IRCDCONF_DELIMITER '%' + +#else +# define AFINET AF_INET +# define SOCKADDR_IN sockaddr_in +# define SOCKADDR sockaddr +# define SIN_FAMILY sin_family +# define SIN_PORT sin_port +# define SIN_ADDR sin_addr +# define S_ADDR s_addr +# define IN_ADDR in_addr + +# define WHOSTENTP(x) (x) +# define IRCDCONF_DELIMITER ':' +#endif diff --git a/common/packet.c b/common/packet.c new file mode 100644 index 0000000..75bc2e6 --- /dev/null +++ b/common/packet.c @@ -0,0 +1,197 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/packet.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 rcsid[] = "@(#)$Id: packet.c,v 1.8 1999/04/19 22:26:22 kalt Exp $"; +#endif + +#include "os.h" +#ifndef CLIENT_COMPILE +# include "s_defines.h" +#else +# include "c_defines.h" +#endif +#define PACKET_C +#ifndef CLIENT_COMPILE +# include "s_externs.h" +#else +# include "c_externs.h" +#endif +#undef PACKET_C + +/* +** dopacket +** cptr - pointer to client structure for which the buffer data +** applies. +** buffer - pointr to the buffer containing the newly read data +** length - number of valid bytes of data in the buffer +** +** The buffer might be partially or totally zipped. +** At the beginning of the compressed flow, it is possible that +** an uncompressed ERROR message will be found. This occurs when +** the connection fails on the other server before switching +** to compressed mode. +** +** Note: +** It is implicitly assumed that dopacket is called only +** with cptr of "local" variation, which contains all the +** necessary fields (buffer etc..) +*/ +int dopacket(cptr, buffer, length) +Reg aClient *cptr; +char *buffer; +Reg int length; +{ + Reg char *ch1; + Reg char *ch2, *bufptr; + aClient *acpt = cptr->acpt; + int r = 1; +#ifdef ZIP_LINKS + int unzipped = 0; +#endif + + me.receiveB += length; /* Update bytes received */ + cptr->receiveB += length; + if (cptr->receiveB > 1023) + { + cptr->receiveK += (cptr->receiveB >> 10); + cptr->receiveB &= 0x03ff; /* 2^10 = 1024, 3ff = 1023 */ + } + if (acpt != &me) + { + acpt->receiveB += length; + if (acpt->receiveB > 1023) + { + acpt->receiveK += (acpt->receiveB >> 10); + acpt->receiveB &= 0x03ff; + } + } + else if (me.receiveB > 1023) + { + me.receiveK += (me.receiveB >> 10); + me.receiveB &= 0x03ff; + } + + bufptr = cptr->buffer; + ch1 = bufptr + cptr->count; + ch2 = buffer; + +#ifdef ZIP_LINKS + while ((length > 0 && ch2) || ((cptr->flags & FLAGS_ZIP) && + (cptr->zip->in->avail_in || + !unzipped))) +#else + while (length > 0 && ch2) +#endif + { + Reg char c; + +#ifdef ZIP_LINKS + if (cptr->flags & FLAGS_ZIPSTART) + { + /* + ** beginning of server connection, the buffer + ** contained PASS/SERVER and is now zipped! + ** Ignore the '\n' that should be here. + */ + if (*ch2 == '\n') /* also check \r ? */ + { + ch2++; + length--; + cptr->flags &= ~FLAGS_ZIPSTART; + } + if (length == 0) + return 1; + } + + if ((cptr->flags & FLAGS_ZIP) && !(unzipped && length)) + { + /* uncompressed buffer first */ + unzipped = length; /* length is register, store + temp in unzipped */ + ch2 = unzip_packet(cptr, ch2, &unzipped); + length = unzipped; + unzipped = 1; + if (length == -1) + return exit_client(cptr, cptr, &me, + "fatal error in unzip_packet()"); + if (length == 0 || *ch2 == '\0') + break; + } +#endif + length--; + c = (*ch1 = *ch2++); + /* + * Yuck. Stuck. To make sure we stay backward compatible, + * we must assume that either CR or LF terminates the message + * and not CR-LF. By allowing CR or LF (alone) into the body + * of messages, backward compatibility is lost and major + * problems will arise. - Avalon + */ + if ((c <= '\r') && (c == '\n' || c == '\r')) + { + if (ch1 == bufptr) + continue; /* Skip extra LF/CR's */ + *ch1 = '\0'; + me.receiveM += 1; /* Update messages received */ + cptr->receiveM += 1; + if (cptr->acpt != &me) + cptr->acpt->receiveM += 1; + cptr->count = 0; /* ...just in case parse returns with + ** FLUSH_BUFFER without removing the + ** structure pointed by cptr... --msa + */ + if ((r = parse(cptr, bufptr, ch1)) == + FLUSH_BUFFER) + /* + ** FLUSH_BUFFER means actually that cptr + ** structure *does* not exist anymore!!! --msa + */ + return FLUSH_BUFFER; +#ifndef CLIENT_COMPILE + /* + ** Socket is dead so exit (which always returns with + ** FLUSH_BUFFER here). - avalon + */ + if (cptr->flags & FLAGS_DEADSOCKET) + { + if (cptr->exitc == EXITC_REG) + cptr->exitc = EXITC_DEAD; + return exit_client(cptr, cptr, &me, + "Dead Socket"); + } + /* + ** Something is wrong, really wrong, and nothing + ** else should be allowed to be parsed! + ** This covers a bug which is somewhere else, + ** since no decent server would send such thing + ** as an unknown command. -krys + */ + if (IsServer(cptr) && (cptr->flags & FLAGS_UNKCMD)) + break; +#endif + ch1 = bufptr; + } + else if (ch1 < bufptr + (sizeof(cptr->buffer)-1)) + ch1++; /* There is always room for the null */ + } + cptr->count = ch1 - bufptr; + return r; +} diff --git a/common/packet_ext.h b/common/packet_ext.h new file mode 100644 index 0000000..9493fc8 --- /dev/null +++ b/common/packet_ext.h @@ -0,0 +1,32 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/packet_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in common/packet.c. + */ + +/* External definitions for global functions. + */ +#ifndef PACKET_C +#define EXTERN extern +#else /* PACKET_C */ +#define EXTERN +#endif /* PACKET_C */ +EXTERN int dopacket __P((Reg aClient *cptr, char *buffer, Reg int length)); +#undef EXTERN diff --git a/common/parse.c b/common/parse.c new file mode 100644 index 0000000..9bb496c --- /dev/null +++ b/common/parse.c @@ -0,0 +1,786 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/parse.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 rcsid[] = "@(#)$Id: parse.c,v 1.25 1999/04/14 17:29:36 kalt Exp $"; +#endif + +#include "os.h" +#ifndef CLIENT_COMPILE +# include "s_defines.h" +#else +# include "c_defines.h" +#endif +#define PARSE_C +#ifndef CLIENT_COMPILE +# include "s_externs.h" +#else +# include "c_externs.h" +#endif +#undef PARSE_C + +struct Message msgtab[] = { + { MSG_PRIVATE, m_private, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, +#ifndef CLIENT_COMPILE + { MSG_NJOIN, m_njoin, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L}, +#endif + { MSG_JOIN, m_join, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_MODE, m_mode, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_NICK, m_nick, MAXPARA, MSG_LAG, 0, 0, 0L}, + { MSG_PART, m_part, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_QUIT, m_quit, MAXPARA, MSG_LAG, 0, 0, 0L}, + { MSG_NOTICE, m_notice, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_KICK, m_kick, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_SERVER, m_server, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L}, +#ifndef CLIENT_COMPILE + { MSG_TRACE, m_trace, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, +#endif + { MSG_TOPIC, m_topic, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_INVITE, m_invite, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_WALLOPS, m_wallops, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L}, + { MSG_PING, m_ping, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_PONG, m_pong, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_ERROR, m_error, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L}, +#ifdef OPER_KILL + { MSG_KILL, m_kill, MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L}, +#else + { MSG_KILL, m_kill, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L}, +#endif +#ifndef CLIENT_COMPILE + { MSG_USER, m_user, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L}, + { MSG_AWAY, m_away, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_UMODE, m_umode, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_ISON, m_ison, 1, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_SQUIT, m_squit, MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L}, + { MSG_WHOIS, m_whois, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_WHO, m_who, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_WHOWAS, m_whowas, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_LIST, m_list, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_NAMES, m_names, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_USERHOST,m_userhost, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_PASS, m_pass, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L}, + { MSG_LUSERS, m_lusers, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_TIME, m_time, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_OPER, m_oper, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_CONNECT, m_connect, MAXPARA, + MSG_LAG|MSG_REGU|MSG_OP|MSG_LOP, 0, 0, 0L}, + { MSG_VERSION, m_version, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_STATS, m_stats, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_LINKS, m_links, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_ADMIN, m_admin, MAXPARA, MSG_LAG, 0, 0, 0L}, + { MSG_USERS, m_users, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_SUMMON, m_summon, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_HELP, m_help, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_INFO, m_info, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_MOTD, m_motd, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_CLOSE, m_close, MAXPARA, MSG_LAG|MSG_REGU|MSG_OP, 0, 0, 0L}, + { MSG_RECONECT,m_reconnect,MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L}, + { MSG_SERVICE, m_service, MAXPARA, MSG_LAG|MSG_NOU, 0, 0, 0L}, +#ifdef USE_SERVICES + { MSG_SERVSET, m_servset, MAXPARA, MSG_LAG|MSG_SVC, 0, 0, 0L}, +#endif + { MSG_SQUERY, m_squery, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_SERVLIST,m_servlist, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_HASH, m_hash, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, + { MSG_DNS, m_dns, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, +#ifdef OPER_REHASH + { MSG_REHASH, m_rehash, MAXPARA, MSG_REGU|MSG_OP +# ifdef LOCOP_REHASH + |MSG_LOP +# endif + , 0, 0, 0L}, +#endif +#ifdef OPER_RESTART + { MSG_RESTART, m_restart, MAXPARA, MSG_REGU|MSG_OP +# ifdef LOCOP_RESTART + |MSG_LOP +# endif + , 0, 0, 0L}, +#endif +#ifdef OPER_DIE + { MSG_DIE, m_die, MAXPARA, MSG_REGU|MSG_OP +# ifdef LOCOP_DIE + |MSG_LOP +# endif + , 0, 0, 0L}, +#endif +#endif /* !CLIENT_COMPILE */ + { (char *) 0, (int (*)()) 0, 0, 0, 0, 0, 0L} +}; + +/* + * NOTE: parse() should not be called recursively by other functions! + */ +static char *para[MAXPARA+1]; + +#ifdef CLIENT_COMPILE +static char sender[NICKLEN+USERLEN+HOSTLEN+3]; +char userhost[USERLEN+HOSTLEN+2]; +#define timeofday time(NULL) +#else +static char sender[HOSTLEN+1]; +static int cancel_clients __P((aClient *, aClient *, char *)); +static void remove_unknown __P((aClient *, char *)); +#endif + +/* +** Find a client (server or user) by name. +** +** *Note* +** Semantics of this function has been changed from +** the old. 'name' is now assumed to be a null terminated +** string and the search is the for server and user. +*/ +#ifndef CLIENT_COMPILE +aClient *find_client(name, cptr) +char *name; +Reg aClient *cptr; + { + aClient *acptr = cptr; + + if (name && *name) + acptr = hash_find_client(name, cptr); + + return acptr; + } + +aClient *find_service(name, cptr) +char *name; +Reg aClient *cptr; + { + aClient *acptr = cptr; + + if (index(name, '@')) + acptr = hash_find_client(name, cptr); + return acptr; + } + +#else /* CLIENT_COMPILE */ + +aClient *find_client(name, cptr) +char *name; +aClient *cptr; + { + Reg aClient *c2ptr = cptr; + + if (!name || !*name) + return c2ptr; + + for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) + if (mycmp(name, c2ptr->name) == 0) + return c2ptr; + return cptr; + } +#endif /* CLIENT_COMPILE */ + +/* +** Find a user@host (server or user). +** +** *Note* +** Semantics of this function has been changed from +** the old. 'name' is now assumed to be a null terminated +** string and the search is the for server and user. +*/ +aClient *find_userhost(user, host, cptr, count) +char *user, *host; +aClient *cptr; +int *count; + { + Reg aClient *c2ptr; + Reg aClient *res = cptr; + + *count = 0; + if (user) + for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) + { + if (!MyClient(c2ptr)) /* implies mine and a user */ + continue; + if ((!host || !match(host, c2ptr->user->host)) && + mycmp(user, c2ptr->user->username) == 0) + { + (*count)++; + res = c2ptr; + } + } + return res; + } + +/* +** Find server by name. +** +** This implementation assumes that server and user names +** are unique, no user can have a server name and vice versa. +** One should maintain separate lists for users and servers, +** if this restriction is removed. +** +** *Note* +** Semantics of this function has been changed from +** the old. 'name' is now assumed to be a null terminated +** string. +*/ +#ifndef CLIENT_COMPILE +/* +** Find a server from hash table, given its name +*/ +aClient *find_server(name, cptr) +char *name; +Reg aClient *cptr; +{ + aClient *acptr = cptr; + + if (name && *name) + acptr = hash_find_server(name, cptr); + return acptr; +} + +/* +** Given a server name, find the server mask behind which the server +** is hidden. +*/ +aClient *find_mask(name, cptr) +char *name; +aClient *cptr; +{ + static char servermask[HOSTLEN+1]; + Reg aClient *c2ptr = cptr; + Reg char *mask = servermask; + + if (!name || !*name) + return c2ptr; + if ((c2ptr = hash_find_server(name, cptr))) + return (c2ptr); + if (index(name, '*')) + return c2ptr; + strcpy (servermask, name); + while (*mask) + { + if (*(mask+1) == '.') + { + *mask = '*'; + if ((c2ptr = hash_find_server(mask, cptr))) + return (c2ptr); + } + mask++; + } + return (c2ptr ? c2ptr : cptr); +} + +/* +** Find a server from hash table, given its token +*/ +aServer *find_tokserver(token, cptr, c2ptr) +int token; +aClient *cptr, *c2ptr; +{ + return hash_find_stoken(token, cptr, c2ptr); +} + +/* +** Find a server, given its name (which might contain *'s, in which case +** the first match will be return [not the best one]) +*/ +aClient *find_name(name, cptr) +char *name; +aClient *cptr; +{ + Reg aClient *c2ptr = cptr; + Reg aServer *sp = NULL; + + if (!name || !*name) + return c2ptr; + + if ((c2ptr = hash_find_server(name, cptr))) + return (c2ptr); + if (!index(name, '*')) + return c2ptr; + for (sp = svrtop; sp; sp = sp->nexts) + { + /* + ** A server present in the list necessarily has a non NULL + ** bcptr pointer. + */ + if (match(name, sp->bcptr->name) == 0) + break; + if (index(sp->bcptr->name, '*')) + if (match(sp->bcptr->name, name) == 0) + break; + } + return (sp ? sp->bcptr : cptr); +} +#else +aClient *find_server(name, cptr) +char *name; +aClient *cptr; +{ + Reg aClient *c2ptr = cptr; + + if (!name || !*name) + return c2ptr; + + for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) + { + if (!IsServer(c2ptr) && !IsMe(c2ptr)) + continue; + if (match(c2ptr->name, name) == 0 || + match(name, c2ptr->name) == 0) + break; + } + return (c2ptr ? c2ptr : cptr); +} +#endif /* CLIENT_COMPILE */ + +/* +** Find person by (nick)name. +*/ +aClient *find_person(name, cptr) +char *name; +aClient *cptr; + { + Reg aClient *c2ptr = cptr; + + c2ptr = find_client(name, c2ptr); + + if (c2ptr && IsClient(c2ptr) && c2ptr->user) + return c2ptr; + else + return cptr; + } + +/* + * parse a buffer. + * Return values: + * errors: -3 for unknown origin/sender, -2 for FLUSH_BUFFER, -1 for bad cptr + * + * NOTE: parse() should not be called recusively by any other fucntions! + */ +int parse(cptr, buffer, bufend) +aClient *cptr; +char *buffer, *bufend; + { + Reg aClient *from = cptr; + Reg char *ch, *s; + Reg int len, i, numeric = 0, paramcount; + Reg struct Message *mptr = NULL; + int ret; + +#ifndef CLIENT_COMPILE + Debug((DEBUG_DEBUG, "Parsing %s: %s", + get_client_name(cptr, FALSE), buffer)); + if (IsDead(cptr)) + return -1; +#endif + + s = sender; + *s = '\0'; + for (ch = buffer; *ch == ' '; ch++) + ; + para[0] = from->name; + if (*ch == ':') + { + /* + ** Copy the prefix to 'sender' assuming it terminates + ** with SPACE (or NULL, which is an error, though). + */ + for (++ch, i = 0; *ch && *ch != ' '; ++ch ) + if (s < (sender + sizeof(sender)-1)) + *s++ = *ch; /* leave room for NULL */ + *s = '\0'; +#ifdef CLIENT_COMPILE + if ((s = index(sender, '!'))) + { + *s++ = '\0'; + strncpyzt(userhost, s, sizeof(userhost)); + } + else if ((s = index(sender, '@'))) + { + *s++ = '\0'; + strncpyzt(userhost, s, sizeof(userhost)); + } +#endif + /* + ** Actually, only messages coming from servers can have + ** the prefix--prefix silently ignored, if coming from + ** a user client... + ** + ** ...sigh, the current release "v2.2PL1" generates also + ** null prefixes, at least to NOTIFY messages (e.g. it + ** puts "sptr->nickname" as prefix from server structures + ** where it's null--the following will handle this case + ** as "no prefix" at all --msa (": NOTICE nick ...") + */ + if (*sender && IsServer(cptr)) + { + from = find_client(sender, (aClient *) NULL); + if (!from || + /* + ** I really believe that the followin line is + ** useless. What a waste, especially with 2.9 + ** hostmasks.. at least the test on from->name + ** will make it a bit better. -krys + */ + (*from->name == '*' && match(from->name, sender))) + from = find_server(sender, (aClient *)NULL); +#ifndef CLIENT_COMPILE + /* Is there svc@server prefix ever? -Vesa */ + /* every time a service talks -krys */ + if (!from && index(sender, '@')) + from = find_service(sender, (aClient *)NULL); + if (!from) + from = find_mask(sender, (aClient *) NULL); +#endif + + para[0] = sender; + + /* Hmm! If the client corresponding to the + * prefix is not found--what is the correct + * action??? Now, I will ignore the message + * (old IRC just let it through as if the + * prefix just wasn't there...) --msa + * Since 2.9 we pick them up and .. --Vesa + */ + if (!from) + { + Debug((DEBUG_ERROR, + "Unknown prefix (%s)(%s) from (%s)", + sender, buffer, cptr->name)); + ircstp->is_unpf++; +#ifndef CLIENT_COMPILE + remove_unknown(cptr, sender); +#endif + return -3; /* Grab it in read_message() */ + } + if (from->from != cptr) + { + ircstp->is_wrdi++; + Debug((DEBUG_ERROR, + "Message (%s) coming from (%s)", + buffer, cptr->name)); +#ifndef CLIENT_COMPILE + return cancel_clients(cptr, from, buffer); +#else + return -1; +#endif + } + } + while (*ch == ' ') + ch++; + } + if (*ch == '\0') + { + ircstp->is_empt++; + Debug((DEBUG_NOTICE, "Empty message from host %s:%s", + cptr->name, from->name)); + return -1; + } + /* + ** Extract the command code from the packet. Point s to the end + ** of the command code and calculate the length using pointer + ** arithmetic. Note: only need length for numerics and *all* + ** numerics must have paramters and thus a space after the command + ** code. -avalon + */ + s = (char *)index(ch, ' '); /* s -> End of the command code */ + len = (s) ? (s - ch) : 0; + if (len == 3 && + isdigit(*ch) && isdigit(*(ch + 1)) && isdigit(*(ch + 2))) + { + numeric = (*ch - '0') * 100 + (*(ch + 1) - '0') * 10 + + (*(ch + 2) - '0'); + paramcount = MAXPARA; + ircstp->is_num++; + } + else + { + if (s) + *s++ = '\0'; + for (mptr = msgtab; mptr->cmd; mptr++) + if (mycmp(mptr->cmd, ch) == 0) + break; + + if (!mptr->cmd) + { + /* + ** Note: Give error message *only* to recognized + ** persons. It's a nightmare situation to have + ** two programs sending "Unknown command"'s or + ** equivalent to each other at full blast.... + ** If it has got to person state, it at least + ** seems to be well behaving. Perhaps this message + ** should never be generated, though... --msa + ** Hm, when is the buffer empty -- if a command + ** code has been found ?? -Armin + */ + if (buffer[0] != '\0') + { + cptr->flags |= FLAGS_UNKCMD; + if (IsPerson(from)) + sendto_one(from, + ":%s %d %s %s :Unknown command", + me.name, ERR_UNKNOWNCOMMAND, + from->name, ch); +#ifdef CLIENT_COMPILE + Debug((DEBUG_ERROR,"Unknown (%s) from %s[%s]", + ch, cptr->name, cptr->sockhost)); +#else + else if (IsServer(cptr)) + sendto_flag(SCH_ERROR, + "Unknown command from %s:%s", + get_client_name(cptr, TRUE), ch); + Debug((DEBUG_ERROR,"Unknown (%s) from %s", + ch, get_client_name(cptr, TRUE))); +#endif + } + ircstp->is_unco++; + return -1; + } + paramcount = mptr->parameters; + i = bufend - ((s) ? s : ch); + mptr->bytes += i; +#ifndef CLIENT_COMPILE + if ((mptr->flags & MSG_LAG) && + !(IsServer(cptr) || IsService(cptr))) + { /* Flood control partly migrated into penalty */ + if (bootopt & BOOT_PROT) + cptr->since += (1 + i / 100); + else + cptr->since = timeofday; + /* Allow only 1 msg per 2 seconds + * (on average) to prevent dumping. + * to keep the response rate up, + * bursts of up to 5 msgs are allowed + * -SRB + */ + } +#endif + } + /* + ** Must the following loop really be so devious? On + ** surface it splits the message to parameters from + ** blank spaces. But, if paramcount has been reached, + ** the rest of the message goes into this last parameter + ** (about same effect as ":" has...) --msa + */ + + /* Note initially true: s==NULL || *(s-1) == '\0' !! */ + +#ifdef CLIENT_COMPILE + if (me.user) + para[0] = sender; +#endif + i = 0; + if (s) + { + if (paramcount > MAXPARA) + paramcount = MAXPARA; + for (;;) + { + /* + ** Never "FRANCE " again!! ;-) Clean + ** out *all* blanks.. --msa + */ + while (*s == ' ') + *s++ = '\0'; + + if (*s == '\0') + break; + if (*s == ':') + { + /* + ** The rest is single parameter--can + ** include blanks also. + */ + para[++i] = s + 1; + break; + } + para[++i] = s; + if (i >= paramcount-1) + break; + for (; *s != ' ' && *s; s++) + ; + } + } + para[++i] = NULL; /* at worst, ++i is paramcount (MAXPARA) */ + if (mptr == NULL) + return (do_numeric(numeric, cptr, from, i, para)); + mptr->count++; + if (!MyConnect(from)) + mptr->rcount++; + if (IsRegisteredUser(cptr) && +#ifdef IDLE_FROM_MSG + mptr->func == m_private) +#else + mptr->func != m_ping && mptr->func != m_pong) +#endif + from->user->last = timeofday; + Debug((DEBUG_DEBUG, "Function: %#x = %s parc %d parv %#x", + mptr->func, mptr->cmd, i, para)); +#ifndef CLIENT_COMPILE + if ((mptr->flags & MSG_REGU) && check_registered_user(from)) + return -1; + if ((mptr->flags & MSG_SVC) && check_registered_service(from)) + return -1; + if ((mptr->flags & MSG_REG) && check_registered(from)) + return -1; + if ((mptr->flags & MSG_NOU) && (MyPerson(from) || MyService(from))) + { + sendto_one(from, err_str(ERR_ALREADYREGISTRED, para[0])); + return-1; + } + if (MyConnect(from) && !IsServer(from) && + (mptr->flags & (MSG_LOP|MSG_OP)) && + !((mptr->flags & MSG_OP) && (IsOper(from))) && + !((mptr->flags & MSG_LOP) && (IsLocOp(from)))) + { + sendto_one(from, err_str(ERR_NOPRIVILEGES, para[0])); + return -1; + } +#endif + /* + ** ALL m_functions return now UNIFORMLY: + ** -2 old FLUSH_BUFFER return value (unchanged). + ** -1 if parsing of a protocol message leads in a syntactic/semantic + ** error and NO penalty scoring should be applied. + ** >=0 if protocol message processing was successful. The return + ** value indicates the penalty score. + */ + ret = (*mptr->func)(cptr, from, i, para); + +#ifndef CLIENT_COMPILE + /* + ** Add penalty score for sucessfully parsed command if issued by + ** a LOCAL user client. + */ + if ((ret > 0) && IsRegisteredUser(cptr) && (bootopt & BOOT_PROT)) + { + cptr->since += ret; +/* only to lurk + sendto_one(cptr, + ":%s NOTICE %s :*** Penalty INCR [%s] +%d", + me.name, cptr->name, ch, ret); +*/ + } +#endif + return (ret != FLUSH_BUFFER) ? 2 : FLUSH_BUFFER; +} + +/* + * field breakup for ircd.conf file. + */ +char *getfield(irc_newline) +char *irc_newline; +{ + static char *line = NULL; + char *end, *field; + + if (irc_newline) + line = irc_newline; + if (line == NULL) + return(NULL); + + field = line; + if ((end = (char *)index(line, IRCDCONF_DELIMITER)) == NULL) + { + line = NULL; + if ((end = (char *)index(field,'\n')) == NULL) + end = field + strlen(field); + } + else + line = end + 1; + *end = '\0'; + return(field); +} + +#ifndef CLIENT_COMPILE +static int cancel_clients(cptr, sptr, cmd) +aClient *cptr, *sptr; +char *cmd; +{ + /* + * kill all possible points that are causing confusion here, + * I'm not sure I've got this all right... + * - avalon + */ + sendto_flag(SCH_NOTICE, "Message (%s) for %s[%s!%s@%s] from %s", + cmd, sptr->name, sptr->from->name, sptr->from->username, + sptr->from->sockhost, get_client_name(cptr, TRUE)); + /* + * Incorrect prefix for a server from some connection. If it is a + * client trying to be annoying, just QUIT them, if it is a server + * then the same deal. + */ + if (IsServer(sptr) || IsMe(sptr)) + { + sendto_flag(SCH_NOTICE, "Dropping server %s",cptr->name); + return exit_client(cptr, cptr, &me, "Fake Direction"); + } + /* + * Ok, someone is trying to impose as a client and things are + * confused. If we got the wrong prefix from a server, send out a + * kill, else just exit the lame client. + */ + if (IsServer(cptr)) + { + sendto_serv_butone(NULL, ":%s KILL %s :%s (%s[%s] != %s)", + me.name, sptr->name, me.name, + sptr->name, sptr->from->name, + get_client_name(cptr, TRUE)); + sptr->flags |= FLAGS_KILLED; + return exit_client(cptr, sptr, &me, "Fake Prefix"); + } + return exit_client(cptr, cptr, &me, "Fake prefix"); +} + +static void remove_unknown(cptr, sender) +aClient *cptr; +char *sender; +{ + if (!IsRegistered(cptr) || IsClient(cptr)) + return; + /* + * Not from a server so don't need to worry about it. + */ + if (!IsServer(cptr)) + return; + /* + * squit if it is a server because it means something is really + * wrong. + */ + if (index(sender, '.') /* <- buggy, it could be a service! */ + && !index(sender, '@')) /* better.. */ + { + sendto_flag(SCH_LOCAL, "Squitting unknown %s brought by %s.", + sender, get_client_name(cptr, FALSE)); + sendto_one(cptr, ":%s SQUIT %s :(Unknown from %s)", + me.name, sender, get_client_name(cptr, FALSE)); + } + else + /* + * Do kill if it came from a server because it means there is a ghost + * user on the other server which needs to be removed. -avalon + * it can simply be caused by lag (among other things), so just + * drop it if it is not a server. -krys + * services aren't prone to collisions, so lag shouldn't be responsible + * if we get here and sender is a service, we should probably issue + * a kill in this case! -krys + */ + sendto_flag(SCH_LOCAL, "Dropping unknown %s brought by %s.", + sender, get_client_name(cptr, FALSE)); +} +#endif diff --git a/common/parse_ext.h b/common/parse_ext.h new file mode 100644 index 0000000..6fdd118 --- /dev/null +++ b/common/parse_ext.h @@ -0,0 +1,56 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/parse_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in common/parse.c. + */ + +/* External definitions for global variables. + */ +#ifndef PARSE_C +#ifdef CLIENT_COMPILE +extern char userhost[]; +#endif /* CLIENT_COMPILE */ +extern struct Message msgtab[]; +#endif /* PARSE_C */ + +/* External definitions for global functions. + */ +#ifndef PARSE_C +#define EXTERN extern +#else /* PARSE_C */ +#define EXTERN +#endif /* PARSE_C */ +#ifndef CLIENT_COMPILE +EXTERN aClient *find_client __P((char *name, Reg aClient *cptr)); +EXTERN aClient *find_service __P((char *name, Reg aClient *cptr)); +EXTERN aClient *find_server __P((char *name, Reg aClient *cptr)); +EXTERN aClient *find_mask __P((char *name, aClient *cptr)); +EXTERN aServer *find_tokserver __P((int token, aClient *cptr, aClient *c2ptr)); +EXTERN aClient *find_name __P((char *name, aClient *cptr)); +#else /* CLIENT_COMPILE */ +EXTERN aClient *find_client __P((char *name, aClient *cptr)); +EXTERN aClient *find_server __P((char *name, aClient *cptr)); +#endif /* CLIENT_COMPILE */ +EXTERN aClient *find_userhost __P((char *user, char *host, aClient *cptr, + int *count)); +EXTERN aClient *find_person __P((char *name, aClient *cptr)); +EXTERN int parse __P((aClient *cptr, char *buffer, char *bufend)); +EXTERN char *getfield __P((char *irc_newline)); +#undef EXTERN diff --git a/common/patchlevel.h b/common/patchlevel.h new file mode 100644 index 0000000..6b84548 --- /dev/null +++ b/common/patchlevel.h @@ -0,0 +1,22 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/patchlevel.h + * + * 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 PATCHLEVEL +#define PATCHLEVEL "0210030000" /* for server identification */ +#define DEVLEVEL 'b' +#endif diff --git a/common/send.c b/common/send.c new file mode 100644 index 0000000..c61e3e5 --- /dev/null +++ b/common/send.c @@ -0,0 +1,1555 @@ +/* + * IRC - Internet Relay Chat, common/send.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 rcsid[] = "@(#)$Id: send.c,v 1.39 1999/07/21 22:57:40 kalt Exp $"; +#endif + +#include "os.h" +#ifndef CLIENT_COMPILE +# include "s_defines.h" +#else +# include "c_defines.h" +#endif +#define SEND_C +#ifndef CLIENT_COMPILE +# include "s_externs.h" +#else +# include "c_externs.h" +#endif +#undef SEND_C + +static char sendbuf[2048]; +static int send_message __P((aClient *, char *, int)); + +#if USE_STDARG +static void vsendto_prefix_one(aClient *, aClient *, char *, va_list); +#endif + + +#ifndef CLIENT_COMPILE +static char psendbuf[2048]; +static int sentalong[MAXCONNECTIONS]; +#endif + +/* +** dead_link +** An error has been detected. The link *must* be closed, +** but *cannot* call ExitClient (m_bye) from here. +** Instead, mark it with FLAGS_DEADSOCKET. This should +** generate ExitClient from the main loop. +** +** If 'notice' is not NULL, it is assumed to be a format +** for a message to local opers. It can contain only one +** '%s', which will be replaced by the sockhost field of +** the failing link. +** +** Also, the notice is skipped for "uninteresting" cases, +** like Persons and yet unknown connections... +*/ +static int dead_link(to, notice) +aClient *to; +char *notice; +{ + if (IsHeld(to)) + return -1; + to->flags |= FLAGS_DEADSOCKET; + /* + * If because of BUFFERPOOL problem then clean dbufs now so that + * notices don't hurt operators below. + */ + DBufClear(&to->recvQ); + DBufClear(&to->sendQ); +#ifndef CLIENT_COMPILE + if (!IsPerson(to) && !IsUnknown(to) && !(to->flags & FLAGS_CLOSING)) + sendto_flag(SCH_ERROR, notice, get_client_name(to, FALSE)); + Debug((DEBUG_ERROR, notice, get_client_name(to, FALSE))); +#endif + return -1; +} + +#ifndef CLIENT_COMPILE +/* +** flush_fdary +** Used to empty all output buffers for connections in fdary. +*/ +void flush_fdary(fdp) +FdAry *fdp; +{ + int i; + aClient *cptr; + + for (i = 0; i <= fdp->highest; i++) + { + if (!(cptr = local[fdp->fd[i]])) + continue; + if (!IsRegistered(cptr)) /* is this needed?? -kalt */ + continue; + if (DBufLength(&cptr->sendQ) > 0) + (void)send_queued(cptr); + } +} + +/* +** flush_connections +** Used to empty all output buffers for all connections. Should only +** be called once per scan of connections. There should be a select in +** here perhaps but that means either forcing a timeout or doing a poll. +** When flushing, all we do is empty the obuffer array for each local +** client and try to send it. if we can't send it, it goes into the sendQ +** -avalon +*/ +void flush_connections(fd) +int fd; +{ + Reg int i; + Reg aClient *cptr; + + if (fd == me.fd) + { + for (i = highest_fd; i >= 0; i--) + if ((cptr = local[i]) && DBufLength(&cptr->sendQ) > 0) + (void)send_queued(cptr); + } + else if (fd >= 0 && (cptr = local[fd]) && DBufLength(&cptr->sendQ) > 0) + (void)send_queued(cptr); +} +#endif + +/* +** send_message +** Internal utility which delivers one message buffer to the +** socket. Takes care of the error handling and buffering, if +** needed. +** if ZIP_LINKS is defined, the message will eventually be compressed, +** anything stored in the sendQ is compressed. +*/ +static int send_message(to, msg, len) +aClient *to; +char *msg; /* if msg is a null pointer, we are flushing connection */ +int len; +#if !defined(CLIENT_COMPILE) +{ + int i; + + Debug((DEBUG_SEND,"Sending %s %d [%s] ", to->name, to->fd, msg)); + + if (to->from) + to = to->from; + if (to->fd < 0) + { + Debug((DEBUG_ERROR, + "Local socket %s with negative fd... AARGH!", + to->name)); + } + if (IsMe(to)) + { + sendto_flag(SCH_ERROR, "Trying to send to myself! [%s]", msg); + return 0; + } + if (IsDead(to)) + return 0; /* This socket has already been marked as dead */ + if (DBufLength(&to->sendQ) > get_sendq(to)) + { +# ifdef HUB + if (CBurst(to)) + { + aConfItem *aconf = to->serv->nline; + + poolsize -= MaxSendq(aconf->class) >> 1; + IncSendq(aconf->class); + poolsize += MaxSendq(aconf->class) >> 1; + sendto_flag(SCH_NOTICE, + "New poolsize %d. (sendq adjusted)", + poolsize); + istat.is_dbufmore++; + } + else if (IsServer(to) || IsService(to)) + sendto_flag(SCH_ERROR, + "Max SendQ limit exceeded for %s: %d > %d", + get_client_name(to, FALSE), + DBufLength(&to->sendQ), get_sendq(to)); + if (!CBurst(to)) + { + to->exitc = EXITC_SENDQ; + return dead_link(to, "Max Sendq exceeded"); + } +# else /* HUB */ + if (IsService(to) || IsServer(to)) + sendto_flag(SCH_ERROR, + "Max SendQ limit exceeded for %s: %d > %d", + get_client_name(to, FALSE), + DBufLength(&to->sendQ), get_sendq(to)); + to->exitc = EXITC_SENDQ; + return dead_link(to, "Max Sendq exceeded"); +# endif /* HUB */ + } + else + { +tryagain: +# ifdef ZIP_LINKS + /* + ** data is first stored in to->zip->outbuf until + ** it's big enough to be compressed and stored in the sendq. + ** send_queued is then responsible to never let the sendQ + ** be empty and to->zip->outbuf not empty. + */ + if (to->flags & FLAGS_ZIP) + msg = zip_buffer(to, msg, &len, 0); + + if (len && (i = dbuf_put(&to->sendQ, msg, len)) < 0) +# else /* ZIP_LINKS */ + if ((i = dbuf_put(&to->sendQ, msg, len)) < 0) +# endif /* ZIP_LINKS */ + if (i == -2 && CBurst(to)) + { /* poolsize was exceeded while connect burst */ + aConfItem *aconf = to->serv->nline; + + poolsize -= MaxSendq(aconf->class) >> 1; + IncSendq(aconf->class); + poolsize += MaxSendq(aconf->class) >> 1; + sendto_flag(SCH_NOTICE, + "New poolsize %d. (reached)", + poolsize); + istat.is_dbufmore++; + goto tryagain; + } + else + { + to->exitc = EXITC_MBUF; + return dead_link(to, + "Buffer allocation error for %s"); + } + } + /* + ** Update statistics. The following is slightly incorrect + ** because it counts messages even if queued, but bytes + ** only really sent. Queued bytes get updated in SendQueued. + */ + to->sendM += 1; + me.sendM += 1; + if (to->acpt != &me) + to->acpt->sendM += 1; + /* + ** This little bit is to stop the sendQ from growing too large when + ** there is no need for it to. Thus we call send_queued() every time + ** 2k has been added to the queue since the last non-fatal write. + ** Also stops us from deliberately building a large sendQ and then + ** trying to flood that link with data (possible during the net + ** relinking done by servers with a large load). + */ + if (DBufLength(&to->sendQ)/1024 > to->lastsq) + send_queued(to); + return 0; +} +#else /* CLIENT_COMPILE */ +{ + int rlen = 0, i; + + Debug((DEBUG_SEND,"Sending %s %d [%s] ", to->name, to->fd, msg)); + + if (to->from) + to = to->from; + if (to->fd < 0) + { + Debug((DEBUG_ERROR, + "Local socket %s with negative fd... AARGH!", + to->name)); + } + if (IsDead(to)) + return 0; /* This socket has already been marked as dead */ + + if ((rlen = deliver_it(to, msg, len)) < 0 && rlen < len) + return dead_link(to,"Write error to %s, closing link"); + /* + ** Update statistics. The following is slightly incorrect + ** because it counts messages even if queued, but bytes + ** only really sent. Queued bytes get updated in SendQueued. + */ + to->sendM += 1; + me.sendM += 1; + if (to->acpt != &me) + to->acpt->sendM += 1; + return 0; +} +#endif + +/* +** send_queued +** This function is called from the main select-loop (or whatever) +** when there is a chance the some output would be possible. This +** attempts to empty the send queue as far as possible... +*/ +int send_queued(to) +aClient *to; +{ + char *msg; + int len, rlen, more = 0; + + /* + ** Once socket is marked dead, we cannot start writing to it, + ** even if the error is removed... + */ + if (IsDead(to)) + { + /* + ** Actually, we should *NEVER* get here--something is + ** not working correct if send_queued is called for a + ** dead socket... --msa + */ + return -1; + } +#ifdef ZIP_LINKS + /* + ** Here, we must make sure than nothing will be left in to->zip->outbuf + ** This buffer needs to be compressed and sent if all the sendQ is sent + */ + if ((to->flags & FLAGS_ZIP) && to->zip->outcount) + { + if (DBufLength(&to->sendQ) > 0) + more = 1; + else + { + msg = zip_buffer(to, NULL, &len, 1); + + if (len == -1) + return dead_link(to, + "fatal error in zip_buffer()"); + + if (dbuf_put(&to->sendQ, msg, len) < 0) + { + to->exitc = EXITC_MBUF; + return dead_link(to, + "Buffer allocation error for %s"); + } + } + } +#endif + while (DBufLength(&to->sendQ) > 0 || more) + { + msg = dbuf_map(&to->sendQ, &len); + /* Returns always len > 0 */ + if ((rlen = deliver_it(to, msg, len)) < 0) + return dead_link(to,"Write error to %s, closing link"); + (void)dbuf_delete(&to->sendQ, rlen); + to->lastsq = DBufLength(&to->sendQ)/1024; + if (rlen < len) /* ..or should I continue until rlen==0? */ + break; + +#ifdef ZIP_LINKS + if (DBufLength(&to->sendQ) == 0 && more) + { + /* + ** The sendQ is now empty, compress what's left + ** uncompressed and try to send it too + */ + more = 0; + msg = zip_buffer(to, NULL, &len, 1); + + if (len == -1) + return dead_link(to, + "fatal error in zip_buffer()"); + + if (dbuf_put(&to->sendQ, msg, len) < 0) + { + to->exitc = EXITC_MBUF; + return dead_link(to, + "Buffer allocation error for %s"); + } + } +#endif + } + + return (IsDead(to)) ? -1 : 0; +} + + +#ifndef CLIENT_COMPILE +static anUser ausr = { NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, + NULL, "anonymous", "anonymous.", "anonymous."}; + +static aClient anon = { NULL, NULL, NULL, &ausr, NULL, NULL, 0, 0,/*flags*/ + &anon, -2, 0, STAT_CLIENT, "anonymous", "anonymous", + "anonymous identity hider", 0, "", +# ifdef ZIP_LINKS + NULL, +# endif + 0, {0, 0, NULL }, {0, 0, NULL }, + 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, NULL, 0 +# if defined(__STDC__) /* hack around union{} initialization -Vesa */ + ,{0}, NULL, "", "" +# endif + }; +#endif + +/* + * + */ +#if ! USE_STDARG +static int sendprep(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +static int vsendprep(char *pattern, va_list va) +#endif +{ + int len; + + Debug((DEBUG_L10, "sendprep(%s)", pattern)); +#if ! USE_STDARG + len = irc_sprintf(sendbuf, pattern, p1, p2, p3, p4, p5, p6, + p7, p8, p9, p10, p11); + if (len == -1) + len = strlen(sendbuf); +#else + len = vsprintf(sendbuf, pattern, va); +#endif + if (len > 510) +#ifdef IRCII_KLUDGE + len = 511; +#else + len = 510; + sendbuf[len++] = '\r'; +#endif + sendbuf[len++] = '\n'; + sendbuf[len] = '\0'; + return len; +} + +#ifndef CLIENT_COMPILE +#if ! USE_STDARG +static int sendpreprep(to, from, pattern, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) +aClient *to, *from; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +{ + static char sender[HOSTLEN+NICKLEN+USERLEN+5]; + Reg anUser *user; + char *par; + int flag = 0, len; + + Debug((DEBUG_L10, "sendpreprep(%#x(%s),%#x(%s),%s)", + to, to->name, from, from->name, pattern)); + par = p1; + if (to && from && MyClient(to) && IsPerson(from) && + !mycmp(par, from->name)) + { + user = from->user; + (void)strcpy(sender, from->name); + if (user) + { + if (*user->username) + { + (void)strcat(sender, "!"); + (void)strcat(sender, user->username); + } + if (*user->host && !MyConnect(from)) + { + (void)strcat(sender, "@"); + (void)strcat(sender, user->host); + flag = 1; + } + } + /* + ** flag is used instead of index(sender, '@') for speed and + ** also since username/nick may have had a '@' in them. -avalon + */ + if (!flag && MyConnect(from) && *user->host) + { + (void)strcat(sender, "@"); + if (IsUnixSocket(from)) + (void)strcat(sender, user->host); + else + (void)strcat(sender, from->sockhost); + } + par = sender; + } + len = irc_sprintf(psendbuf, pattern, par, p2, p3, p4, p5, p6, + p7, p8, p9, p10, p11); + if (len == -1) + len = strlen(psendbuf); + if (len > 510) +#ifdef IRCII_KLUDGE + len = 511; +#else + len = 510; + psendbuf[len++] = '\r'; +#endif + psendbuf[len++] = '\n'; + psendbuf[len] = '\0'; + return len; +} + +#else /* USE_STDARG */ + +static int vsendpreprep(aClient *to, aClient *from, char *pattern, va_list va) +{ + Reg anUser *user; + int flag = 0, len; + + Debug((DEBUG_L10, "sendpreprep(%#x(%s),%#x(%s),%s)", + to, to->name, from, from->name, pattern)); + if (to && from && MyClient(to) && IsPerson(from) && + !strncmp(pattern, ":%s", 3)) + { + char *par = va_arg(va, char *); + if (from == &anon || !mycmp(par, from->name)) + { + user = from->user; + (void)strcpy(psendbuf, ":"); + (void)strcat(psendbuf, from->name); + if (user) + { + if (*user->username) + { + (void)strcat(psendbuf, "!"); + (void)strcat(psendbuf, user->username); + } + if (*user->host && !MyConnect(from)) + { + (void)strcat(psendbuf, "@"); + (void)strcat(psendbuf, user->host); + flag = 1; + } + } + /* + ** flag is used instead of index(newpat, '@') for speed and + ** also since username/nick may have had a '@' in them. -avalon + */ + if (!flag && MyConnect(from) && *user->host) + { + (void)strcat(psendbuf, "@"); + if (IsUnixSocket(from)) + (void)strcat(psendbuf, user->host); + else + (void)strcat(psendbuf, from->sockhost); + } + } + else + { + (void)strcpy(psendbuf, ":"); + (void)strcat(psendbuf, par); + } + + len = strlen(psendbuf); + len += vsprintf(psendbuf+len, pattern+3, va); + } + else + len = vsprintf(psendbuf, pattern, va); + + if (len > 510) +#ifdef IRCII_KLUDGE + len = 511; +#else + len = 510; + psendbuf[len++] = '\r'; +#endif + psendbuf[len++] = '\n'; + psendbuf[len] = '\0'; + return len; +} +#endif /* USE_STDARG */ +#endif /* CLIENT_COMPILE */ + +/* +** send message to single client +*/ +#if ! USE_STDARG +int sendto_one(to, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) +aClient *to; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +int vsendto_one(aClient *to, char *pattern, va_list va) +#endif +{ + int len; + +#if ! USE_STDARG + len = sendprep(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); +#else + len = vsendprep(pattern, va); +#endif + + (void)send_message(to, sendbuf, len); + return len; +} + +#if USE_STDARG +int sendto_one(aClient *to, char *pattern, ...) +{ + int len; + va_list va; + va_start(va, pattern); + len = vsendto_one(to, pattern, va); + va_end(va); + return len; +} +#endif + +#ifndef CLIENT_COMPILE +#if ! USE_STDARG +/*VARARGS*/ +void sendto_channel_butone(one, from, chptr, pattern, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) +aClient *one, *from; +aChannel *chptr; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +void sendto_channel_butone(aClient *one, aClient *from, aChannel *chptr, char *pattern, ...) +#endif +{ + Reg Link *lp; + Reg aClient *acptr, *lfrm = from; + int len1, len2 = 0; + + if (IsAnonymous(chptr) && IsClient(from)) + { +#if ! USE_STDARG + if (p1 && *p1 && !mycmp(p1, from->name)) + p1 = anon.name; +#endif + lfrm = &anon; + } + + if (one != from && MyConnect(from) && IsRegisteredUser(from)) + { + /* useless junk? */ +#if ! USE_STDARG + sendto_prefix_one(from, from, pattern, p1, p2, p3, p4, + p5, p6, p7, p8, p9, p10, p11); +#else + va_list va; + va_start(va, pattern); + vsendto_prefix_one(from, from, pattern, va); + va_end(va); +#endif + } + +#if ! USE_STDARG + len1 = sendprep(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); +#else + { + va_list va; + va_start(va, pattern); + len1 = vsendprep(pattern, va); + va_end(va); + } +#endif + + + for (lp = chptr->clist; lp; lp = lp->next) + { + acptr = lp->value.cptr; + if (acptr->from == one || IsMe(acptr)) + continue; /* ...was the one I should skip */ + if (MyConnect(acptr) && IsRegisteredUser(acptr)) + { + if (!len2) + { +#if ! USE_STDARG + len2 = sendpreprep(acptr, lfrm, pattern, p1, + p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11); +#else + va_list va; + va_start(va, pattern); + len2 = vsendpreprep(acptr, lfrm, pattern, va); + va_end(va); +#endif + } + + if (acptr != from) + (void)send_message(acptr, psendbuf, len2); + } + else + (void)send_message(acptr, sendbuf, len1); + } + return; +} + +/* + * sendto_server_butone + * + * Send a message to all connected servers except the client 'one'. + */ +#if ! USE_STDARG +/*VARARGS*/ +void sendto_serv_butone(one, pattern, p1, p2, p3, p4,p5,p6,p7,p8,p9,p10,p11) +aClient *one; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +void sendto_serv_butone(aClient *one, char *pattern, ...) +#endif +{ + Reg int i, len=0; + Reg aClient *cptr; + + for (i = fdas.highest; i >= 0; i--) + if ((cptr = local[fdas.fd[i]]) && + (!one || cptr != one->from) && !IsMe(cptr)) { + if (!len) + { +#if ! USE_STDARG + len = sendprep(pattern, p1, p2, p3, p4, p5, + p6, p7, p8, p9, p10, p11); +#else + va_list va; + va_start(va, pattern); + len = vsendprep(pattern, va); + va_end(va); +#endif + } + (void)send_message(cptr, sendbuf, len); + } + return; +} + +#if ! USE_STDARG +int +sendto_serv_v(one, ver, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) +aClient *one; +int ver; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +int +sendto_serv_v(aClient *one, int ver, char *pattern, ...) +#endif +{ + Reg int i, len=0, rc=0; + Reg aClient *cptr; + + for (i = fdas.highest; i >= 0; i--) + if ((cptr = local[fdas.fd[i]]) && + (!one || cptr != one->from) && !IsMe(cptr)) + if (cptr->serv->version & ver) + { + if (!len) + { +#if ! USE_STDARG + len = sendprep(pattern, p1, p2, p3, p4, + p5, p6, p7, p8, p9, p10, + p11); +#else + va_list va; + va_start(va, pattern); + len = vsendprep(pattern, va); + va_end(va); +#endif + } + (void)send_message(cptr, sendbuf, len); + } + else + rc = 1; + return rc; +} + +#if ! USE_STDARG +int +sendto_serv_notv(one, ver, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9,p10,p11) +aClient *one; +int ver; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +int +sendto_serv_notv(aClient *one, int ver, char *pattern, ...) +#endif +{ + Reg int i, len=0, rc=0; + Reg aClient *cptr; + + for (i = fdas.highest; i >= 0; i--) + if ((cptr = local[fdas.fd[i]]) && + (!one || cptr != one->from) && !IsMe(cptr)) + if ((cptr->serv->version & ver) == 0) + { + if (!len) + { +#if ! USE_STDARG + len = sendprep(pattern, p1, p2, p3, p4, + p5, p6, p7, p8, p9, p10, + p11); +#else + va_list va; + va_start(va, pattern); + len = vsendprep(pattern, va); + va_end(va); +#endif + } + (void)send_message(cptr, sendbuf, len); + } + else + rc = 1; + return rc; +} + +/* + * sendto_common_channels() + * + * Sends a message to all people (inclusing user) on local server who are + * in same channel with user, except for channels set Quiet or Anonymous + * The calling procedure must take the necessary steps for such channels. + */ +#if ! USE_STDARG +/*VARARGS*/ +void sendto_common_channels(user,pattern,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11) +aClient *user; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +void sendto_common_channels(aClient *user, char *pattern, ...) +#endif +{ + Reg int i; + Reg aClient *cptr; + Reg Link *channels, *lp; + int len = 0; + +/* This is kind of funky, but should work. The first part below + is optimized for HUB servers or servers with few clients on + them. The second part is optimized for bigger client servers + where looping through the whole client list is bad. I'm not + really certain of the point at which each function equals + out...but I do know the 2nd part will help big client servers + fairly well... - Comstud 97/04/24 +*/ + + if (highest_fd < 50) /* This part optimized for HUB servers... */ + { + if (MyConnect(user)) + { +#if ! USE_STDARG + len = sendpreprep(user, user, pattern, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11); + +#else + va_list va; + va_start(va, pattern); + len = vsendpreprep(user, user, pattern, va); + va_end(va); +#endif + (void)send_message(user, psendbuf, len); + } + for (i = 0; i <= highest_fd; i++) + { + if (!(cptr = local[i]) || IsServer(cptr) || + user == cptr || !user->user) + continue; + for (lp = user->user->channel; lp; lp = lp->next) + { + if (!IsMember(cptr, lp->value.chptr)) + continue; + if (IsAnonymous(lp->value.chptr)) + continue; + if (!IsQuiet(lp->value.chptr)) + { +#ifndef DEBUGMODE + if (!len) /* This saves little cpu, + but breaks the debug code.. */ +#endif + { +#if ! USE_STDARG + len = sendpreprep(cptr, user, pattern, + p1, p2, p3, p4, p5, + p6, p7, p8, p9, p10, + p11); +#else + va_list va; + va_start(va, pattern); + len = vsendpreprep(cptr, user, pattern, va); + va_end(va); +#endif + } + (void)send_message(cptr, psendbuf, + len); + break; + } + } + } + } + else + { + /* This part optimized for client servers */ + bzero((char *)&sentalong[0], sizeof(int) * MAXCONNECTIONS); + if (MyConnect(user)) + { +#if ! USE_STDARG + len = sendpreprep(user, user, pattern, p1, p2, p3, p4, + p5, p6, p7, p8, p9, p10, p11); +#else + va_list va; + va_start(va, pattern); + len = vsendpreprep(user, user, pattern, va); + va_end(va); +#endif + (void)send_message(user, psendbuf, len); + sentalong[user->fd] = 1; + } + if (!user->user) + return; + for (channels=user->user->channel; channels; + channels=channels->next) + { + if (IsQuiet(channels->value.chptr)) + continue; + if (IsAnonymous(channels->value.chptr)) + continue; + for (lp=channels->value.chptr->members;lp; + lp=lp->next) + { + cptr = lp->value.cptr; + if (user == cptr) + continue; + if (!MyConnect(cptr) || sentalong[cptr->fd]) + continue; + sentalong[cptr->fd]++; +#ifndef DEBUGMODE + if (!len) /* This saves little cpu, + but breaks the debug code.. */ +#endif + { +#if ! USE_STDARG + len = sendpreprep(cptr, user, pattern, + p1, p2, p3, p4, p5, + p6, p7, p8, p9, p10, + p11); +#else + va_list va; + va_start(va, pattern); + len = vsendpreprep(cptr, user, pattern, va); + va_end(va); +#endif + } + (void)send_message(cptr, psendbuf, len); + } + } + } + return; +} + +/* + * sendto_channel_butserv + * + * Send a message to all members of a channel that are connected to this + * server. + */ +#if ! USE_STDARG +/*VARARGS*/ +void sendto_channel_butserv(chptr, from, pattern, p1, p2, p3, + p4, p5, p6, p7, p8, p9, p10, p11) +aChannel *chptr; +aClient *from; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +void sendto_channel_butserv(aChannel *chptr, aClient *from, char *pattern, ...) +#endif +{ + Reg Link *lp; + Reg aClient *acptr, *lfrm = from; + int len = 0; + + if (MyClient(from)) + { /* Always send to the client itself */ +#if ! USE_STDARG + sendto_prefix_one(from, from, pattern, p1, p2, p3, p4, + p5, p6, p7, p8, p9, p10, p11); +#else + va_list va; + va_start(va, pattern); + vsendto_prefix_one(from, from, pattern, va); + va_end(va); +#endif + if (IsQuiet(chptr)) /* Really shut up.. */ + return; + } + if (IsAnonymous(chptr) && IsClient(from)) + { +#if ! USE_STDARG + if (p1 && *p1 && !mycmp(p1, from->name)) + p1 = anon.name; +#endif + lfrm = &anon; + } + + for (lp = chptr->members; lp; lp = lp->next) + if (MyClient(acptr = lp->value.cptr) && acptr != from) + { + if (!len) + { +#if ! USE_STDARG + len = sendpreprep(acptr, lfrm, pattern, p1, p2, + p3, p4, p5, p6, p7, p8, p9, + p10, p11); +#else + va_list va; + va_start(va, pattern); + len = vsendpreprep(acptr, lfrm, pattern, va); + va_end(va); +#endif + } + (void)send_message(acptr, psendbuf, len); + } + + return; +} + +/* +** send a msg to all ppl on servers/hosts that match a specified mask +** (used for enhanced PRIVMSGs) +** +** addition -- Armin, 8jun90 (gruner@informatik.tu-muenchen.de) +*/ + +static int match_it(one, mask, what) +aClient *one; +char *mask; +int what; +{ + switch (what) + { + case MATCH_HOST: + return (match(mask, one->user->host)==0); + case MATCH_SERVER: + default: + return (match(mask, one->user->server)==0); + } +} + +/* + * sendto_match_servs + * + * send to all servers which match the mask at the end of a channel name + * (if there is a mask present) or to all if no mask. + */ +#if ! USE_STDARG +/*VARARGS*/ +void sendto_match_servs(chptr, from, format, p1, p2, p3, p4, p5, p6, p7, + p8, p9, p10, p11) +aChannel *chptr; +aClient *from; +char *format, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +void sendto_match_servs(aChannel *chptr, aClient *from, char *format, ...) +#endif +{ + Reg int i, len=0; + Reg aClient *cptr; + char *mask; + + if (chptr) + { + if (*chptr->chname == '&') + return; + if ((mask = (char *)rindex(chptr->chname, ':'))) + mask++; + } + else + mask = (char *)NULL; + + for (i = fdas.highest; i >= 0; i--) + { + if (!(cptr = local[fdas.fd[i]]) || (cptr == from) || + IsMe(cptr)) + continue; + if (!BadPtr(mask) && match(mask, cptr->name)) + continue; + if (chptr && + *chptr->chname == '!' && !(cptr->serv->version & SV_NJOIN)) + continue; + if (!len) + { +#if ! USE_STDARG + len = sendprep(format, p1, p2, p3, p4, p5, p6, p7, + p8, p9, p10, p11); +#else + va_list va; + va_start(va, format); + len = vsendprep(format, va); + va_end(va); +#endif + } + (void)send_message(cptr, sendbuf, len); + } +} + +#if ! USE_STDARG +/*VARARGS*/ +int +sendto_match_servs_v(chptr, from, ver, format, p1, p2, p3, p4, p5, p6, + p7, p8, p9, p10, p11) +aChannel *chptr; +aClient *from; +char *format, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +int ver; +#else +int +sendto_match_servs_v(aChannel *chptr, aClient *from, int ver, + char *format, ...) +#endif +{ + Reg int i, len=0, rc=0; + Reg aClient *cptr; + char *mask; + + if (chptr) + { + if (*chptr->chname == '&') + return 0; + if ((mask = (char *)rindex(chptr->chname, ':'))) + mask++; + } + else + mask = (char *)NULL; + + for (i = fdas.highest; i >= 0; i--) + { + if (!(cptr = local[fdas.fd[i]]) || (cptr == from) || + IsMe(cptr)) + continue; + if (!BadPtr(mask) && match(mask, cptr->name)) + continue; + if (chptr && + *chptr->chname == '!' && !(cptr->serv->version & SV_NJOIN)) + continue; + if ((ver & cptr->serv->version) == 0) + { + rc = 1; + continue; + } + if (!len) + { +#if ! USE_STDARG + len = sendprep(format, p1, p2, p3, p4, p5, p6, p7, + p8, p9, p10, p11); +#else + va_list va; + va_start(va, format); + len = vsendprep(format, va); + va_end(va); +#endif + } + (void)send_message(cptr, sendbuf, len); + } + return rc; +} + +#if ! USE_STDARG +/*VARARGS*/ +int +sendto_match_servs_notv(chptr, from, ver, format, p1, p2, p3, p4, p5, + p6, p7, p8, p9, p10, p11) +aChannel *chptr; +aClient *from; +char *format, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +int ver; +#else +int +sendto_match_servs_notv(aChannel *chptr, aClient *from, int ver, + char *format, ...) +#endif +{ + Reg int i, len=0, rc=0; + Reg aClient *cptr; + char *mask; + + if (chptr) + { + if (*chptr->chname == '&') + return 0; + if ((mask = (char *)rindex(chptr->chname, ':'))) + mask++; + } + else + mask = (char *)NULL; + + for (i = fdas.highest; i >= 0; i--) + { + if (!(cptr = local[fdas.fd[i]]) || (cptr == from) || + IsMe(cptr)) + continue; + if (!BadPtr(mask) && match(mask, cptr->name)) + continue; + if (chptr && + *chptr->chname == '!' && !(cptr->serv->version & SV_NJOIN)) + continue; + if ((ver & cptr->serv->version) != 0) + { + rc = 1; + continue; + } + if (!len) + { +#if ! USE_STDARG + len = sendprep(format, p1, p2, p3, p4, p5, p6, p7, + p8, p9, p10, p11); +#else + va_list va; + va_start(va, format); + len = vsendprep(format, va); + va_end(va); +#endif + } + (void)send_message(cptr, sendbuf, len); + } + return rc; +} + +/* + * sendto_match_butone + * + * Send to all clients which match the mask in a way defined on 'what'; + * either by user hostname or user servername. + */ +/*VARARGS*/ +#if ! USE_STDARG +void sendto_match_butone(one, from, mask, what, pattern, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) +aClient *one, *from; +int what; +char *mask, *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9,*p10,*p11; +#else +void sendto_match_butone(aClient *one, aClient *from, char *mask, int what, char *pattern, ...) + +#endif +{ + int i; + aClient *cptr, + *srch; + + for (i = 0; i <= highest_fd; i++) + { + if (!(cptr = local[i])) + continue; /* that clients are not mine */ + if (cptr == one) /* must skip the origin !! */ + continue; + if (IsServer(cptr)) + { + /* + ** we can save some CPU here by not searching the + ** entire list of users since it is ordered! + ** original idea/code from pht. + ** it could be made better by looping on the list of + ** servers to avoid non matching blocks in the list + ** (srch->from != cptr), but then again I never + ** bothered to worry or optimize this routine -kalt + */ + for (srch = cptr->prev; srch; srch = srch->prev) + { + if (!IsRegisteredUser(srch)) + continue; + if (srch->from == cptr && + match_it(srch, mask, what)) + break; + } + if (srch == NULL) + continue; + } + /* my client, does he match ? */ + else if (!(IsRegisteredUser(cptr) && + match_it(cptr, mask, what))) + continue; +#if ! USE_STDARG + sendto_prefix_one(cptr, from, pattern, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11); +#else + { + va_list va; + va_start(va, pattern); + vsendto_prefix_one(cptr, from, pattern, va); + va_end(va); + } +#endif + + } + return; +} + +/* +** sendto_ops_butone +** Send message to all operators. +** one - client not to send message to +** from- client which message is from *NEVER* NULL!! +*/ +#if ! USE_STDARG +/*VARARGS*/ +void sendto_ops_butone(one, from, pattern, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) +aClient *one, *from; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +void sendto_ops_butone(aClient *one, aClient *from, char *pattern, ...) +#endif +{ + Reg int i; + Reg aClient *cptr; + + bzero((char *)&sentalong[0], sizeof(int) * MAXCONNECTIONS); + for (cptr = client; cptr; cptr = cptr->next) + { + if (IsService(cptr) || !IsRegistered(cptr)) + continue; + if ((IsPerson(cptr) && !SendWallops(cptr)) || IsMe(cptr)) + continue; + if (MyClient(cptr) && !(IsServer(from) || IsMe(from))) + continue; + i = cptr->from->fd; /* find connection oper is on */ + if (sentalong[i]) /* sent message along it already ? */ + continue; + if (cptr->from == one) + continue; /* ...was the one I should skip */ + sentalong[i] = 1; +#if ! USE_STDARG + sendto_prefix_one(cptr->from, from, pattern, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11); +#else + { + va_list va; + va_start(va, pattern); + vsendto_prefix_one(cptr->from, from, pattern, va); + va_end(va); + } +#endif + } + return; +} + +/* + * to - destination client + * from - client which message is from + * + * NOTE: NEITHER OF THESE SHOULD *EVER* BE NULL!! + * -avalon + */ +#if ! USE_STDARG +/*VARARGS*/ +void sendto_prefix_one(to, from, pattern, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) +Reg aClient *to; +Reg aClient *from; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +void sendto_prefix_one(aClient *to, aClient *from, char *pattern, ...) +#endif +{ + int len; + +#if ! USE_STDARG + len = sendpreprep(to, from, pattern, p1, p2, p3, p4, p5, p6, p7, p8, + p9, p10, p11); +#else + va_list va; + va_start(va, pattern); + len = vsendpreprep(to, from, pattern, va); + va_end(va); +#endif + send_message(to, psendbuf, len); + return; +} + +#if USE_STDARG +static void vsendto_prefix_one(aClient *to, aClient *from, char *pattern, va_list va) +{ + int len; + + len = vsendpreprep(to, from, pattern, va); + send_message(to, psendbuf, len); + return; +} +#endif + + +/* + * sends a message to a server-owned channel + */ +static SChan svchans[SCH_MAX] = { + { SCH_ERROR, "&ERRORS", NULL }, + { SCH_NOTICE, "&NOTICES", NULL }, + { SCH_KILL, "&KILLS", NULL }, + { SCH_CHAN, "&CHANNEL", NULL }, + { SCH_NUM, "&NUMERICS", NULL }, + { SCH_SERVER, "&SERVERS", NULL }, + { SCH_HASH, "&HASH", NULL }, + { SCH_LOCAL, "&LOCAL", NULL }, + { SCH_SERVICE, "&SERVICES", NULL }, + { SCH_DEBUG, "&DEBUG", NULL }, + { SCH_AUTH, "&AUTH", NULL }, +}; + + +void setup_svchans() +{ + int i; + SChan *shptr; + + for (i = SCH_MAX, shptr = svchans + (i - 1); i > 0; i--, shptr--) + shptr->svc_ptr = find_channel(shptr->svc_chname, NULL); +} + +#if ! USE_STDARG +void sendto_flag(chan, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11) +u_int chan; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +#else +void sendto_flag(u_int chan, char *pattern, ...) +#endif +{ + Reg aChannel *chptr = NULL; + SChan *shptr; + char nbuf[1024]; + + if (chan < 1 || chan > SCH_MAX) + chan = SCH_NOTICE; + shptr = svchans + (chan - 1); + + if ((chptr = shptr->svc_ptr)) + { +#if ! USE_STDARG + (void)sprintf(nbuf, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); +#else + { + va_list va; + va_start(va, pattern); + (void)vsprintf(nbuf, pattern, va); + va_end(va); + } +#endif + sendto_channel_butserv(chptr, &me, ":%s NOTICE %s :%s", ME, chptr->chname, nbuf); + +#ifdef USE_SERVICES + switch (chan) + { + case SCH_ERROR: + check_services_butone(SERVICE_WANT_ERRORS, NULL, &me, + "&ERRORS :%s", nbuf); + break; + case SCH_NOTICE: + check_services_butone(SERVICE_WANT_NOTICES, NULL, &me, + "&NOTICES :%s", nbuf); + break; + case SCH_LOCAL: + check_services_butone(SERVICE_WANT_LOCAL, NULL, &me, + "&LOCAL :%s", nbuf); + break; + case SCH_NUM: + check_services_butone(SERVICE_WANT_NUMERICS, NULL, &me, + "&NUMERICS :%s", nbuf); + break; + } +#endif + } + + return; +} + +/* + * sendto_flog + * cptr used for firsttime, auth, exitc, send/received M/K + * msg replaces duration if duration is 0 + * duration only used if non 0 + * username can't get it from cptr + * hostname i.e. + */ +void sendto_flog(cptr, msg, duration, username, hostname) +aClient *cptr; +char *msg, *username, *hostname; +time_t duration; +{ + char linebuf[1024]; /* auth reply might be long.. */ + int logfile; + +#ifdef USE_SERVICES + if (duration) + { + (void)sprintf(linebuf, + "%s (%3d:%02d:%02d): %s@%s [%s] %c %lu %luKb %lu %luKb\n", + myctime(cptr->firsttime), + (int) (duration / 3600), + (int) ((duration % 3600) / 60), + (int) (duration % 60), + username, hostname, cptr->auth, + cptr->exitc, cptr->sendM, cptr->sendK, + cptr->receiveM, cptr->receiveK); + check_services_butone(SERVICE_WANT_USERLOG, NULL, &me, + "USERLOG :%s", linebuf); + } + else + { + (void)sprintf(linebuf, + "%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb\n", + myctime(cptr->firsttime), msg, username, + hostname, cptr->auth, + cptr->exitc, cptr->sendM, cptr->sendK, + cptr->receiveM, cptr->receiveK); + check_services_butone(SERVICE_WANT_CONNLOG, NULL, &me, + "CONNLOG :%s", linebuf); + } +#endif + /* + * 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 + * file in 3 seconds. -avalon (curtesy of wumpus) + */ + (void)alarm(3); + if ( +#ifdef FNAME_USERLOG + (duration && + (logfile = open(FNAME_USERLOG, O_WRONLY|O_APPEND)) != -1) +# ifdef FNAME_CONNLOG + || +# endif +#endif +#ifdef FNAME_CONNLOG + (!duration && + (logfile = open(FNAME_CONNLOG, O_WRONLY|O_APPEND)) != -1) +#else +# ifndef FNAME_USERLOG + 0 +# endif +#endif + ) + { + (void)alarm(0); +#ifndef USE_SERVICES + if (duration) + (void)sprintf(linebuf, + "%s (%3d:%02d:%02d): %s@%s [%s] %c %lu %luKb %lu %luKb\n", + myctime(cptr->firsttime), + (int) (duration / 3600), + (int) ((duration % 3600) / 60), + (int) (duration % 60), + username, hostname, cptr->auth, + cptr->exitc, cptr->sendM, cptr->sendK, + cptr->receiveM, cptr->receiveK); + else + (void)sprintf(linebuf, + "%s (%s): %s@%s [%s] %c %lu %luKb %lu %luKb\n", + myctime(cptr->firsttime), msg, username, + hostname, cptr->auth, + cptr->exitc, cptr->sendM, cptr->sendK, + cptr->receiveM, cptr->receiveK); +#endif + (void)alarm(3); + (void)write(logfile, linebuf, strlen(linebuf)); + (void)alarm(0); + (void)close(logfile); + } + (void)alarm(0); +} +#endif /* CLIENT_COMPILE */ diff --git a/common/send_ext.h b/common/send_ext.h new file mode 100644 index 0000000..7f0d409 --- /dev/null +++ b/common/send_ext.h @@ -0,0 +1,82 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/send_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in common/send.c. + */ + +/* External definitions for global functions. + */ +#ifndef SEND_C +#define EXTERN extern +#else /* SEND_C */ +#define EXTERN +#endif /* SEND_C */ +EXTERN int send_queued __P((aClient *to)); +#if ! USE_STDARG +EXTERN int sendto_one(); +#else /* USE_STDARG */ +EXTERN int vsendto_one (aClient *to, char *pattern, va_list va); +EXTERN int sendto_one (aClient *to, char *pattern, ...); +#endif /* USE_STDARG */ +#ifndef CLIENT_COMPILE +EXTERN void flush_connections __P((int fd)); +EXTERN void flush_fdary __P((FdAry *)); +EXTERN void setup_svchans(); +EXTERN void sendto_flog __P((aClient *cptr, char *msg, time_t duration, + char *username, char *hostname)); +#if ! USE_STDARG +EXTERN void sendto_channel_butone(); +EXTERN void sendto_serv_butone(); +EXTERN int sendto_serv_v(); +EXTERN int sendto_serv_notv(); +EXTERN void sendto_common_channels(); +EXTERN void sendto_channel_butserv(); +EXTERN void sendto_match_servs(); +EXTERN int sendto_match_servs_v(); +EXTERN int sendto_match_servs_notv(); +EXTERN void sendto_match_butone(); +EXTERN void sendto_ops_butone(); +EXTERN void sendto_prefix_one(); +EXTERN void sendto_flag(); +#else /* USE_STDARG */ +EXTERN void sendto_channel_butone (aClient *one, aClient *from, + aChannel *chptr, char *pattern, ...); +EXTERN void sendto_serv_butone (aClient *one, char *pattern, ...); +EXTERN int sendto_serv_v (aClient *one, int ver, char *pattern, ...); +EXTERN int sendto_serv_notv (aClient *one, int ver, char *pattern, ...); +EXTERN void sendto_common_channels (aClient *user, char *pattern, ...); +EXTERN void sendto_channel_butserv (aChannel *chptr, aClient *from, + char *pattern, ...); +EXTERN void sendto_match_servs (aChannel *chptr, aClient *from, + char *format, ...); +EXTERN int sendto_match_servs_v (aChannel *chptr, aClient *from, int ver, + char *format, ...); +EXTERN int sendto_match_servs_notv (aChannel *chptr, aClient *from, int ver, + char *format, ...); +EXTERN void sendto_match_butone (aClient *one, aClient *from, char *mask, + int what, char *pattern, ...); +EXTERN void sendto_ops_butone (aClient *one, aClient *from, char *pattern, + ...); +EXTERN void sendto_prefix_one (aClient *to, aClient *from, char *pattern, + ...); +EXTERN void sendto_flag (u_int chan, char *pattern, ...); +#endif /* USE_STDARG */ +#endif /* CLIENT_COMPILE */ +#undef EXTERN diff --git a/common/struct_def.h b/common/struct_def.h new file mode 100644 index 0000000..720a531 --- /dev/null +++ b/common/struct_def.h @@ -0,0 +1,832 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/struct_def.h + * 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. + */ + +typedef struct ConfItem aConfItem; +typedef struct Client aClient; +typedef struct Channel aChannel; +typedef struct User anUser; +typedef struct Server aServer; +typedef struct Service aService; +typedef struct SLink Link; +typedef struct SMode Mode; +typedef struct fdarray FdAry; +typedef struct CPing aCPing; +typedef struct Zdata aZdata; +#if defined(CACHED_MOTD) +typedef struct LineItem aMotd; +#endif +#if defined(USE_IAUTH) +typedef struct LineItem aExtCf; +typedef struct LineItem aExtData; +#endif + +#define HOSTLEN 63 /* Length of hostname. Updated to */ + /* comply with RFC1123 */ + +#define NICKLEN 9 /* Necessary to put 9 here instead of 10 + ** if s_msg.c/m_nick has been corrected. + ** This preserves compatibility with old + ** servers --msa + */ +#define USERLEN 10 +#define REALLEN 50 +#define TOPICLEN 80 +#define CHANNELLEN 50 +#define PASSWDLEN 20 +#define KEYLEN 23 +#define BUFSIZE 512 /* WARNING: *DONT* CHANGE THIS!!!! */ +#define MAXRECIPIENTS 20 +#define MAXBANS 30 +#define MAXBANLENGTH 1024 +#define BANLEN (USERLEN + NICKLEN + HOSTLEN + 3) +#define MAXPENALTY 10 +#define CHIDLEN 5 /* WARNING: *DONT* CHANGE THIS!!!! */ + +#define READBUF_SIZE 16384 /* used in s_bsd.c *AND* s_zip.c ! */ + +/* + * Make up some numbers which should reflect average leaf server connect + * queue max size. + * queue=(<# of channels> * <channel size> + <user size> * <# of users>) * 2 + * pool=<queue per client> * <avg. # of clients having data in queue> + */ +#define QUEUELEN (((MAXCONNECTIONS / 10) * (CHANNELLEN + BANLEN + 16) +\ + (HOSTLEN * 4 + REALLEN + NICKLEN + USERLEN + 24) *\ + (MAXCONNECTIONS / 2)) * 2) + +#define BUFFERPOOL (DBUFSIZ * MAXCONNECTIONS * 2) + \ + (QUEUELEN * MAXSERVERS) + +#define USERHOST_REPLYLEN (NICKLEN+HOSTLEN+USERLEN+5) + +/* +** 'offsetof' is defined in ANSI-C. The following definition +** is not absolutely portable (I have been told), but so far +** it has worked on all machines I have needed it. The type +** should be size_t but... --msa +*/ +#ifndef offsetof +#define offsetof(t,m) (int)((&((t *)0L)->m)) +#endif + +#define elementsof(x) (sizeof(x)/sizeof(x[0])) + +/* +** flags for bootup options (command line flags) +*/ +#define BOOT_CONSOLE 0x001 +#define BOOT_QUICK 0x002 +#define BOOT_DEBUG 0x004 +#define BOOT_INETD 0x008 +#define BOOT_TTY 0x010 +#define BOOT_OPER 0x020 +#define BOOT_AUTODIE 0x040 +#define BOOT_BADTUNE 0x080 +#define BOOT_PROT 0x100 +#define BOOT_STRICTPROT 0x200 +#define BOOT_NOIAUTH 0x400 + +#define STAT_RECONNECT -7 /* Reconnect attempt for server connections */ +#define STAT_LOG -6 /* logfile for -x */ +#define STAT_MASTER -5 /* Local ircd master before identification */ +#define STAT_CONNECTING -4 +#define STAT_HANDSHAKE -3 +#define STAT_UNKNOWN -2 +#define STAT_ME -1 +#define STAT_SERVER 0 +#define STAT_CLIENT 1 +#define STAT_SERVICE 2 + +/* + * status macros. + */ +#define IsRegisteredUser(x) ((x)->status == STAT_CLIENT && (x)->user) +#define IsRegistered(x) ((x)->status >= STAT_SERVER || \ + (x)->status == STAT_ME) +#define IsConnecting(x) ((x)->status == STAT_CONNECTING) +#define IsHandshake(x) ((x)->status == STAT_HANDSHAKE) +#define IsMe(x) ((x)->status == STAT_ME) +#define IsUnknown(x) ((x)->status == STAT_UNKNOWN || \ + (x)->status == STAT_MASTER) +#define IsServer(x) ((x)->status == STAT_SERVER) +#define IsClient(x) ((x)->status == STAT_CLIENT) +#define IsLog(x) ((x)->status == STAT_LOG) +#define IsService(x) ((x)->status == STAT_SERVICE && (x)->service) +#define IsReconnect(x) ((x)->status == STAT_RECONNECT) + +#define SetMaster(x) ((x)->status = STAT_MASTER) +#define SetConnecting(x) ((x)->status = STAT_CONNECTING) +#define SetHandshake(x) ((x)->status = STAT_HANDSHAKE) +#define SetMe(x) ((x)->status = STAT_ME) +#define SetUnknown(x) ((x)->status = STAT_UNKNOWN) +#define SetServer(x) ((x)->status = STAT_SERVER) +#define SetClient(x) ((x)->status = STAT_CLIENT) +#define SetLog(x) ((x)->status = STAT_LOG) +#define SetService(x) ((x)->status = STAT_SERVICE) + +#define FLAGS_PINGSENT 0x0001 /* Unreplied ping sent */ +#define FLAGS_DEADSOCKET 0x0002 /* Local socket is dead--Exiting soon */ +#define FLAGS_KILLED 0x0004 /* Prevents "QUIT" from being sent for this */ +#define FLAGS_BLOCKED 0x0008 /* socket is in a blocked condition [unused] */ +#define FLAGS_UNIX 0x0010 /* socket is in the unix domain, not inet */ +#define FLAGS_CLOSING 0x0020 /* set when closing to suppress errors */ +#define FLAGS_LISTEN 0x0040 /* used to mark clients which we listen() on */ +#define FLAGS_XAUTHDONE 0x0080 /* iauth is finished with this client */ +#define FLAGS_DOINGDNS 0x0100 /* client is waiting for a DNS response */ +#define FLAGS_AUTH 0x0200 /* client is waiting on rfc931 response */ +#define FLAGS_WRAUTH 0x0400 /* set if we havent writen to ident server */ +#define FLAGS_LOCAL 0x0800 /* set for local clients */ +#define FLAGS_GOTID 0x1000 /* successful ident lookup achieved */ +#define FLAGS_XAUTH 0x2000 /* waiting on external authentication */ +#define FLAGS_WXAUTH 0x4000 /* same as above, but also prevent parsing */ +#define FLAGS_NONL 0x8000 /* No \n in buffer */ +#define FLAGS_CBURST 0x10000 /* set to mark connection burst being sent */ +#define FLAGS_RILINE 0x20000 /* Restricted i-line [unused?] */ +#define FLAGS_QUIT 0x40000 /* QUIT :comment shows it's not a split */ +#define FLAGS_SPLIT 0x80000 /* client QUITting because of a netsplit */ +#define FLAGS_HIDDEN 0x100000 /* netsplit is behind a hostmask */ +#define FLAGS_UNKCMD 0x200000 /* has sent an unknown command */ +#define FLAGS_ZIP 0x400000 /* link is zipped */ +#define FLAGS_ZIPRQ 0x800000 /* zip requested */ +#define FLAGS_ZIPSTART 0x1000000 /* start of zip (ignore any CRLF) */ +#define FLAGS_HELD 0x8000000 /* connection held and reconnect try */ + +#define FLAGS_OPER 0x0001 /* Operator */ +#define FLAGS_LOCOP 0x0002 /* Local operator -- SRB */ +#define FLAGS_WALLOP 0x0004 /* send wallops to them */ +#define FLAGS_INVISIBLE 0x0008 /* makes user invisible */ +#define FLAGS_RESTRICTED 0x0010 /* Restricted user */ +#define FLAGS_AWAY 0x0020 /* user is away */ + +#define SEND_UMODES (FLAGS_INVISIBLE|FLAGS_OPER|FLAGS_WALLOP|FLAGS_AWAY) +#define ALL_UMODES (SEND_UMODES|FLAGS_LOCOP|FLAGS_RESTRICTED) + +/* + * flags macros. + */ +#define IsOper(x) ((x)->user && (x)->user->flags & FLAGS_OPER) +#define IsLocOp(x) ((x)->user && (x)->user->flags & FLAGS_LOCOP) +#define IsInvisible(x) ((x)->user->flags & FLAGS_INVISIBLE) +#define IsRestricted(x) ((x)->user && \ + (x)->user->flags & FLAGS_RESTRICTED) +#define IsAnOper(x) ((x)->user && \ + (x)->user->flags & (FLAGS_OPER|FLAGS_LOCOP)) +#define IsPerson(x) ((x)->user && IsClient(x)) +#define IsPrivileged(x) (IsServer(x) || IsAnOper(x)) +#define SendWallops(x) ((x)->user->flags & FLAGS_WALLOP) +#define IsUnixSocket(x) ((x)->flags & FLAGS_UNIX) +#define IsListening(x) ((x)->flags & FLAGS_LISTEN) +#define IsLocal(x) (MyConnect(x) && (x)->flags & FLAGS_LOCAL) +#define IsDead(x) ((x)->flags & FLAGS_DEADSOCKET) +#define IsHeld(x) ((x)->flags & FLAGS_HELD) +#define CBurst(x) ((x)->flags & FLAGS_CBURST) + +#define SetOper(x) ((x)->user->flags |= FLAGS_OPER) +#define SetLocOp(x) ((x)->user->flags |= FLAGS_LOCOP) +#define SetInvisible(x) ((x)->user->flags |= FLAGS_INVISIBLE) +#define SetRestricted(x) ((x)->user->flags |= FLAGS_RESTRICTED) +#define SetWallops(x) ((x)->user->flags |= FLAGS_WALLOP) +#define SetUnixSock(x) ((x)->flags |= FLAGS_UNIX) +#define SetDNS(x) ((x)->flags |= FLAGS_DOINGDNS) +#define SetDoneXAuth(x) ((x)->flags |= FLAGS_XAUTHDONE) +#define DoingDNS(x) ((x)->flags & FLAGS_DOINGDNS) +#define DoingAuth(x) ((x)->flags & FLAGS_AUTH) +#define DoingXAuth(x) ((x)->flags & FLAGS_XAUTH) +#define WaitingXAuth(x) ((x)->flags & FLAGS_WXAUTH) +#define DoneXAuth(x) ((x)->flags & FLAGS_XAUTHDONE) +#define NoNewLine(x) ((x)->flags & FLAGS_NONL) + +#define ClearOper(x) ((x)->user->flags &= ~FLAGS_OPER) +#define ClearInvisible(x) ((x)->user->flags &= ~FLAGS_INVISIBLE) +#define ClearRestricted(x) ((x)->user->flags &= ~FLAGS_RESTRICTED) +#define ClearWallops(x) ((x)->user->flags &= ~FLAGS_WALLOP) +#define ClearDNS(x) ((x)->flags &= ~FLAGS_DOINGDNS) +#define ClearAuth(x) ((x)->flags &= ~FLAGS_AUTH) +#define ClearXAuth(x) ((x)->flags &= ~FLAGS_XAUTH) +#define ClearWXAuth(x) ((x)->flags &= ~FLAGS_WXAUTH) + +/* + * defined debugging levels + */ +#define DEBUG_FATAL 0 +#define DEBUG_ERROR 1 /* report_error() and other errors that are found */ +#define DEBUG_READ 2 +#define DEBUG_WRITE 2 +#define DEBUG_NOTICE 3 +#define DEBUG_DNS 4 /* used by all DNS related routines - a *lot* */ +#define DEBUG_INFO 5 /* general usful info */ +#define DEBUG_NUM 6 /* numerics */ +#define DEBUG_SEND 7 /* everything that is sent out */ +#define DEBUG_DEBUG 8 /* anything to do with debugging, ie unimportant :) */ +#define DEBUG_MALLOC 9 /* malloc/free calls */ +#define DEBUG_LIST 10 /* debug list use */ +#define DEBUG_L10 10 +#define DEBUG_L11 11 + +/* + * defines for curses in client + */ +#define DUMMY_TERM 0 +#define CURSES_TERM 1 +#define TERMCAP_TERM 2 + +struct CPing { + u_short port; /* port to send pings to */ + u_long rtt; /* average RTT */ + u_long ping; + u_long seq; /* # sent still in the "window" */ + u_long lseq; /* sequence # of last sent */ + u_long recvd; /* # received still in the "window" */ + u_long lrecvd; /* # received */ +}; + +struct ConfItem { + u_int status; /* If CONF_ILLEGAL, delete when no clients */ + int clients; /* Number of *LOCAL* clients using this */ + struct IN_ADDR ipnum; /* ip number of host field */ + char *host; + char *passwd; + char *name; + int port; + u_int pref; /* preference value */ + struct CPing *ping; + time_t hold; /* Hold action until this time (calendar time) */ +#ifndef VMSP + aClass *class; /* Class of connection */ +#endif + struct ConfItem *next; +}; + +#define CONF_ILLEGAL 0x80000000 +#define CONF_MATCH 0x40000000 +#define CONF_QUARANTINED_SERVER 0x000001 +#define CONF_CLIENT 0x000002 +#define CONF_RCLIENT 0x000004 +#define CONF_CONNECT_SERVER 0x000008 +#define CONF_NOCONNECT_SERVER 0x000010 +#define CONF_ZCONNECT_SERVER 0x000020 +#define CONF_LOCOP 0x000040 +#define CONF_OPERATOR 0x000080 +#define CONF_ME 0x000100 +#define CONF_KILL 0x000200 +#define CONF_ADMIN 0x000400 +#ifdef R_LINES +#define CONF_RESTRICT 0x000800 +#endif +#define CONF_CLASS 0x001000 +#define CONF_SERVICE 0x002000 +#define CONF_LEAF 0x004000 +#define CONF_LISTEN_PORT 0x008000 +#define CONF_HUB 0x010000 +#define CONF_VER 0x020000 +#define CONF_BOUNCE 0x040000 +#define CONF_OTHERKILL 0x080000 +#define CONF_DENY 0x100000 + +#define CONF_OPS (CONF_OPERATOR | CONF_LOCOP) +#define CONF_SERVER_MASK (CONF_CONNECT_SERVER | CONF_NOCONNECT_SERVER |\ + CONF_ZCONNECT_SERVER) +#define CONF_CLIENT_MASK (CONF_CLIENT | CONF_RCLIENT | CONF_SERVICE | CONF_OPS | \ + CONF_SERVER_MASK) + +#define IsIllegal(x) ((x)->status & CONF_ILLEGAL) + +typedef struct { + u_long pi_id; + u_long pi_seq; + struct timeval pi_tv; + aConfItem *pi_cp; +} Ping; + + +#define PING_REPLY 0x01 +#define PING_CPING 0x02 + +#ifdef ZIP_LINKS +/* the minimum amount of data needed to trigger compression */ +# define ZIP_MINIMUM 4096 + +/* the maximum amount of data to be compressed (can actually be a bit more) */ +# define ZIP_MAXIMUM 8192 /* WARNING: *DON'T* CHANGE THIS!!!! */ + +struct Zdata { + z_stream *in; /* input zip stream data */ + z_stream *out; /* output zip stream data */ + char outbuf[ZIP_MAXIMUM]; /* outgoing (unzipped) buffer */ + int outcount; /* size of outbuf content */ +}; +#endif + +struct LineItem +{ + char *line; + struct LineItem *next; +}; + +/* + * Client structures + */ +struct User { + Link *channel; /* chain of channel pointer blocks */ + Link *invited; /* chain of invite pointer blocks */ + Link *uwas; /* chain of whowas pointer blocks */ + char *away; /* pointer to away message */ + time_t last; /* "idle" time */ + int refcnt; /* Number of times this block is referenced + ** from aClient (field user), aServer (field + ** by) and whowas array (field ww_user). + */ + int joined; /* number of channels joined */ + int flags; /* user modes */ + struct Server *servp; + /* + ** In a perfect world the 'server' name + ** should not be needed, a pointer to the + ** client describing the server is enough. + ** Unfortunately, in reality, server may + ** not yet be in links while USER is + ** introduced... --msa + */ + aClient *bcptr; + char username[USERLEN+1]; + char host[HOSTLEN+1]; + char *server; +}; + +struct Server { + anUser *user; /* who activated this connection */ + char *up; /* uplink for this server */ + aConfItem *nline; /* N-line pointer for this server */ + int version; /* version id for local client */ + int snum; + int stok, + ltok; + int refcnt; /* Number of times this block is referenced + ** from anUser (field servp), aService (field + ** servp) and aClient (field serv) + */ + struct Server *nexts, *prevs, *shnext; + aClient *bcptr; + char by[NICKLEN+1]; + char tok[5]; + time_t lastload; /* penalty like counters, see s_serv.c + ** should be in the local part, but.. + */ +}; + +struct Service { + int wants; + int type; + char *server; + aServer *servp; + struct Service *nexts, *prevs; + aClient *bcptr; + char dist[HOSTLEN+1]; +}; + +struct Client { + struct Client *next,*prev, *hnext; + anUser *user; /* ...defined, if this is a User */ + aServer *serv; /* ...defined, if this is a server */ + aService *service; + u_int hashv; /* raw hash value */ + long flags; /* client flags */ + aClient *from; /* == self, if Local Client, *NEVER* NULL! */ + int fd; /* >= 0, for local clients */ + int hopcount; /* number of servers to this 0 = local */ + short status; /* Client type */ + char name[HOSTLEN+1]; /* Unique name of the client, nick or host */ + char username[USERLEN+1]; /* username here now for auth stuff */ + char *info; /* Free form additional client information */ + /* + ** The following fields are allocated only for local clients + ** (directly connected to *this* server with a socket. + ** The first of them *MUST* be the "count"--it is the field + ** to which the allocation is tied to! *Never* refer to + ** these fields, if (from != self). + */ + int count; /* Amount of data in buffer */ + char buffer[BUFSIZE]; /* Incoming message buffer */ +#ifdef ZIP_LINKS + aZdata *zip; /* zip data */ +#endif + short lastsq; /* # of 2k blocks when sendqueued called last*/ + dbuf sendQ; /* Outgoing message queue--if socket full */ + dbuf recvQ; /* Hold for data incoming yet to be parsed */ + long sendM; /* Statistics: protocol messages send */ + long sendK; /* Statistics: total k-bytes send */ + long receiveM; /* Statistics: protocol messages received */ + long receiveK; /* Statistics: total k-bytes received */ + u_short sendB; /* counters to count upto 1-k lots of bytes */ + u_short receiveB; /* sent and received. */ + time_t lasttime; /* last time we received data */ + time_t firsttime; /* time client was created */ + time_t since; /* last time we parsed something */ + aClient *acpt; /* listening client which we accepted from */ + Link *confs; /* Configuration record associated */ + int authfd; /* fd for rfc931 authentication */ + char *auth; + u_short port; /* and the remote port# too :-) */ + struct IN_ADDR ip; /* keep real ip# too */ + struct hostent *hostp; + char sockhost[HOSTLEN+1]; /* This is the host name from the socket + ** and after which the connection was + ** accepted. + */ + char passwd[PASSWDLEN+1]; + char exitc; +}; + +#define CLIENT_LOCAL_SIZE sizeof(aClient) +#define CLIENT_REMOTE_SIZE offsetof(aClient,count) + +/* + * statistics structures + */ +struct stats { + u_int is_cl; /* number of client connections */ + u_int is_sv; /* number of server connections */ + u_int is_ni; /* connection but no idea who it was + * (can be a P: line that has been removed -krys) */ + u_short is_cbs; /* bytes sent to clients */ + u_short is_cbr; /* bytes received to clients */ + u_short is_sbs; /* bytes sent to servers */ + u_short is_sbr; /* bytes received to servers */ + u_long is_cks; /* k-bytes sent to clients */ + u_long is_ckr; /* k-bytes received to clients */ + u_long is_sks; /* k-bytes sent to servers */ + u_long is_skr; /* k-bytes received to servers */ + time_t is_cti; /* time spent connected by clients */ + time_t is_sti; /* time spent connected by servers */ + u_int is_ac; /* connections accepted */ + u_int is_ref; /* accepts refused */ + u_int is_unco; /* unknown commands */ + u_int is_wrdi; /* command going in wrong direction */ + u_int is_unpf; /* unknown prefix */ + u_int is_empt; /* empty message */ + u_int is_num; /* numeric message */ + u_int is_kill; /* number of kills generated on collisions */ + u_int is_fake; /* MODE 'fakes' */ + u_int is_asuc; /* successful auth requests */ + u_int is_abad; /* bad auth requests */ + u_int is_udpok; /* packets recv'd on udp port */ + u_int is_udperr; /* packets recvfrom errors on udp port */ + u_int is_udpdrop; /* packets recv'd but dropped on udp port */ + u_int is_loc; /* local connections made */ + u_int is_nosrv; /* user without server */ + u_long is_wwcnt; /* number of nicks overwritten in whowas[] */ + u_long is_wwt; /* sum of elapsed time on when overwriting whowas[]*/ + u_long is_wwMt; /* max elapsed time on when overwriting whowas[] */ + u_long is_wwmt; /* min elapsed time on when overwriting whowas[] */ + u_long is_lkcnt; /* number of nicks overwritten in locked[] */ + u_long is_lkt; /* sum of elapsed time on when overwriting locked[]*/ + u_long is_lkMt; /* max elapsed time on when overwriting locked[] */ + u_long is_lkmt; /* min elapsed time on when overwriting locked[] */ + u_int is_ckl; /* calls to check_link() */ + u_int is_cklQ; /* rejected: SendQ too high */ + u_int is_ckly; /* rejected: link too young */ + u_int is_cklno; /* rejected: "flood" */ + u_int is_cklok; /* accepted */ + u_int is_cklq; /* accepted early */ +}; + +/* mode structure for channels */ + +struct SMode { + u_int mode; + int limit; + char key[KEYLEN+1]; +}; + +/* Message table structure */ + +struct Message { + char *cmd; + int (* func)(); + int parameters; + u_int flags; + /* bit 0 set means that this command is allowed to be used + * only on the average of once per 2 seconds -SRB */ + u_int count; /* total count */ + u_int rcount; /* remote count */ + u_long bytes; +}; + +#define MSG_LAG 0x0001 +#define MSG_NOU 0x0002 /* Not available to users */ +#define MSG_SVC 0x0004 /* Services only */ +#define MSG_NOUK 0x0008 /* Not available to unknowns */ +#define MSG_REG 0x0010 /* Must be registered */ +#define MSG_REGU 0x0020 /* Must be a registered user */ +/*#define MSG_PP 0x0040*/ +/*#define MSG_FRZ 0x0080*/ +#define MSG_OP 0x0100 /* opers only */ +#define MSG_LOP 0x0200 /* locops only */ + +/* fd array structure */ + +struct fdarray { + int fd[MAXCONNECTIONS]; + int highest; +}; + +/* general link structure used for chains */ + +struct SLink { + struct SLink *next; + union { + aClient *cptr; + aChannel *chptr; + aConfItem *aconf; + char *cp; + int i; + } value; + int flags; +}; + +/* channel structure */ + +struct Channel { + struct Channel *nextch, *prevch, *hnextch; + u_int hashv; /* raw hash value */ + Mode mode; + char topic[TOPICLEN+1]; + int users; /* current membership total */ + Link *members; /* channel members */ + Link *invites; /* outstanding invitations */ + Link *mlist; /* list of extended modes: +b/+e/+I */ + Link *clist; /* list of connections which are members */ + time_t history; /* channel history (aka channel delay) */ + time_t reop; /* server reop stamp for !channels */ + char chname[1]; +}; + +/* +** Channel Related macros follow +*/ + +/* Channel related flags */ + +#define CHFL_UNIQOP 0x0001 /* Channel creator */ +#define CHFL_CHANOP 0x0002 /* Channel operator */ +#define CHFL_VOICE 0x0004 /* the power to speak */ +#define CHFL_BAN 0x0008 /* ban channel flag */ +#define CHFL_EXCEPTION 0x0010 /* exception channel flag */ +#define CHFL_INVITE 0x0020 /* invite channel flag */ + +/* Channel Visibility macros */ + +#define MODE_UNIQOP CHFL_UNIQOP +#define MODE_CHANOP CHFL_CHANOP +#define MODE_VOICE CHFL_VOICE +#define MODE_PRIVATE 0x0008 +#define MODE_SECRET 0x0010 +#define MODE_MODERATED 0x0020 +#define MODE_TOPICLIMIT 0x0040 +#define MODE_INVITEONLY 0x0080 +#define MODE_NOPRIVMSGS 0x0100 +#define MODE_KEY 0x0200 +#define MODE_BAN 0x0400 +#define MODE_LIMIT 0x0800 +#define MODE_ANONYMOUS 0x1000 +#define MODE_QUIET 0x2000 +#define MODE_EXCEPTION 0x4000 +#define MODE_INVITE 0x8000 +#define MODE_REOP 0x10000 +#define MODE_FLAGS 0x1ffff +/* + * mode flags which take another parameter (With PARAmeterS) + */ +#define MODE_WPARAS (MODE_UNIQOP|MODE_CHANOP|MODE_VOICE|MODE_BAN|MODE_KEY\ + |MODE_LIMIT|MODE_INVITE|MODE_EXCEPTION) +/* + * Undefined here, these are used in conjunction with the above modes in + * the source. +#define MODE_DEL 0x40000000 +#define MODE_ADD 0x80000000 + */ + +#define HoldChannel(x) (!(x)) +/* name invisible */ +#define SecretChannel(x) ((x) && ((x)->mode.mode & MODE_SECRET)) +/* channel not shown but names are */ +#define HiddenChannel(x) ((x) && ((x)->mode.mode & MODE_PRIVATE)) +/* channel visible */ +#define ShowChannel(v,c) (PubChannel(c) || IsMember((v),(c))) +#define IsAnonymous(c) ((c) && ((c)->mode.mode & MODE_ANONYMOUS)) +#define PubChannel(x) ((!x) || ((x)->mode.mode &\ + (MODE_PRIVATE | MODE_SECRET)) == 0) + +/* +#define IsMember(u, c) (assert(*(c)->chname != '\0'), find_user_link((c)->members, u) ? 1 : 0) +#define IsMember(u, c) (find_user_link((c)->members, u) ? 1 : 0) +*/ +#define IsMember(u, c) (u && (u)->user && \ + find_channel_link((u)->user->channel, c) ? 1 : 0) +#ifdef CLIENT_COMPILE +# define IsChannelName(n) ((n) && (*(n) == '#' || *(n) == '&' ||\ + *(n) == '+' || *(n) == '!')) +#else +# define IsChannelName(n) ((n) && (*(n) == '#' || *(n) == '&' ||\ + *(n) == '+' || \ + (*(n) == '!' && cid_ok(n)))) +#endif +#define IsQuiet(x) ((x)->mode.mode & MODE_QUIET) +#define UseModes(n) ((n) && (*(n) == '#' || *(n) == '&' || \ + *(n) == '!')) + +/* Misc macros */ + +#define BadPtr(x) (!(x) || (*(x) == '\0')) + +#define isvalid(c) (((c) >= 'A' && (c) <= '~') || isdigit(c) || (c) == '-') + +#define MyConnect(x) ((x)->fd >= 0) +#define MyClient(x) (MyConnect(x) && IsClient(x)) +#define MyPerson(x) (MyConnect(x) && IsPerson(x)) +#define MyOper(x) (MyConnect(x) && IsOper(x)) +#define MyService(x) (MyConnect(x) && IsService(x)) +#define ME me.name + +#define GotDependantClient(x) (x->prev && \ + ((IsRegisteredUser(x->prev) && \ + x->prev->user->servp == x->serv) || \ + (IsService(x->prev) && \ + x->prev->service->servp == x->serv))) + +typedef struct { + u_long is_user[2]; /* users, non[0] invis and invis[1] */ + u_long is_serv; /* servers */ + u_long is_service; /* services */ + u_long is_chan; /* channels */ + u_long is_chanmem; + u_long is_chanusers; /* channels users */ + u_long is_hchan; /* channels in history */ + u_long is_hchanmem; + u_long is_cchan; /* channels in cache */ + u_long is_cchanmem; + u_long is_away; /* away sets */ + u_long is_awaymem; + u_long is_oper; /* opers */ + u_long is_bans; /* bans */ + u_long is_banmem; + u_long is_invite; /* invites */ + u_long is_class; /* classes */ + u_long is_conf; /* conf lines */ + u_long is_confmem; + u_long is_conflink; /* attached conf lines */ + u_long is_myclnt; /* local clients */ + u_long is_myserv; /* local servers */ + u_long is_myservice; /* local services */ + u_long is_unknown; /* unknown (local) connections */ + u_long is_wwusers; /* users kept for whowas[] */ + u_long is_wwaways; /* aways in users in whowas[] */ + u_long is_wwawaysmem; + u_long is_wwuwas; /* uwas links */ + u_long is_localc; /* local items (serv+service+client+..) */ + u_long is_remc; /* remote clients */ + u_long is_users; /* user structs */ + u_long is_useri; /* user invites */ + u_long is_userc; /* user links to channels */ + u_long is_auth; /* OTHER ident reply block */ + u_long is_authmem; + u_int is_dbuf; /* number of dbuf allocated (originally) */ + u_int is_dbufnow; /* number of dbuf allocated */ + u_int is_dbufuse; /* number of dbuf in use */ + u_int is_dbufmin; /* min number of dbuf in use */ + u_int is_dbufmax; /* max number of dbuf in use */ + u_int is_dbufmore; /* how many times we increased the bufferpool*/ +} istat_t; + +/* String manipulation macros */ + +/* strncopynt --> strncpyzt to avoid confusion, sematics changed + N must be now the number of bytes in the array --msa */ +#define strncpyzt(x, y, N) do{(void)strncpy(x,y,N);x[N-1]='\0';}while(0) +#define StrEq(x,y) (!strcmp((x),(y))) + +/* used in SetMode() in channel.c and m_umode() in s_msg.c */ + +#define MODE_NULL 0 +#define MODE_ADD 0x40000000 +#define MODE_DEL 0x20000000 + +/* return values for hunt_server() */ + +#define HUNTED_NOSUCH (-1) /* if the hunted server is not found */ +#define HUNTED_ISME 0 /* if this server should execute the command */ +#define HUNTED_PASS 1 /* if message passed onwards successfully */ + +/* used when sending to #mask or $mask */ + +#define MATCH_SERVER 1 +#define MATCH_HOST 2 + +/* used for sendto_serv */ + +#define SV_OLD 0x0000 +#define SV_29 0x0001 /* useless, but preserved for coherence */ +#define SV_NJOIN 0x0002 /* server understands the NJOIN command */ +#define SV_NMODE 0x0004 /* server knows new MODEs (+e/+I) */ +#define SV_NCHAN 0x0008 /* server knows new channels -????name */ + /* ! SV_NJOIN implies ! SV_NCHAN */ +#define SV_2_10 (SV_29|SV_NJOIN|SV_NMODE|SV_NCHAN) +#define SV_OLDSQUIT 0x1000 /* server uses OLD SQUIT logic */ + +/* used for sendto_flag */ + +typedef struct { + int svc_chan; + char *svc_chname; + struct Channel *svc_ptr; +} SChan; + +#define SCH_ERROR 1 +#define SCH_NOTICE 2 +#define SCH_KILL 3 +#define SCH_CHAN 4 +#define SCH_NUM 5 +#define SCH_SERVER 6 +#define SCH_HASH 7 +#define SCH_LOCAL 8 +#define SCH_SERVICE 9 +#define SCH_DEBUG 10 +#define SCH_AUTH 11 +#define SCH_MAX 11 + +/* used for async dns values */ + +#define ASYNC_NONE (-1) +#define ASYNC_CLIENT 0 +#define ASYNC_CONNECT 1 +#define ASYNC_CONF 2 +#define ASYNC_SERVER 3 + +/* Client exit codes for log file */ +#define EXITC_UNDEF '-' /* unregistered client */ +#define EXITC_REG '0' /* normal exit */ +#define EXITC_DIE 'd' /* server died */ +#define EXITC_DEAD 'D' /* socket died */ +#define EXITC_ERROR 'E' /* socket error */ +#define EXITC_FLOOD 'F' /* client flooding */ +#define EXITC_KLINE 'k' /* K-lined */ +#define EXITC_KILL 'K' /* KILLed */ +#define EXITC_MBUF 'M' /* mem alloc error */ +#define EXITC_PING 'P' /* ping timeout */ +#define EXITC_SENDQ 'Q' /* send queue exceeded */ +#define EXITC_RLINE 'r' /* R-lined */ +#define EXITC_REF 'R' /* Refused */ +#define EXITC_AREF 'U' /* Unauthorized by iauth */ +#define EXITC_AREFQ 'u' /* Unauthorized by iauth, be quiet */ +#define EXITC_AUTHFAIL 'A' /* Authentication failure (iauth problem) */ +#define EXITC_AUTHTOUT 'a' /* Authentication time out */ + +/* eXternal authentication slave OPTions */ +#define XOPT_REQUIRED 0x01 /* require authentication be done by iauth */ +#define XOPT_NOTIMEOUT 0x02 /* disallow iauth time outs */ +#define XOPT_EXTWAIT 0x10 /* extend registration ping timeout */ +#define XOPT_EARLYPARSE 0x20 /* allow early parsing and send USER/PASS + information to iauth */ + +/* misc defines */ + +#define FLUSH_BUFFER -2 +#define UTMP "/etc/utmp" +#define COMMA "," + +#define SAP struct SOCKADDR * + +/* IRC client structures */ + +#ifdef CLIENT_COMPILE +typedef struct Ignore { + char user[NICKLEN+1]; + char from[USERLEN+HOSTLEN+2]; + int flags; + struct Ignore *next; +} anIgnore; + +#define IGNORE_PRIVATE 1 +#define IGNORE_PUBLIC 2 +#define IGNORE_TOTAL 3 + +#define HEADERLEN 200 + +#endif /* CLIENT_COMPILE */ diff --git a/common/support.c b/common/support.c new file mode 100644 index 0000000..f90e6b0 --- /dev/null +++ b/common/support.c @@ -0,0 +1,1190 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/support.c + * Copyright (C) 1990, 1991 Armin Gruner + * + * 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 rcsid[] = "@(#)$Id: support.c,v 1.17 1999/06/25 15:36:16 kalt Exp $"; +#endif + +#include "os.h" +#ifndef CLIENT_COMPILE +# include "s_defines.h" +#else +# include "c_defines.h" +#endif +#define SUPPORT_C +#ifndef CLIENT_COMPILE +# include "s_externs.h" +#else +# include "c_externs.h" +#endif +#undef SUPPORT_C + +char *mystrdup(s) +char *s; +{ + /* Portable strdup(), contributed by mrg, thanks! -roy */ + + char *t; + + t = (char *) MyMalloc(strlen(s) + 1); + if (t) + return ((char *)strcpy(t, s)); + return NULL; +} + +#if ! HAVE_STRTOKEN +/* +** strtoken.c -- walk through a string of tokens, using a set +** of separators +** argv 9/90 +*/ + +char *strtoken(save, str, fs) +char **save; +char *str, *fs; +{ + char *pos = *save; /* keep last position across calls */ + Reg char *tmp; + + if (str) + pos = str; /* new string scan */ + + while (pos && *pos && index(fs, *pos) != NULL) + pos++; /* skip leading separators */ + + if (!pos || !*pos) + return (pos = *save = NULL); /* string contains only sep's */ + + tmp = pos; /* now, keep position of the token */ + + while (*pos && index(fs, *pos) == NULL) + pos++; /* skip content of the token */ + + if (*pos) + *pos++ = '\0'; /* remove first sep after the token */ + else + pos = NULL; /* end of string */ + + *save = pos; + return(tmp); +} +#endif /* HAVE_STRTOKEN */ + +#if ! HAVE_STRTOK +/* +** NOT encouraged to use! +*/ + +char *strtok(str, fs) +char *str, *fs; +{ + static char *pos; + + return strtoken(&pos, str, fs); +} + +#endif /* HAVE_STRTOK */ + +#if ! HAVE_STRERROR +/* +** strerror - return an appropriate system error string to a given errno +** +** argv 11/90 +*/ + +char *strerror(err_no) +int err_no; +{ + static char buff[40]; + char *errp; + + errp = (err_no > sys_nerr ? (char *)NULL : sys_errlist[err_no]); + + if (errp == (char *)NULL) + { + errp = buff; + SPRINTF(errp, "Unknown Error %d", err_no); + } + return errp; +} + +#endif /* HAVE_STRERROR */ + +/** + ** 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]; + Reg char *p; + + (void)strcpy(buf, ctime(&value)); + if ((p = (char *)index(buf, '\n')) != NULL) + *p = '\0'; + + return buf; +} + +/* +** mybasename() +** removes path from a filename +*/ +char * +mybasename(path) +char *path; +{ + char *lastslash; + + if (lastslash = rindex(path, '/')) + return lastslash + 1; + return path; +} + +#ifdef INET6 +/* + * inetntop: return the : notation of a given IPv6 internet number. + * make sure the compressed representation (rfc 1884) isn't used. + */ +char *inetntop(af, in, out, the_size) +int af; +const void *in; +char *out; +size_t the_size; +{ + static char local_dummy[MYDUMMY_SIZE]; + + inet_ntop(af, in, local_dummy, the_size); + if (strstr(local_dummy, "::")) + { + char cnt = 0, *cp = local_dummy, *op = out; + + while (*cp) + { + if (*cp == ':') + cnt += 1; + if (*cp++ == '.') + { + cnt += 1; + break; + } + } + cp = local_dummy; + while (*cp) + { + *op++ = *cp++; + if (*(cp-1) == ':' && *cp == ':') + { + if ((cp-1) == local_dummy) + { + op--; + *op++ = '0'; + *op++ = ':'; + } + + *op++ = '0'; + while (cnt++ < 7) + { + *op++ = ':'; + *op++ = '0'; + } + } + } + if (*(op-1)==':') *op++ = '0'; + *op = '\0'; + Debug((DEBUG_DNS,"Expanding `%s' -> `%s'", local_dummy, + out)); + } + else + bcopy(local_dummy, out, 64); + return out; +} +#endif + +#if ! HAVE_INET_NTOA +/* +** inetntoa -- changed name to remove collision possibility and +** so behaviour is gaurunteed to take a pointer arg. +** -avalon 23/11/92 +** inet_ntoa -- returned the dotted notation of a given +** internet number (some ULTRIX don't have this) +** argv 11/90). +** inet_ntoa -- its broken on some Ultrix/Dynix too. -avalon +*/ + +char *inetntoa(in) +char *in; +{ + static char buf[16]; + Reg u_char *s = (u_char *)in; + Reg int a,b,c,d; + + a = (int)*s++; + b = (int)*s++; + c = (int)*s++; + d = (int)*s; + (void)sprintf(buf, "%d.%d.%d.%d", a,b,c,d ); + + return buf; +} +#endif + +#if ! HAVE_INET_NETOF +/* +** inet_netof -- return the net portion of an internet number +** argv 11/90 +*/ +int inetnetof(in) +struct in_addr in; +{ + register u_long i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT); + else if (IN_CLASSB(i)) + return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT); + else + return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT); +} +#endif + +#if ! HAVE_INET_ADDR +# ifndef INADDR_NONE +# define INADDR_NONE 0xffffffff +# endif +/* + * Ascii internet address interpretation routine. + * The value returned is in network order. + */ +u_long +inetaddr(cp) + register const char *cp; +{ + struct in_addr val; + + if (inetaton(cp, &val)) + return (val.s_addr); + return (INADDR_NONE); +} +#endif + +#if ! HAVE_INET_ATON +/* + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inetaton(cp, addr) + register const char *cp; + struct in_addr *addr; +{ + register u_long val; + register int base, n; + register char c; + u_int parts[4]; + register u_int *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, isdigit=decimal. + */ + if (!isdigit(c)) + return (0); + val = 0; base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') + base = 16, c = *++cp; + else + base = 8; + } + for (;;) { + if (isascii(c) && isdigit(c)) { + val = (val * base) + (c - '0'); + c = *++cp; + } else if (base == 16 && isascii(c) && isxdigit(c)) { + val = (val << 4) | + (c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) + return (0); + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && (!isascii(c) || !isspace(c))) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr) + addr->s_addr = htonl(val); + return (1); +} +#endif + +#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) +void dumpcore(msg, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) +char *msg, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10, *p11; +{ + static time_t lastd = 0; + static int dumps = 0; + char corename[12]; + time_t now; + int p; + + now = time(NULL); + + if (!lastd) + lastd = now; + else if (now - lastd < 60 && dumps > 2) + (void)s_die(0); + if (now - lastd > 60) + { + lastd = now; + dumps = 1; + } + else + dumps++; + p = getpid(); + if (fork()>0) { + kill(p, 3); + kill(p, 9); + } + write_pidfile(); + SPRINTF(corename, "core.%d", p); + (void)rename("core", corename); + Debug((DEBUG_FATAL, "Dumped core : core.%d", p)); + sendto_flag(SCH_ERROR, "Dumped core : core.%d", p); + Debug((DEBUG_FATAL, msg, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10,p11)); + sendto_flag(SCH_ERROR, msg, p1, p2, p3, p4, p5, p6, p7, p8,p9,p10,p11); + (void)s_die(0); +} +#endif + +#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) && defined(DO_DEBUG_MALLOC) + +static char *marray[100000]; +static int mindex = 0; + +#define SZ_EX (sizeof(char *) + sizeof(size_t) + 4) +#define SZ_CHST (sizeof(char *) + sizeof(size_t)) +#define SZ_CH (sizeof(char *)) +#define SZ_ST (sizeof(size_t)) + +char *MyMalloc(x) +size_t x; +{ + register int i; + register char **s; + char *ret; + + ret = (char *)malloc(x + (size_t)SZ_EX); + + if (!ret) + { +# ifndef CLIENT_COMPILE + outofmemory(); +# else + perror("malloc"); + exit(-1); +# endif + } + bzero(ret, (int)x + SZ_EX); + bcopy((char *)&ret, ret, SZ_CH); + bcopy((char *)&x, ret + SZ_ST, SZ_ST); + bcopy("VAVA", ret + SZ_CHST + (int)x, 4); + Debug((DEBUG_MALLOC, "MyMalloc(%ld) = %#x", x, ret + SZ_CHST)); + for(i = 0, s = marray; *s && i < mindex; i++, s++) + ; + if (i < 100000) + { + *s = ret; + if (i == mindex) + mindex++; + } + return ret + SZ_CHST; + } + +char *MyRealloc(x, y) +char *x; +size_t y; + { + register int l; + register char **s; + char *ret, *cp; + size_t i; + int k; + + if (x != NULL) + { + x -= SZ_CHST; + bcopy(x, (char *)&cp, SZ_CH); + bcopy(x + SZ_CH, (char *)&i, SZ_ST); + bcopy(x + (int)i + SZ_CHST, (char *)&k, 4); + if (bcmp((char *)&k, "VAVA", 4) || (x != cp)) + dumpcore("MyRealloc %#x %d %d %#x %#x", x, y, i, cp, k); + } + ret = (char *)realloc(x, y + (size_t)SZ_EX); + + if (!ret) + { +# ifndef CLIENT_COMPILE + outofmemory(); +# else + perror("realloc"); + exit(-1); +# endif + } + bcopy((char *)&ret, ret, SZ_CH); + bcopy((char *)&y, ret + SZ_CH, SZ_ST); + bcopy("VAVA", ret + SZ_CHST + (int)y, 4); + Debug((DEBUG_NOTICE, "MyRealloc(%#x,%ld) = %#x", x, y, ret + SZ_CHST)); + for(l = 0, s = marray; *s != x && l < mindex; l++, s++) + ; + if (l < mindex) + *s = NULL; + else if (l == mindex) + Debug((DEBUG_MALLOC, "%#x !found", x)); + for(l = 0, s = marray; *s && l < mindex; l++,s++) + ; + if (l < 100000) + { + *s = ret; + if (l == mindex) + mindex++; + } + return ret + SZ_CHST; + } + +void MyFree(x) +char *x; +{ + size_t i; + char *j; + u_char k[4]; + register int l; + register char **s; + + if (!x) + return; + x -= SZ_CHST; + + bcopy(x, (char *)&j, SZ_CH); + bcopy(x + SZ_CH, (char *)&i, SZ_ST); + bcopy(x + SZ_CHST + (int)i, (char *)k, 4); + + if (bcmp((char *)k, "VAVA", 4) || (j != x)) + dumpcore("MyFree %#x %ld %#x %#x", x, i, j, + (k[3]<<24) | (k[2]<<16) | (k[1]<<8) | k[0]); + + Debug((DEBUG_MALLOC, "MyFree(%#x)",x + SZ_CHST)); +#undef free + (void)free(x); +#define free(x) MyFree(x) + + for (l = 0, s = marray; *s != x && l < mindex; l++, s++) + ; + if (l < mindex) + *s = NULL; + else if (l == mindex) + Debug((DEBUG_MALLOC, "%#x !found", x)); +} +#else +char *MyMalloc(x) +size_t x; +{ + char *ret = (char *)malloc(x); + + if (!ret) + { +# ifndef CLIENT_COMPILE + outofmemory(); +# else + perror("malloc"); + exit(-1); +# endif + } + return ret; +} + +char *MyRealloc(x, y) +char *x; +size_t y; + { + char *ret = (char *)realloc(x, y); + + if (!ret) + { +# ifndef CLIENT_COMPILE + outofmemory(); +# else + perror("realloc"); + exit(-1); +# endif + } + return ret; + } +#endif + + +/* +** 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 (tail > head) + { + n = MIN(tail - head, 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; +} + +#if ! USE_STDARG +/* + * By Mika + */ +int irc_sprintf(outp, formp, + i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11) +char *outp; +char *formp; +char *i0, *i1, *i2, *i3, *i4, *i5, *i6, *i7, *i8, *i9, *i10, *i11; +{ + /* rp for Reading, wp for Writing, fp for the Format string */ + /* we could hack this if we know the format of the stack */ + char *inp[12]; + Reg char *rp, *fp, *wp, **pp = inp; + Reg char f; + Reg long myi; + int i; + + inp[0] = i0; + inp[1] = i1; + inp[2] = i2; + inp[3] = i3; + inp[4] = i4; + inp[5] = i5; + inp[6] = i6; + inp[7] = i7; + inp[8] = i8; + inp[9] = i9; + inp[10] = i10; + inp[11] = i11; + + /* + * just scan the format string and puke out whatever is necessary + * along the way... + */ + + for (i = 0, wp = outp, fp = formp; (f = *fp++); ) + if (f != '%') + *wp++ = f; + else + switch (*fp++) + { + /* put the most common case at the top */ + /* copy a string */ + case 's': + for (rp = *pp++; (*wp++ = *rp++); ) + ; + --wp; + /* get the next parameter */ + break; + /* + * reject range for params to this mean that the + * param must be within 100-999 and this +ve int + */ + case 'd': + case 'u': + myi = (long)*pp++; + if ((myi < 100) || (myi > 999)) + { + (void)sprintf(outp, formp, i0, i1, i2, + i3, i4, i5, i6, i7, i8, + i9, i10, i11); + return -1; + } + + *wp++ = (char)(myi / 100 + (int) '0'); + myi %= 100; + *wp++ = (char)(myi / 10 + (int) '0'); + myi %= 10; + *wp++ = (char)(myi + (int) '0'); + break; + case 'c': + *wp++ = (char)(long)*pp++; + break; + case '%': + *wp++ = '%'; + break; + default : + (void)sprintf(outp, formp, i0, i1, i2, i3, i4, + i5, i6, i7, i8, i9, i10, i11); + return -1; + } + *wp = '\0'; + return wp - outp; +} +#endif + +/* + * Make 'readable' version string. + */ +char *make_version() +{ + int ve, re, mi, dv, pl; + char ver[15]; + + sscanf(PATCHLEVEL, "%2d%2d%2d%2d%2d", &ve, &re, &mi, &dv, &pl); + /* version & revision */ + sprintf(ver, "%d.%d", ve, (mi == 99) ? re + 1 : re); + if (mi == 99) mi = -1; + /* minor revision */ + sprintf(ver + strlen(ver), ".%d", dv ? mi+1 : mi); + if (dv) /* alpha/beta, note how visual patchlevel is raised above */ + sprintf(ver + strlen(ver), "%c%d", DEVLEVEL, dv); + if (pl) /* patchlevel */ + sprintf(ver + strlen(ver), "p%d", pl); + return mystrdup(ver); +} + +#ifndef HAVE_TRUNCATE +/* truncate: set a file to a specified length + * I don't know of any UNIX that doesn't have truncate, but CYGWIN32 beta18 + * doesn't have it. -krys + * Replacement version from Dave Miller. + */ +int truncate(path, length) +const char *path; +off_t length; +{ + int fd, res; + fd = open(path, O_WRONLY); + if (fd == -1) + return -1; + res = ftruncate(fd, length); + close(fd); + return res; +} +#endif /* HAVE_TRUNCATE */ + +#if SOLARIS_2_3 +/* + * On Solaris 2.3 (SunOS 5.3) systems, gethostbyname() has a bug, it always + * returns null in h->aliases. Workaround: use the undocumented + * _switch_gethostbyname_r(...). + */ +#define HBUFSIZE 4096 + +struct hostent *solaris_gethostbyname(name) + const char *name; +{ + static struct hostent hp; + static char buf[HBUFSIZE]; + + return _switch_gethostbyname_r(name, &hp, buf, sizeof(buf), &h_errno); +} +#endif /* SOLARIS_2_3 */ + +#if HAVE_MEMCMP && MEMCMP_BROKEN +/* + * Some OS may have a memcmp that is not 8-bit clean. + * + * Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc. + * Contributed by Torbjorn Granlund (tege@sics.se). + * + * NOTE: The canonical source of this part of the file is maintained with the + * GNU C Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. + */ + +/* Type to use for aligned memory operations. + This should normally be the biggest type supported by a single load + and store. Must be an unsigned type. */ +#define op_t unsigned long int +#define OPSIZ (sizeof(op_t)) + +/* Threshold value for when to enter the unrolled loops. */ +#define OP_T_THRES 16 + +/* Type to use for unaligned operations. */ +typedef unsigned char byte; + +#if ! WORDS_BIGENDIAN +#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2))) +#else +#define MERGE(w0, sh_1, w1, sh_2) (((w0) << (sh_1)) | ((w1) >> (sh_2))) +#endif + +#if WORDS_BIGENDIAN +#define CMP_LT_OR_GT(a, b) ((a) > (b) ? 1 : -1) +#else +#define CMP_LT_OR_GT(a, b) memcmp_bytes ((a), (b)) +#endif + +/* BE VERY CAREFUL IF YOU CHANGE THIS CODE! */ + +/* The strategy of this memcmp is: + + 1. Compare bytes until one of the block pointers is aligned. + + 2. Compare using memcmp_common_alignment or + memcmp_not_common_alignment, regarding the alignment of the other + block after the initial byte operations. The maximum number of + full words (of type op_t) are compared in this way. + + 3. Compare the few remaining bytes. */ + +#if ! WORDS_BIGENDIAN +/* memcmp_bytes -- Compare A and B bytewise in the byte order of the machine. + A and B are known to be different. + This is needed only on little-endian machines. */ +#ifdef __GNUC__ +__inline +#endif +static int +memcmp_bytes (a, b) + op_t a, b; +{ + long int srcp1 = (long int) &a; + long int srcp2 = (long int) &b; + op_t a0, b0; + + do + { + a0 = ((byte *) srcp1)[0]; + b0 = ((byte *) srcp2)[0]; + srcp1 += 1; + srcp2 += 1; + } + while (a0 == b0); + return a0 - b0; +} +#endif + +/* memcmp_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN `op_t' + objects (not LEN bytes!). Both SRCP1 and SRCP2 should be aligned for + memory operations on `op_t's. */ +#ifdef __GNUC__ +__inline +#endif +static int +memcmp_common_alignment (srcp1, srcp2, len) + long int srcp1; + long int srcp2; + size_t len; +{ + op_t a0, a1; + op_t b0, b1; + + switch (len % 4) + { + case 2: + a0 = ((op_t *) srcp1)[0]; + b0 = ((op_t *) srcp2)[0]; + srcp1 -= 2 * OPSIZ; + srcp2 -= 2 * OPSIZ; + len += 2; + goto do1; + case 3: + a1 = ((op_t *) srcp1)[0]; + b1 = ((op_t *) srcp2)[0]; + srcp1 -= OPSIZ; + srcp2 -= OPSIZ; + len += 1; + goto do2; + case 0: + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + return 0; + a0 = ((op_t *) srcp1)[0]; + b0 = ((op_t *) srcp2)[0]; + goto do3; + case 1: + a1 = ((op_t *) srcp1)[0]; + b1 = ((op_t *) srcp2)[0]; + srcp1 += OPSIZ; + srcp2 += OPSIZ; + len -= 1; + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + goto do0; + /* Fall through. */ + } + + do + { + a0 = ((op_t *) srcp1)[0]; + b0 = ((op_t *) srcp2)[0]; + if (a1 != b1) + return CMP_LT_OR_GT (a1, b1); + + do3: + a1 = ((op_t *) srcp1)[1]; + b1 = ((op_t *) srcp2)[1]; + if (a0 != b0) + return CMP_LT_OR_GT (a0, b0); + + do2: + a0 = ((op_t *) srcp1)[2]; + b0 = ((op_t *) srcp2)[2]; + if (a1 != b1) + return CMP_LT_OR_GT (a1, b1); + + do1: + a1 = ((op_t *) srcp1)[3]; + b1 = ((op_t *) srcp2)[3]; + if (a0 != b0) + return CMP_LT_OR_GT (a0, b0); + + srcp1 += 4 * OPSIZ; + srcp2 += 4 * OPSIZ; + len -= 4; + } + while (len != 0); + + /* This is the right position for do0. Please don't move + it into the loop. */ + do0: + if (a1 != b1) + return CMP_LT_OR_GT (a1, b1); + return 0; +} + +/* memcmp_not_common_alignment -- Compare blocks at SRCP1 and SRCP2 with LEN + `op_t' objects (not LEN bytes!). SRCP2 should be aligned for memory + operations on `op_t', but SRCP1 *should be unaligned*. */ +#ifdef __GNUC__ +__inline +#endif +static int +memcmp_not_common_alignment (srcp1, srcp2, len) + long int srcp1; + long int srcp2; + size_t len; +{ + op_t a0, a1, a2, a3; + op_t b0, b1, b2, b3; + op_t x; + int shl, shr; + + /* Calculate how to shift a word read at the memory operation + aligned srcp1 to make it aligned for comparison. */ + + shl = 8 * (srcp1 % OPSIZ); + shr = 8 * OPSIZ - shl; + + /* Make SRCP1 aligned by rounding it down to the beginning of the `op_t' + it points in the middle of. */ + srcp1 &= -OPSIZ; + + switch (len % 4) + { + case 2: + a1 = ((op_t *) srcp1)[0]; + a2 = ((op_t *) srcp1)[1]; + b2 = ((op_t *) srcp2)[0]; + srcp1 -= 1 * OPSIZ; + srcp2 -= 2 * OPSIZ; + len += 2; + goto do1; + case 3: + a0 = ((op_t *) srcp1)[0]; + a1 = ((op_t *) srcp1)[1]; + b1 = ((op_t *) srcp2)[0]; + srcp2 -= 1 * OPSIZ; + len += 1; + goto do2; + case 0: + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + return 0; + a3 = ((op_t *) srcp1)[0]; + a0 = ((op_t *) srcp1)[1]; + b0 = ((op_t *) srcp2)[0]; + srcp1 += 1 * OPSIZ; + goto do3; + case 1: + a2 = ((op_t *) srcp1)[0]; + a3 = ((op_t *) srcp1)[1]; + b3 = ((op_t *) srcp2)[0]; + srcp1 += 2 * OPSIZ; + srcp2 += 1 * OPSIZ; + len -= 1; + if (OP_T_THRES <= 3 * OPSIZ && len == 0) + goto do0; + /* Fall through. */ + } + + do + { + a0 = ((op_t *) srcp1)[0]; + b0 = ((op_t *) srcp2)[0]; + x = MERGE(a2, shl, a3, shr); + if (x != b3) + return CMP_LT_OR_GT (x, b3); + + do3: + a1 = ((op_t *) srcp1)[1]; + b1 = ((op_t *) srcp2)[1]; + x = MERGE(a3, shl, a0, shr); + if (x != b0) + return CMP_LT_OR_GT (x, b0); + + do2: + a2 = ((op_t *) srcp1)[2]; + b2 = ((op_t *) srcp2)[2]; + x = MERGE(a0, shl, a1, shr); + if (x != b1) + return CMP_LT_OR_GT (x, b1); + + do1: + a3 = ((op_t *) srcp1)[3]; + b3 = ((op_t *) srcp2)[3]; + x = MERGE(a1, shl, a2, shr); + if (x != b2) + return CMP_LT_OR_GT (x, b2); + + srcp1 += 4 * OPSIZ; + srcp2 += 4 * OPSIZ; + len -= 4; + } + while (len != 0); + + /* This is the right position for do0. Please don't move + it into the loop. */ + do0: + x = MERGE(a2, shl, a3, shr); + if (x != b3) + return CMP_LT_OR_GT (x, b3); + return 0; +} + +int +irc_memcmp (s1, s2, len) + const __ptr_t s1; + const __ptr_t s2; + size_t len; +{ + op_t a0; + op_t b0; + long int srcp1 = (long int) s1; + long int srcp2 = (long int) s2; + op_t res; + + if (len >= OP_T_THRES) + { + /* There are at least some bytes to compare. No need to test + for LEN == 0 in this alignment loop. */ + while (srcp2 % OPSIZ != 0) + { + a0 = ((byte *) srcp1)[0]; + b0 = ((byte *) srcp2)[0]; + srcp1 += 1; + srcp2 += 1; + res = a0 - b0; + if (res != 0) + return res; + len -= 1; + } + + /* SRCP2 is now aligned for memory operations on `op_t'. + SRCP1 alignment determines if we can do a simple, + aligned compare or need to shuffle bits. */ + + if (srcp1 % OPSIZ == 0) + res = memcmp_common_alignment (srcp1, srcp2, len / OPSIZ); + else + res = memcmp_not_common_alignment (srcp1, srcp2, len / OPSIZ); + if (res != 0) + return res; + + /* Number of bytes remaining in the interval [0..OPSIZ-1]. */ + srcp1 += len & -OPSIZ; + srcp2 += len & -OPSIZ; + len %= OPSIZ; + } + + /* There are just a few bytes to compare. Use byte memory operations. */ + while (len != 0) + { + a0 = ((byte *) srcp1)[0]; + b0 = ((byte *) srcp2)[0]; + srcp1 += 1; + srcp2 += 1; + res = a0 - b0; + if (res != 0) + return res; + len -= 1; + } + + return 0; +} +#endif /* HAVE_MEMCMP && MEMCMP_BROKEN */ diff --git a/common/support_def.h b/common/support_def.h new file mode 100644 index 0000000..500e88f --- /dev/null +++ b/common/support_def.h @@ -0,0 +1,28 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/support_def.h + * Copyright (C) 1991, 1993, 1995 Free Software Foundation, Inc. + * Contributed by Torbjorn Granlund (tege@sics.se). + * + * 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. + */ + +#ifdef __ptr_t +#undef __ptr_t +#endif +#if defined (__STDC__) && __STDC__ +#define __ptr_t void * +#else +#define __ptr_t char * +#endif diff --git a/common/support_ext.h b/common/support_ext.h new file mode 100644 index 0000000..6e81d18 --- /dev/null +++ b/common/support_ext.h @@ -0,0 +1,80 @@ +/************************************************************************ + * IRC - Internet Relay Chat, common/support_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in common/support.c. + */ + +/* External definitions for global functions. + */ +#ifndef SUPPORT_C +#define EXTERN extern +#else /* SUPPORT_C */ +#define EXTERN +#endif /* SUPPORT_C */ +EXTERN char *mystrdup __P((char *s)); +#if ! HAVE_STRTOKEN +EXTERN char *strtoken __P((char **save, char *str, char *fs)); +#endif /* HAVE_STRTOKEN */ +#if ! HAVE_STRTOK +EXTERN char *strtok __P((char *str, char *fs)); +#endif /* HAVE_STRTOK */ +#if ! HAVE_STRERROR +EXTERN char *strerror __P((int err_no)); +#endif /* HAVE_STRERROR */ +EXTERN char *myctime __P((time_t value)); +EXTERN char *mybasename __P((char *)); +#ifdef INET6 +EXTERN char *inetntop(int af, const void *in, char *local_dummy, size_t the_size); +#endif +#if ! HAVE_INET_NTOA +EXTERN char *inetntoa __P((char *in)); +#endif /* HAVE_INET_NTOA */ +#if ! HAVE_INET_NETOF +EXTERN int inetnetof __P((struct in_addr in)); +#endif /* HAVE_INET_NETOF */ +#if ! HAVE_INET_ADDR +EXTERN u_long inetaddr __P((register const char *cp)); +#endif /* HAVE_INET_ADDR */ +#if ! HAVE_INET_ATON +EXTERN int inetaton __P((register const char *cp, struct in_addr *addr)); +#endif /* HAVE_INET_ATON */ +#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) +EXTERN void dumpcore (); +#endif /* DEBUGMODE && !CLIENT_COMPILE */ +#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) && defined(DO_DEBUG_MALLOC) +EXTERN char *MyMalloc __P((size_t x)); +EXTERN char *MyRealloc __P((char *x, size_t y)); +EXTERN void MyFree __P((char *x)); +#else /* DEBUGMODE && !CLIENT_COMPILE && !DO_DEBUG_MALLOC */ +EXTERN char *MyMalloc __P((size_t x)); +EXTERN char *MyRealloc __P((char *x, size_t y)); +#endif /* DEBUGMODE && !CLIENT_COMPILE && !DO_DEBUG_MALLOC */ +#if ! USE_STDARG +EXTERN int irc_sprintf(); +#endif /* USE_STDARG */ +EXTERN int dgets __P((int fd, char *buf, int num)); +EXTERN char *make_version(); +#if SOLARIS_2_3 +EXTERN struct hostent *solaris_gethostbyname __P((const char *name)); +#endif /* SOLARIS_2_3 */ +#if HAVE_MEMCMP && MEMCMP_BROKEN +EXTERN int irc_memcmp __P((const __ptr_t s1, const __ptr_t s2, size_t len)); +#endif /* HAVE_MEMCMP && MEMCMP_BROKEN */ +#undef EXTERN diff --git a/configure b/configure new file mode 100755 index 0000000..6ea0218 --- /dev/null +++ b/configure @@ -0,0 +1,50 @@ +#! /bin/sh + +quick_fwd= +for arg +do + case "$arg" in + -help | --help | --hel | --he) + quick_fwd=yes + break ;; + -version | --version | --versio | --versi | --vers) + quick_fwd=yes + break ;; + *) + break ;; + esac +done +if test "x$quick_fwd" = xyes +then + support/configure $* +else + echo "retrieving the system name, type and OS release..." + rev=`support/config.guess` + if test "${rev}" # test for no output + then + echo " your system seems to be ${rev}." + if test ! -d "${rev}" + then + echo "creating directory ${rev}..." + mkdir "${rev}" + fi + cd "${rev}" + echo "now working in directory ${rev}..." + cp -p ../support/configure . + if test ! -f config.h + then + echo "copying config.h from config.h.dist..." + cp -p ../support/config.h.dist config.h + fi + ./configure $* + if test $? = 0 + then + echo "Have you read doc/README? (I hope so)" + echo "Next cd ${rev}, edit \"config.h\" and \"Makefile\"," + echo "run \"make all\" to build and \"make install\" to install." + fi + else + echo Failed to determine your host type, giving up. + echo Perhaps you should specify it manually. + fi +fi diff --git a/contrib/README b/contrib/README new file mode 100644 index 0000000..7d62989 --- /dev/null +++ b/contrib/README @@ -0,0 +1,21 @@ +$Id: README,v 1.6 1999/03/13 23:06:15 kalt Exp $ + +This directory contains ircd related contributions. Most of them fall + in one of the following categories: + * small side utility + * code sample + * service + +Each contribution lives in its own directory under contrib/ and has a +README file. For those which need to be compiled, this can be done in +the same directory as you compiled irc and/or ircd. + +If you want to submit a package for this directory, see the RULES file. + +--- + +mkpasswd utility to crypt a password. +ircdwatch utility to keep ircd running (eventually restarting it). +tkserv stupid toy to manage "temporary" klines. +mod_passwd example of DSM module for iauth +antispoof.diff diff file to add extra code to ircd to prevent TCP spoofing diff --git a/contrib/RULES b/contrib/RULES new file mode 100644 index 0000000..f3de2a1 --- /dev/null +++ b/contrib/RULES @@ -0,0 +1,24 @@ +$Id: RULES,v 1.2 1998/11/09 20:07:12 kalt Exp $ + +This file describes how to prepare a package for inclusion +in the contrib/ directory. The goal is to have a consistent +setup for all contributions, making it easy to install any +of them. + +* each package must have a README file (at least) explaining + what it is about. +* a man page would be nice ;-) + +* packages are stored in contrib/<package name> + +* C programs: + * If possible, use the same coding style as in the + rest of the package. + * They need to be portable + * They should use "setup.h" or "os.h" + * If needed, they may have a *.h file generated by configure + * They are to be compiled from within the same + directory as irc/ircd, using the same Makefile + + +* questions, submissions should be sent to ircd-dev@irc.org diff --git a/contrib/antispoof.README b/contrib/antispoof.README new file mode 100644 index 0000000..fd1d5a7 --- /dev/null +++ b/contrib/antispoof.README @@ -0,0 +1,56 @@ +The nospoof patch was adapted from the nospoof5 patch in use on Undernet +servers. It should NOT be needed unless you're running ircd on a really +old OS which doesn't have a patch against TCP spoofing. Note that this +patch should be applied BEFORE running ./configure -- this is very +important, and the usual cause of any problems encountered. + +When a client connects to the server, they are sent a PING with a random +number (please do not confuse this with a CTCP PING -- they're very +different things). Until the client responds with a PONG and the correct +random number, it is not registered with the server and cannot do +anything. + +Please note that this does break the RFC. However, it has been tested +with most popular clients and is in common use on large IRC networks +currently. The only reported client to have problems is Homer (for +the Macintosh). + +To cater for possibly broken clients, a message is also sent to clients +on connect of the form: + +*** If your client freezes here, type /QUOTE PONG 12345678 or /PONG 12345678 + +Because of this, it is a good idea to increase the allowed timeout on +connections since the user might have to manually PONG the server with +the ugly number (although hopefully they only need to cut'n'paste). + +If the client PONGs with the wrong number, another message is sent to +the client directing the user what to type. In addition, if the +connection does end up timing out due to no PONG, a message is sent to +the user explaining the client may not be compatible, and lists where +compatible clients for all the major platforms can be found. + +The random number sequence is based on an md5 series. I didn't write it. +Someone else did. It's included because many have a dud random() in their +libc (this applies to more people than you think). It is seeded on a +#define value in config.h - YOU MUST CHANGE THIS FROM THE DEFAULT OR YOU +CAN STILL BE SPOOFED. If you still find that you get spoofed, try +changing this value again and recompiling. + +KNOWN BUGS: + + - There is a known bug whereby the host provided by the client's + USER sequence is not checked for validity until after the PONG + reply (and registration takes place). This allows a form of + "spoofing" to take place, with the client showing under /whois + lookups with a fake hostname. At this stage the client can't + actually issue commands to the server though, and the hostmask + is corrected to what it should be upon the PONG being received + (and the client properly registered). + + - The random number generator isn't 64-bit clean. On 64-bit + machines, a 64-bit random number is generated, but I'm not + convinced all 64-bits are random. At least 32 bits are + however, so this isn't a problem. + + - Andrew (earthpig@yoyo.cc.monash.edu.au) diff --git a/contrib/antispoof.diff b/contrib/antispoof.diff new file mode 100644 index 0000000..b02832f --- /dev/null +++ b/contrib/antispoof.diff @@ -0,0 +1,484 @@ +diff -urN irc-cvs/common/numeric_def.h irc-cvs-nospoof/common/numeric_def.h +--- irc-cvs/common/numeric_def.h Wed Jan 20 12:28:46 1999 ++++ irc-cvs-nospoof/common/numeric_def.h Tue Mar 16 12:45:56 1999 +@@ -198,6 +198,10 @@ + #define ERR_UMODEUNKNOWNFLAG 501 + #define ERR_USERSDONTMATCH 502 + ++#if defined(NOSPOOF) ++#define ERR_BADPING 513 ++#endif ++ + /* + * Numberic replies from server commands. + * These are currently in the range 200-399. +diff -urN irc-cvs/common/parse.c irc-cvs-nospoof/common/parse.c +--- irc-cvs/common/parse.c Tue Dec 29 02:44:57 1998 ++++ irc-cvs-nospoof/common/parse.c Tue Mar 16 12:45:56 1999 +@@ -56,7 +56,11 @@ + { MSG_INVITE, m_invite, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_WALLOPS, m_wallops, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L}, + { MSG_PING, m_ping, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, ++#if defined(NOSPOOF) ++ { MSG_PONG, m_pong, MAXPARA, MSG_LAG, 0, 0, 0L}, ++#else + { MSG_PONG, m_pong, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, ++#endif + { MSG_ERROR, m_error, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L}, + #ifdef OPER_KILL + { MSG_KILL, m_kill, MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L}, +diff -urN irc-cvs/common/send.c irc-cvs-nospoof/common/send.c +--- irc-cvs/common/send.c Fri Feb 5 10:26:35 1999 ++++ irc-cvs-nospoof/common/send.c Tue Mar 16 12:45:56 1999 +@@ -392,6 +392,9 @@ + NULL, + # endif + 0, {0, 0, NULL }, {0, 0, NULL }, ++#if defined(NOSPOOF) ++ -1, ++#endif + 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, NULL, 0 + # if defined(__STDC__) /* hack around union{} initialization -Vesa */ + ,{0}, NULL, "", "" +diff -urN irc-cvs/common/struct_def.h irc-cvs-nospoof/common/struct_def.h +--- irc-cvs/common/struct_def.h Sun Mar 14 11:59:54 1999 ++++ irc-cvs-nospoof/common/struct_def.h Tue Mar 16 12:45:56 1999 +@@ -432,6 +432,9 @@ + short lastsq; /* # of 2k blocks when sendqueued called last*/ + dbuf sendQ; /* Outgoing message queue--if socket full */ + dbuf recvQ; /* Hold for data incoming yet to be parsed */ ++#if defined(NOSPOOF) ++ u_long cookie; /* Random cookie local clients must PONG */ ++#endif + long sendM; /* Statistics: protocol messages send */ + long sendK; /* Statistics: total k-bytes send */ + long receiveM; /* Statistics: protocol messages received */ +diff -urN irc-cvs/ircd/ircd.c irc-cvs-nospoof/ircd/ircd.c +--- irc-cvs/ircd/ircd.c Sun Mar 14 11:59:58 1999 ++++ irc-cvs-nospoof/ircd/ircd.c Tue Mar 16 12:45:56 1999 +@@ -493,6 +493,22 @@ + else + { + cptr->exitc = EXITC_PING; ++#if defined(NOSPOOF) ++ if((!IsRegistered(cptr)) && (cptr->name) && ++ (cptr->username)) ++ { ++ sendto_one(cptr, ++ ":%s %d %s :Your client may not be compatible with this server.", ++ me.name, ERR_BADPING, cptr->name); ++ /* Someone suggest a better ++ * place? :) - Earthpig ++ */ ++ sendto_one(cptr, ++ ":%s %d %s :Compatible clients are available at " ++ "ftp://yoyo.cc.monash.edu.au/pub/irc/clients/", ++ me.name, ERR_BADPING, cptr->name); ++ } ++#endif + (void)exit_client(cptr, cptr, &me, + "Ping timeout"); + } +diff -urN irc-cvs/ircd/list.c irc-cvs-nospoof/ircd/list.c +--- irc-cvs/ircd/list.c Tue Dec 29 02:44:57 1998 ++++ irc-cvs-nospoof/ircd/list.c Tue Mar 16 12:45:56 1999 +@@ -146,6 +146,9 @@ + if (size == CLIENT_LOCAL_SIZE) + { + cptr->since = cptr->lasttime = cptr->firsttime = timeofday; ++#if defined(NOSPOOF) ++ cptr->cookie = 0; ++#endif + cptr->confs = NULL; + cptr->sockhost[0] = '\0'; + cptr->buffer[0] = '\0'; +diff -urN irc-cvs/ircd/random.c irc-cvs-nospoof/ircd/random.c +--- irc-cvs/ircd/random.c Thu Jan 1 10:00:00 1970 ++++ irc-cvs-nospoof/ircd/random.c Tue Mar 16 12:45:56 1999 +@@ -0,0 +1,162 @@ ++/************************************************************************ ++ * 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 "os.h" ++#include "s_defines.h" ++ ++#ifdef NOSPOOF ++ ++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); ++} ++ ++#endif +diff -urN irc-cvs/ircd/s_debug.c irc-cvs-nospoof/ircd/s_debug.c +--- irc-cvs/ircd/s_debug.c Fri Feb 5 10:44:16 1999 ++++ irc-cvs-nospoof/ircd/s_debug.c Tue Mar 16 12:45:56 1999 +@@ -148,6 +148,9 @@ + #ifdef INET6 + '6', + #endif ++#if defined(NOSPOOF) ++'*', ++#endif + '\0'}; + + #ifdef DEBUGMODE +@@ -344,7 +347,7 @@ + sendto_one(cptr, ":%s %d %s :BS:%d MXR:%d MXB:%d MXBL:%d PY:%d", + ME, RPL_STATSDEFINE, nick, BUFSIZE, MAXRECIPIENTS, MAXBANS, + MAXBANLENGTH, MAXPENALTY); +- sendto_one(cptr, ":%s %d %s :ZL:%d CM:%d CP:%d", ++ sendto_one(cptr, ":%s %d %s :ZL:%d CM:%d CP:%d NS:%s", + ME, RPL_STATSDEFINE, nick, + #ifdef ZIP_LINKS + ZIP_LEVEL, +@@ -352,9 +355,14 @@ + -1, + #endif + #ifdef CLONE_CHECK +- CLONE_MAX, CLONE_PERIOD ++ CLONE_MAX, CLONE_PERIOD, ++#else ++ -1, -1, ++#endif ++#if defined(NOSPOOF) ++ "yes" + #else +- -1, -1 ++ "no" + #endif + ); + } +diff -urN irc-cvs/ircd/s_err.c irc-cvs-nospoof/ircd/s_err.c +--- irc-cvs/ircd/s_err.c Sun Feb 28 02:45:29 1999 ++++ irc-cvs-nospoof/ircd/s_err.c Tue Mar 16 12:45:56 1999 +@@ -162,6 +162,19 @@ + { 0, (char *)NULL }, + /* 501 */ { ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag" }, + /* 502 */ { ERR_USERSDONTMATCH, ":Can't change mode for other users" }, ++#if defined(NOSPOOF) ++ { 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 }, ++ { 0, (char *)NULL }, ++/* 513 */ { ERR_BADPING, (char *)NULL }, ++#endif + { 0, (char *)NULL } + }; + +diff -urN irc-cvs/ircd/s_user.c irc-cvs-nospoof/ircd/s_user.c +--- irc-cvs/ircd/s_user.c Tue Mar 16 12:32:51 1999 ++++ irc-cvs-nospoof/ircd/s_user.c Tue Mar 16 12:51:41 1999 +@@ -335,9 +335,9 @@ + + /* + ** register_user +-** This function is called when both NICK and USER messages +-** have been accepted for the client, in whatever order. Only +-** after this the USER message is propagated. ++** This function is called when both NICK and USER [and maybe PONG] ++** messages have been accepted for the client, in whatever order. ++** Only after this the USER message is propagated. + ** + ** NICK's must be propagated at once when received, although + ** it would be better to delay them too until full info is +@@ -1007,9 +1007,30 @@ + + /* This had to be copied here to avoid problems.. */ + (void)strcpy(sptr->name, nick); ++#if defined(NOSPOOF) ++ /* If the client hasn't gotten a cookie-ping yet, ++ choose a cookie and send it. -record!jegelhof@cloud9.net */ ++ ++ if (!sptr->cookie) ++ { ++ while((!sptr->cookie) || (sptr->cookie==-1)) ++ sptr->cookie=(ircrandom()); ++ sendto_one(cptr, "PING :%lu", sptr->cookie); ++ sendto_one(sptr, ++ ":%s %d %s :If your client freezes here, type /QUOTE PONG %lu " ++ "or /PONG %lu ", ++ me.name, ERR_BADPING, sptr->name, ++ sptr->cookie, sptr->cookie); ++ } ++ ++ if ((sptr->user) && (sptr->cookie==-1)) ++ { ++#else + if (sptr->user) ++#endif + /* +- ** USER already received, now we have NICK. ++ ** USER [and possibly PONG] already received, ++ ** now we have NICK. + ** *NOTE* For servers "NICK" *must* precede the + ** user message (giving USER before NICK is possible + ** only for local client connection!). register_user +@@ -1020,6 +1041,9 @@ + sptr->user->username) + == FLUSH_BUFFER) + return FLUSH_BUFFER; ++#if defined(NOSPOOF) ++ } ++#endif + } + /* + ** Finally set new nick name. +@@ -1849,7 +1873,12 @@ + if (strlen(realname) > REALLEN) + realname[REALLEN] = '\0'; + sptr->info = mystrdup(realname); +- if (sptr->name[0]) /* NICK already received, now we have USER... */ ++ if ((sptr->name[0]) ++#if defined(NOSPOOF) ++ && (!MyConnect(sptr) || (sptr->cookie==-1)) ++#endif ++ ) ++ /* NICK already received, now we have USER... */ + { + if ((parc == 6) && IsServer(cptr)) /* internal m_user() */ + { +@@ -2222,7 +2251,32 @@ + aClient *acptr; + char *origin, *destination; + +- if (parc < 2 || *parv[1] == '\0') ++#if defined(NOSPOOF) ++ /* Check to see if this is a PONG :cookie reply from an ++ unregistered user. If so, process it. -record */ ++ ++ if((!IsRegistered(sptr)) && (sptr->cookie!=0) && ++ (sptr->cookie!=-1) && (parc>1)) ++ { ++ if(strtoul(parv[parc-1],NULL,10)==sptr->cookie) ++ { ++ sptr->cookie=-1; ++ if((sptr->user) && (sptr->name[0])) ++ /* NICK and USER OK */ ++ return register_user(cptr, sptr, sptr->name, ++ sptr->user->username); ++ } ++ else ++ sendto_one(sptr, ++ ":%s %d %s :To connect, type /QUOTE PONG %lu or /PONG %lu", ++ me.name, ERR_BADPING, sptr->name, ++ sptr->cookie, sptr->cookie); ++ ++ return 1; ++ } ++#endif ++ ++ if (parc < 2 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NOORIGIN, parv[0])); + return 1; +diff -urN irc-cvs/support/Makefile.in irc-cvs-nospoof/support/Makefile.in +--- irc-cvs/support/Makefile.in Fri Mar 12 20:06:00 1999 ++++ irc-cvs-nospoof/support/Makefile.in Tue Mar 16 12:47:37 1999 +@@ -153,7 +153,7 @@ + SERVER_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_id.o s_misc.o s_numeric.o \ + s_serv.o s_service.o s_user.o s_zip.o whowas.o \ +- res_init.o res_comp.o res_mkquery.o ++ res_init.o res_comp.o res_mkquery.o random.o + + IAUTH_COMMON_OBJS = clsupport.o clmatch.o # This is a little evil + IAUTH_OBJS = iauth.o a_conf.o a_io.o a_log.o \ +@@ -431,6 +431,9 @@ + + res_mkquery.o: ../ircd/res_mkquery.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_mkquery.c ++ ++random.o: ../ircd/random.c setup.h config.h ++ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/random.c + + iauth.o: ../iauth/iauth.c config.h setup.h + $(CC) $(A_CFLAGS) -c -o $@ ../iauth/iauth.c +diff -urN irc-cvs/support/config.h.dist irc-cvs-nospoof/support/config.h.dist +--- irc-cvs/support/config.h.dist Mon Feb 22 10:41:32 1999 ++++ irc-cvs-nospoof/support/config.h.dist Tue Mar 16 12:45:57 1999 +@@ -374,6 +374,30 @@ + */ + #undef CLONE_CHECK + ++/* Define this to turn on code that enables a PING/PONG cookies sequence ++ * whenever a client connects. The purpose of this is to prevent IP ++ * spoofing (normally based on predicting TCP/IP sequence numbers). ++ * This breaks the RFC slightly, but so far only one (old) client has ++ * been encountered that breaks. There's a small overhead if you define ++ * it, but it's essential for older BSD-based (or any other) TCP/IP ++ * stacks with predictable sequence numbers. ++ */ ++ ++#undef NOSPOOF ++ ++/* Random number generator seed -- used for cookies if NOSPOOF is ++ * defined. ++ * ++ * Set this to an 8 character random text string. ++ * Do _NOT_ use the default text. ++ * If people are able to defeat the IP-spoofing protection on your ++ * server, please consider changing this value and recompiling. ++ */ ++ ++#if defined(NOSPOOF) ++#define RANDOM_SEED "ChangeMe" ++#endif ++ + /* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */ + /* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */ + /* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */ diff --git a/contrib/ircdwatch/README b/contrib/ircdwatch/README new file mode 100644 index 0000000..80653bd --- /dev/null +++ b/contrib/ircdwatch/README @@ -0,0 +1,56 @@ +$Id: README,v 1.5 1998/11/09 22:56:34 borud Exp $ + +DESCRIPTION +=========== + ircdwatch is a daemon that regularly checks to see if ircd is running. + if ircd should die or somehow stop running, ircdwatch will respawn the + ircd daemon. if desirable, ircdwatch can be configured to check if + the ircd configuration file is changed and send a SIGHUP to the ircd + daemon which then causes the daemon to reload the configuration + file. + + the ircdwatch program itself is also used as sort of a remote + control depending on what command line arguments you feed it. you + can use it to start ircd and stop ircd and ircdwatch. + +OPTIONS +======= + if you invoke ircdwatch without any command line arguments it will + either daemonize itself and become a daemon, or it will exit if it + detects that an ircdwatch daemon is already running. + + for using the ircdwatch program as a remote control the following + command line options are available: + + --kill + stop both ircdwatch and ircd + + --rest + stop ircdwatch but leave ircd running + + --help + list command line arguments + + +COMPILE TIME CONFIGURATION +========================== + you configure ircdwatch by editing config.h in the directory where + you build ircd. the configuration parameters available for + ircdwatch are those starting with the prefix "IRCDWATCH_". please + refer to the config.h file for more information on the parameter + settings. most of the defaults should be okay if you want to use + ircdwatch though. + + +ADMINISTRATIVIA +=============== + ircdwatch was written by Bjorn Borud <borud@guardian.no> and is + Copyright (C) 1998 Bjorn Borud <borud@guardian.no> + + the program is released under the GNU General Public License + + the current maintainer can be reached at: <borud@guardian.no> + + please report bugs to <ircd-users@stealth.net> + improvements are welcome. + diff --git a/contrib/ircdwatch/ircdwatch.8 b/contrib/ircdwatch/ircdwatch.8 new file mode 100644 index 0000000..cc944b1 --- /dev/null +++ b/contrib/ircdwatch/ircdwatch.8 @@ -0,0 +1,50 @@ +.\" @(#)$Id: ircdwatch.8,v 1.1 1998/06/12 22:57:40 kalt Exp $ +.TH IRCDWATCH 8 "$Date: 1998/06/12 22:57:40 $" +.SH NAME +ircdwatch \- Daemon for monitoring ircd and ircd.conf +.SH SYNOPSIS +.hy 0 +.IP \fBircdwatch\fP +[ +.BI \-\-kill +] [ +.BI \-\-rest +] [ +.BI \-\-help +] +.SH DESCRIPTION +.LP +\fIircdwatch\fP is a daemon that periodically checks that the +\fIircd\fP daemon is running, restarting it of necessary. This +daemon can also be configured (at compile time) to check for +changes to the \fIircd\fP configuration file and make \fIircd\fP +reload its configuration file by sending it a SIGHUP signal. +.LP +Given command line arguments \fIircdwatch\fP will serve as a remote +control for stopping both \fIircdwatch\fP and \fIircd\fP or just +\fIircdwatch\fP. + +.SH OPTIONS +.TP +.B \-\-kill +Stop both \fIircd\fP and \fIircdwatch\fP +.TP +.B \-\-rest +Stop \fIircdwatch\fP but leave \fIircd\fP running +.TP +.B \-\-help +List command line arguments +.SH COPYRIGHT +Copyright (C) 1998 Bjorn Borud, <borud@guardian.no> +.LP +.RE +.SH FILES + "ircd.conf" + "ircd.pid" + "ircdwatch.pid" +.SH "SEE ALSO" +ircd(8) +.SH BUGS +There may be some portability issues. Report bugs to <ircd-users@stealth.net> +.SH AUTHOR +Bjorn Borud, <borud@guardian.no> diff --git a/contrib/ircdwatch/ircdwatch.c b/contrib/ircdwatch/ircdwatch.c new file mode 100644 index 0000000..c384578 --- /dev/null +++ b/contrib/ircdwatch/ircdwatch.c @@ -0,0 +1,499 @@ +/* + * Copyright (C) 1998 Bjorn Borud <borud@guardian.no> + * + * 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 rcsid[] = "@(#)$Id: ircdwatch.c,v 1.3 1999/02/21 00:33:44 kalt Exp $"; +#endif + +#include <stdio.h> +#include <stdlib.h> /* atol() */ +#include <unistd.h> /* fork() exec() */ +#include <sys/types.h> +#include <sys/stat.h> /* stat() */ +#include <signal.h> +#include <syslog.h> +#include <string.h> /* strncmp() */ +#include <time.h> + +#include "os.h" +#include "config.h" + +/* + * Try and find the correct name to use with getrlimit() for setting + * the max. number of files allowed to be open by this process. + * (borrowed from ircd/s_bsd.c) + */ +#ifdef RLIMIT_FDMAX +# define RLIMIT_FD_MAX RLIMIT_FDMAX +#else +# ifdef RLIMIT_NOFILE +# define RLIMIT_FD_MAX RLIMIT_NOFILE +# else +# ifdef RLIMIT_OPEN_MAX +# define RLIMIT_FD_MAX RLIMIT_OPEN_MAX +# else +# undef RLIMIT_FD_MAX +# endif +# endif +#endif + +#define PID_LEN 7 /* overkill, but hey */ +#define MAX_OPEN_FILEDESCRIPTORS_WILD_GUESS 256 + +static int want_to_quit = 0; + +void finalize(int i) +{ +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_NOTICE, "ircdwatch daemon exiting"); + closelog(); +#endif + exit(i); +} + +int daemonize(void) +{ + pid_t pid; + int i; + int open_max; + +#ifdef RLIMIT_FD_MAX + struct rlimit rlim; + + if (getrlimit(RLIMIT_FD_MAX, &rlim) != 0) { + perror("getrlimit"); + finalize(1); + } + + /* if we get a lame answer we just take a wild guess */ + if (rlim.rlim_max == 0) { + open_max = MAX_OPEN_FILEDESCRIPTORS_WILD_GUESS; + } + + open_max = rlim.rlim_max; + +#else + + /* no RLIMIT_FD_MAX? take a wild guess */ + open_max = MAX_OPEN_FILEDESCRIPTORS_WILD_GUESS; + +#endif + + pid = fork(); + if (pid < 0) { + perror("fork"); + exit(1); + } + + /* parent process dies */ + if (pid != 0) { + exit(0); + } + + setsid(); + umask(0); + + /* close file descriptors */ + for (i=0; i < open_max; i++) { + close(i); + } + + return(0); +} + +static void sig_handler (int signo) +{ + if (signo == SIGHUP) { + want_to_quit = 1; + return; + } + + if (signo == SIGALRM) { + +#ifndef POSIX_SIGNALS + (void)signal(SIGALRM, &sig_handler); +#endif; + + return; + } +} + + +void set_up_signals(void) +{ +#ifdef POSIX_SIGNALS + struct sigaction act; + + act.sa_handler = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + if (sigaction(SIGHUP, &act, NULL) < 0) { + perror("sigaction"); + } + + if (sigaction(SIGALRM, &act, NULL) < 0) { + perror("sigaction"); + } +#else + (void)signal(SIGHUP, &sig_handler); + (void)signal(SIGALRM, &sig_handler); +#endif + + /* ignore it if child processes die */ + signal(SIGCHLD, SIG_IGN); +} + +int write_my_pid(void) +{ + FILE *f; + + f = fopen(IRCDWATCH_PID_FILENAME, "w"); + if (f == NULL) { + return(-1); + } + + fprintf(f, "%d\n", getpid()); + fclose(f); + + return(0); +} + + +int file_modified(char *s) +{ + struct stat st; + + if (stat(s, &st) < 0) { + return(-1); + } + return(st.st_ctime); +} + + +int spawn (char *cmd) +{ + pid_t pid; + + pid = fork(); + + if (pid == -1) { +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "spawn() unable to fork, errno=%d", errno); +#endif + return(-1); + } + + if (pid == 0) { + execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); + _exit(127); + } + return(0); +} + +int read_pid(char *pid_filename) +{ + FILE *f; + char pidbuf[PID_LEN]; + pid_t pid; + + f = fopen(pid_filename, "r"); + if (f == NULL) { +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "unable to fopen() %s: %s", pid_filename, strerror(errno)); +#endif + return(-1); + } + + if (fgets(pidbuf, PID_LEN, f) != NULL) { + pid = atol(pidbuf); + } else { +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "fgets() %s: %s", pid_filename, strerror(errno)); +#endif + fclose(f); + return(-1); + } + + fclose(f); + return(pid); +} + +int file_exists (char *s) +{ + struct stat st; + if ((stat(s, &st) < 0) && (errno == ENOENT)) { + return(0); + } + return(1); +} + +/* yeah, I'll get around to these in some later version */ + +int file_readable (char *s) +{ + return(access(s, R_OK) == 0); +} + +int file_writable (char *s) +{ + return(access(s, W_OK) == 0); +} + +int file_executable (char *s) +{ + int rc; + rc = (access(IRCD_PATH, X_OK) == 0); + return rc; +} + +int verify_pid(int pid) +{ + int res; + + res = kill(pid, 0); + if (res < 0 && errno == EPERM) { + fprintf(stderr, "Not process owner\n"); + exit(1); + } + + return(res == 0); +} + +int ircdwatch_running () { + int pid; + + if (file_exists(IRCDWATCH_PID_FILENAME)) { + pid = read_pid(IRCDWATCH_PID_FILENAME); + if (pid > 0) { + return(verify_pid(pid) == 1); + } else { + return(-1); + } + } + return(0); +} + +int ircd_running () { + int pid; + + if (file_exists(IRCDPID_PATH)) { + pid = read_pid(IRCDPID_PATH); + if (pid > 0) { + return(verify_pid(pid) == 1); + } else { + return(-1); + } + } + return(0); +} + +void hup_ircd () +{ + int pid; + int res; + + if (file_exists(IRCDPID_PATH)) { + pid = read_pid(IRCDPID_PATH); + if (pid > 0) { + res = kill(pid, SIGHUP); + if (res < 0 && errno == EPERM) { +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "not allowed to send SIGHUP to ircd"); +#endif + finalize(1); + } + } + } +} + + +void daemon_run () +{ + int i; + int last_config_time = 0; + + /* is ircdwatch already running? */ + i = ircdwatch_running(); + if (i == -1) { + /* unable to open pid file. wrong user? */ + fprintf(stderr, "ircdwatch pid file exists but is unreadable\n"); + exit(1); + } else if (i) { + fprintf(stderr, "ircdwatch is already running\n"); + exit(0); + } + + /* is ircd running? */ + i = ircd_running(); + if (i == -1) { + /* unable to open pid file. wrong user? */ + fprintf(stderr, "ircdwatch pid file exists but is unreadable\n"); + exit(1); + } else if (!i) { + fprintf(stderr, "ircd not running. attempting to start ircd...\n"); + if (file_exists(IRCD_PATH)) { + if (file_executable(IRCD_PATH)) { + spawn(IRCD_PATH); + } else { + fprintf(stderr, "%s not executable\n", IRCD_PATH); + exit(1); + } + } else { + fprintf(stderr, "%s does not exist\n", IRCD_PATH); + exit(1); + } + } + + set_up_signals(); + closelog(); + /* daemonize(); */ + +#ifdef IRCDWATCH_USE_SYSLOG + openlog(IRCDWATCH_SYSLOG_IDENT, + IRCDWATCH_SYSLOG_OPTIONS, + IRCDWATCH_SYSLOG_FACILITY); + + syslog(LOG_NOTICE, "starting ircdwatch daemon"); +#endif + + alarm(IRCDWATCH_POLLING_INTERVAL); + pause(); + + while (!want_to_quit) { + if (! ircd_running() ) { + +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "spawning %s", IRCD_PATH); +#endif + + spawn(IRCD_PATH); + } + +#ifdef IRCDWATCH_HUP_ON_CONFIG_CHANGE + i = file_modified(IRCDCONF_PATH); + if (i != -1) { + + if (last_config_time == 0) { + last_config_time = i; + } + + else if (i > last_config_time) { + last_config_time = i; + hup_ircd(); + +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_NOTICE, "config change, HUPing ircd"); +#endif + + } + } +#endif + + alarm(IRCDWATCH_POLLING_INTERVAL); + pause(); + } + return; +} + +void kill_ircd () +{ + int pid; + int res; + + if (file_exists(IRCDPID_PATH)) { + pid = read_pid(IRCDPID_PATH); + if (pid > 0) { + res = kill(pid, SIGTERM); + if (res < 0) { + perror("ircd kill"); + finalize(1); + } else { + fprintf(stderr, "killed ircd\n"); + } + } + } else { + fprintf(stderr, "File %s does not exist\n", IRCDPID_PATH); + } +} + +void kill_ircdwatch () +{ + int pid; + int res; + + if (file_exists(IRCDWATCH_PID_FILENAME)) { + pid = read_pid(IRCDWATCH_PID_FILENAME); + if (pid > 0) { + res = kill(pid, SIGHUP); + if (res < 0) { + perror("ircdwatch kill"); + finalize(1); + } else { + fprintf(stderr, "Sent HUP to ircdwatch. it will die soon...\n"); + } + } + } else { + fprintf(stderr, "File %s does not exist\n", IRCDWATCH_PID_FILENAME); + } +} + + +void usage (void) +{ + fprintf(stderr,"\n\ +Usage:\n\ + ircdwatch [--kill | --rest | --help]\n\ +\n\ + --kill, stop both ircdwatch and ircd\n\ + --rest, stop ircdwatch but let ircd alone\n\ + --help, display this text\n\ +\n\ +%s\n", rcsid); +} + +int +main (int argc, char **argv) { + int i; + +#ifdef IRCDWATCH_USE_SYSLOG + openlog(IRCDWATCH_SYSLOG_IDENT, + IRCDWATCH_SYSLOG_OPTIONS, + IRCDWATCH_SYSLOG_FACILITY); +#endif + + if (argc > 1) { + if (strncmp(argv[1], "--rest", 6) == 0) { + kill_ircdwatch(); + exit(0); + } + + if (strncmp(argv[1], "--kill", 6) == 0) { + kill_ircdwatch(); + kill_ircd(); + exit(0); + } + + usage(); + exit(0); + } + + daemon_run(); + finalize(0); +} diff --git a/contrib/mkpasswd/README b/contrib/mkpasswd/README new file mode 100644 index 0000000..a2bb420 --- /dev/null +++ b/contrib/mkpasswd/README @@ -0,0 +1,64 @@ +/************************************************************************ + * 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. + * + * $Id: README,v 1.1 1998/04/07 21:20:59 kalt Exp $ + * + */ + +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) diff --git a/contrib/mkpasswd/crypter b/contrib/mkpasswd/crypter new file mode 100755 index 0000000..4851620 --- /dev/null +++ b/contrib/mkpasswd/crypter @@ -0,0 +1,55 @@ +#!/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. +#* +#* $Id: crypter,v 1.1 1998/04/07 21:21:00 kalt Exp $ +#* +#*/ + +#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); diff --git a/contrib/mkpasswd/mkpasswd.c b/contrib/mkpasswd/mkpasswd.c new file mode 100644 index 0000000..8ea8413 --- /dev/null +++ b/contrib/mkpasswd/mkpasswd.c @@ -0,0 +1,44 @@ +/* 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> + +#ifndef lint +static char rcsid[] = "@(#)$Id: mkpasswd.c,v 1.1 1998/04/07 21:21:00 kalt Exp $"; +#endif + +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; +} + diff --git a/contrib/mod_passwd/README b/contrib/mod_passwd/README new file mode 100644 index 0000000..6aa2352 --- /dev/null +++ b/contrib/mod_passwd/README @@ -0,0 +1,30 @@ +$Id: README,v 1.1 1999/03/13 23:06:15 kalt Exp $ + +This is an example module for the authentication program (iauth) used by +the IRC server. + +* This module demonstrates how a module can access and use the PASS and + USER information provided by users. It is *NOT* a finished product. In + particular, the actual password validation is not implemented. + +* This module also demonstrates how a DSM module should be written. You'll + note that it is completely identical to ordinary modules, except for one + extra function: "passwd_load()" + +To be used, this module needs to be compiled from the normal compilation +directory. It should be linked as a dynamic library. Methods vary +depending on the compiler and platform. + +$ gcc -c -g -I../iauth -I../common -I. ../contrib/mod_passwd/mod_passwd.c +$ ld -Bshareable mod_passwd.o -o mod_passwd.so +$ ls -l mod_passwd.so +-rwxr--r-- 1 kalt staff 26932 Mar 13 17:59 mod_passwd.so +$ + +To be used by iauth, add the following lines to the iauth.conf file: + + extinfo + shared passwd /path/to/mod_passwd.so + module passwd + +See iauth.conf(5) for more information on configuring iauth. diff --git a/contrib/mod_passwd/mod_passwd.c b/contrib/mod_passwd/mod_passwd.c new file mode 100644 index 0000000..817a722 --- /dev/null +++ b/contrib/mod_passwd/mod_passwd.c @@ -0,0 +1,171 @@ +/************************************************************************ + * IRC - Internet Relay Chat, mod_passwd.c + * Copyright (C) 1999 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: mod_passwd.c,v 1.1 1999/03/13 23:06:15 kalt Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#include "a_externs.h" + +/* + * passwd_init + * + * This procedure is called when a particular module is loaded. + * Returns NULL if everything went fine, + * an error message otherwise. + */ +char * +passwd_init(self) +AnInstance *self; +{ + return NULL; +} + +/* + * passwd_release + * + * This procedure is called when a particular module is unloaded. + */ +void +passwd_release(self) +AnInstance *self; +{ +} + +/* + * passwd_stats + * + * This procedure is called regularly to update statistics sent to ircd. + */ +void +passwd_stats(self) +AnInstance *self; +{ +} + +/* + * passwd_start + * + * This procedure is called to start an authentication. + * Returns 0 if everything went fine, + * +1 if still waiting for some data (username, password).. + * -1 otherwise (nothing to be done, or failure) + * + * It is responsible for sending error messages where appropriate. + * In case of failure, it's responsible for cleaning up (e.g. passwd_clean + * will NOT be called) + */ +int +passwd_start(cl) +u_int cl; +{ + if (cldata[cl].authuser && + cldata[cl].authfrom < cldata[cl].instance->in) + { + /* + ** another instance preceding this one in the configuration + ** has already authenticated the user, no need to bother + ** doing anything here then. (the other takes precedence) + */ + return -1; + } + if ((cldata[cl].state & A_GOTU) == 0) + /* haven't received username/password pair from ircd yet */ + return 1; + if ((cldata[cl].state & A_GOTP) == 0) + { + /* no password to check -> reject user! */ + cldata[cl].state |= A_DENY; + sendto_ircd("K %d %s %u ", cl, cldata[cl].itsip, + cldata[cl].itsport); + return -1; /* done */ + } + /* + ** + ** + ** INSERT FUNCTION TO CHECK PASSWORD VALIDITY + ** + ** + */ + /* if failure, see above */ + /* if success: */ + cldata[cl].state |= A_UNIX; + if (cldata[cl].authuser) + free(cldata[cl].authuser); + cldata[cl].authuser = mystrdup(cldata[cl].user); + cldata[cl].authfrom = cldata[cl].instance->in; + sendto_ircd("U %d %s %u %s", cl, cldata[cl].itsip, cldata[cl].itsport, + cldata[cl].authuser); + return -1; /* done */ +} + +/* + * passwd_work + * + * This procedure is called whenever there's new data in the buffer. + * Returns 0 if everything went fine, and there is more work to be done, + * Returns -1 if the module has finished its work (and cleaned up). + * + * It is responsible for sending error messages where appropriate. + */ +int +passwd_work(cl) +u_int cl; +{ + return -1; +} + +/* + * passwd_clean + * + * This procedure is called whenever the module should interrupt its work. + * It is responsible for cleaning up any allocated data, and in particular + * closing file descriptors. + */ +void +passwd_clean(cl) +u_int cl; +{ +} + +/* + * passwd_timeout + * + * This procedure is called whenever the timeout set by the module is + * reached. + * + * Returns 0 if things are okay, -1 if authentication was aborted. + */ +int +passwd_timeout(cl) +u_int cl; +{ +} + +static aModule Module_passwd = + { "passwd", passwd_init, passwd_release, passwd_stats, + passwd_start, passwd_work, passwd_timeout, passwd_clean }; + +aModule * +passwd_load() +{ + return &Module_passwd; +} diff --git a/contrib/tkserv/CHANGES b/contrib/tkserv/CHANGES new file mode 100644 index 0000000..e983ded --- /dev/null +++ b/contrib/tkserv/CHANGES @@ -0,0 +1,37 @@ +1.0.0b8 : Ported TkServ to C. +1.0.0b8 : It is now possible to QUIT the service via SQUERY. +1.0.0b9 : Added default expiration if no time value was specified (koopal) +1.0.0b9 : It is now possible to remove existing tklines "manually" (koopal) +1.0.0b10: the pwd of the service went to the cmd line (koopal) +1.0.0 : Official release of TkServ +1.0.1 : Applied some fixes to make TkServ work under BSDI (primetime) +1.0.1 : no address of a local var is returned anymore :) (primetime) +1.0.2 : Added forgotten tkserv.access.example to the package (primetime) +1.0.2 : IP masks (x.x.x.*) are now also be recognized as IPs (primetime) +1.0.2 : hostnames are now also possible in the restriction field (primetime) +1.0.3 : DEBUGGING is now functional and displays all service<->server + traffic to the standard output +1.0.3 : TkServ should now also compile under Irix (Szern) +1.0.3 : IP restrictions are now also possible in the access file + - wildcards are allowed (Szern) +1.0.3 : Wildcards do now also work in the oper u@h field of the access + file (Szern) +1.0.3 : Replaced FNM_CASEFOLD by FNM_NOESCAPE +1.0.4 : ':' is not allowed anymore in the TKLINE cmd line (Eumel) +1.0.4 : Fixed lame bug which kept tklines active altho already expired (Eumel) +1.0.5 : TkServ should now also compile under Redhat Linux. (Tero) +1.0.5 : a few changes for ircd/contrib compliancy +1.0.5 : the semantics for the access file have changed (check out README) +1.0.5 : it is now possible to disallow tklining of specific hosts (tumble) +1.0.6 : Added leading colons for the /squery commands (tumble) +1.0.6 : Added a hint concerning the distribution to the README +1.0.6 : it's now possible to decide whether a user needs to be opered or + not when accessing TkServ +1.0.7 : TkServ won't crash anymore if a bad lifetime is given (Tero) +1.0.8 : A few changes to make TkServ fit better into ircd/contrib. +1.0.8 : TkServ now sends out a hint when it receives an unknown cmd + (Fusion & viha) +1.0.9 : renamed the function logf due to a conflict in *BSD? (Virginie) +1.0.9 : General rename of some tkserv functions +1.2 : Password migration from cmd line to conf file (Earthpig) +1.2 : TkServ now daemonizes itself. (Earthpig) diff --git a/contrib/tkserv/CREDITS b/contrib/tkserv/CREDITS new file mode 100644 index 0000000..617fb16 --- /dev/null +++ b/contrib/tkserv/CREDITS @@ -0,0 +1,60 @@ +Thanks to the following people, who have contributed in one way or another +to the development of TkServ: + +- Andre 'koopal' Koopal + + beta testing + + default expiration + + removal of tklines before expiration (manual removal) + + password migration from config.h to cmd line + +- Asu 'primetime' Pala + + fix for BSDI + + IP recognition bug + + forgotten tkserv.access.example file + + hostnames in the restriction field of the access file + +- 'Szern' + + fix for Irix + + IPs in the restriction field + + wildcards in the u@h oper field of the access file + +- Michael 'Eumel' Neumayer + + colons are not allowed anymore outside the password parameter + + expired tklines do now get removed really automatically + +- Tero 'Tero' Saari + + RedHat Linux cludge + + no crashes anymore when a bad lifetime is given + +- Andrew ´Earthpig´ Snare + + password back to conf file (more secure) + + automatic daemonization + +- 'tumble' + + possibility to explicitly disallow specific hosts from getting tklined + + leading colons for the /squery commands in the README + +- Kristian 'Fusion' Bergmann & 'viha' + + Sending out of a hint when an unknown command is received + +- 'Virginie' + + rename of the logf function because of conflict under *BSD? + +- 'jbn' + + expiration of tklines / default expiration + +- The EPIC Software Labs + + for their nice ircII-EPIC client from which i took some networking + stuff, see http://www.snafu.de/~kl/epic/index.html for more about + epic + +- Kai 'Oswald' Seidler + + for his NoteServ, on which TkServ is based and which has helped me a + lot in making TkServ, see http://oswald.pages.de for more + +- Christophe 'syrk' Kalt and Vesa 'Vesa' Ruokonen + + for giving me the impulse to this kind of service :) + + +And finally thanks to all the Linux people out there for contributing +to the world's best OS! :-) diff --git a/contrib/tkserv/INSTALL b/contrib/tkserv/INSTALL new file mode 100644 index 0000000..9bc69bd --- /dev/null +++ b/contrib/tkserv/INSTALL @@ -0,0 +1,20 @@ +How to install TkServ +--------------------- + +Yes, there isn't any configure yet. That's why the compilation on some +machines could be difficult because you may have to include one or two +libraries by hand. I'll try to create a configure file in the future. + +Up to now, i've only compiled TkServ on Linux, Solaris and Irix. I hope you +won't get into trouble when trying to compile on another OS. But everyone +should be running Linux anyway. :-) + +So here we go: + +1. Unpack and untar the archive. (which you might already have done :) +2. RTFM. :-> +3. run "./configure" (if you haven't already done so) +3. Edit the tkconf.h file. +4. "make tkserv" + +Good luck, Kasi diff --git a/contrib/tkserv/README b/contrib/tkserv/README new file mode 100644 index 0000000..a7b7c47 --- /dev/null +++ b/contrib/tkserv/README @@ -0,0 +1,290 @@ +Welcome to TkServ ! +=+=+=+=+=+=+=+=+=+= + +This program is released under the GNU General Public License. +A copy of this license is included in the distribution. + +I) Introduction +--------------- + +TkServ is a so-called temporary k-line service. + +[If you don't know what a service is, consult the documentation which comes +along with the irc2.10.x package (if you don't know services, you shouldn't +be reading this anyway ;).] + +This is what TkServ does - roughly: On request, it adds a given k-line +pattern to the server's k-line list and (sooner or later, see below) then +removes it. The adding/removing is done via the ircd.conf file. + +The purpose/advantages of a temporary k-line service: + + - it facilitates the process of k-lining users + - added k-lines disappear automatically (see below) + - it allows _also_ remote users (only if they are listed in the access + file of the service - see below) to temp k-line users on the respective + server + - it allows people to specify a duration for each tkline + - it is more effective than /kill but practically as easy to use + - it could therefore act as a replacement for the /kill command - which in + fact is more or less its longtime goal... + + +II) Security concerns +--------------------- + +Of course, when allowing remote "access" to the ircd.conf file, the main +concern of most admins is security. Therefore, here's a list of the +procedures used by TkServ to ensure that only authorized users may add +temporary k-lines to the server's conf file [origin == the person who is +sending a request]: + +- the origin's user@host has to match one of the u@h's in the tkserv.access + file (case sensitive!) +- the origin has always to specify a password which has to match the + password that belongs to the corresponding user@host in the access file + (case sensitive!) +- the origin has to be opered, if you want to +- it is possible to allow an authorized user to only tkline given hostnames + or TLDs + +Especially the third point equals to strong security, because: Could you +imagine any cracker who has gained O: on some server, wasting his time on +trying to get access to a remote server's temp k-line list instead of +playing around with his O: ? See, neither could i. ;-) + + +III) Installation +----------------- + +A) Precondition + + The only thing you need in order to run TkServ is an "ircd.conf" file, + an "ircd.pid" file and an IRC server which has been compiled with + USE_SERVICES #define'd in the config.h file (!). + +B) Editing the configuration file (config.h) + + You have to change the following entries in the config file: + + TKSERV_ADMIN_NAME (your real name) + TKSERV_ADMIN_CONTACT (mail address) + TKSERV_ADMIN_OTHER (your nick, for example) + + TKSERV_NAME (the name of the service appearing on /SERVLIST) + TKSERV_DESC (a neato description :) + TKSERV_DIST (the distribution of the service) + +| A few words to the distribution of the service. Here are the pros & +| contras of a global TkServ from my point of view: +| +| [contra] It makes the /servlist become unnecessarily big and less handy +| [contra] You can detect also local services by /trace'ing a server +| [contra] You can access a local TkServ by setting up a special client +| on the concerned server (maybe with a special I: line) +| +| [pro] A global TkServ is more comfortable to use for remote users. +| [pro] If you want to see which server is running one (for e.g. to +| request access to it), you do only have to do a /servlist. + + TKSERV_PATH (the abs. path to your ircd.conf, no trailing slash please!) + TKSERV_LOGFILE (the abs. path to your tkserv logfile, no trailing slash) + TKSERV_ACCESSFILE (the abs. path to your tkserv access file, ditto) + + TKSERV_DEBUG (for debugging only, displayes traffic to standard output) + +C) Compiling the source + +TkServ will be compiled along with the irc server. + +D) Setting up the access file: tkserv.access + + If anyone should be authorized to use TkServ on your server, he/she has + to figure in the access file. The format of it is: + +| [!]<user@host.domain.tld><SPACE><password><SPACE>[<FQDN || IP>]<RETURN> +| +| Which means: +| [!]<user@host.domain.tld> <password> [<FQDN || IP>] +| +| A '!' before the u@h means that the specified user doesn't need to be +| opered when accessing TkServ. Before the FQDN/IP, it means that the user +| is not allowed to tkline that given FQDN/IP. See below. +| +| Examples: +| (1) foo@bar.com foo-pass +| (2) some@user.on.the.net some.passw1 *.net,207.128.* +| another@user.foo.com Akfdsv.df *netcom.com,*.ca +| you@get.the.picture.org ditto. *.org,dialup*.lamer.net,194.44.44.* +| oper@dialup*.dialup.net pwd1.2 *dialup.net,145.44.*,*.fr +| (3) !luser@doesnt.need.to.be.opered.org bleh !elite.org,*.org +| (4) !~luser@no.ident.no.oper.com yo *.com +| +| (1) Any oper who is running identd and whose userhost equals to +| foo@bar.com can tkline everyone if supplied password equals +| foo-pass. +| (2) Any oper with identd whose u@h equals to some@user.on.the.net +| can tkline everyone whose TLD is ".net" or who is IRCing within +| the IP subnet 207.128.*, if correct password is given. +| (3) Any luser (no need to be opered) whose u@h/passwd equals can tkline +| everyone whose TLD is ".org" except the host "elite.org" +| ("*@elite.org"). +| +| Generally, you should be aware of the fact that if you put something +| in the FQDN/IP field, then you automatically restrict the access. +| Therefore, you must then also indicate all the allowed FQDNs/IPs. +| +| The access routines are pretty flexible. So pay attention in what order +| you allow/disallow what. :) +| +| Other examples: +| !foo@bar.com foo-pass !*.net,*.com,!*.com +| some@user.on.the.net some.passw1 *.net,207.128.*,!127.0.0.* +| another@user.foo.com Akfdsv.df *netcom.com,!*trends.ca,*.ca +| +| Notice that if you allow "*.de" and after it you forbid "blah.de", +| this won't work. The oper will still be able to tkline blah.de since +| "*.de" appears before "!blah.de" in the access field. +| +| Are we confused, yet? ;-) + + For some other examples, refer to the tkserv.access.example file, which + is included in the package. + + The u@h field for the user can also contain wildcards, as you can see. + +| If you specify an FQDN (or several of them in a comma-separated +| list), the concerned user will only be allowed to tkline users from +| that FQDN(s). Everything is done via 'wildcard-matching' (if any). +| I.e. that "home.blah.de" matches only "*@home.blah.de". If you want +| to allow a whole TLD, you have to do this by putting "*.tld" in the +| access field. + +! An empty FQDN/IP field means that the concerned user can tkline everyone. ! + [Except *@* that is.] + +E) Setting up the S: line in your ircd.conf file + + If you're not yet familiar with S: lines, consult the documentation of + the ircd package. + + S:<host>:<password>:<name>:33554432:<class> + + <host> is the FQDN from which the service will connect to the server. + + The service type 33554432 is mandatory! Currently, TkServ will refuse + any other service type. [Actually, it won't, but it's good to think that + it will... ;-] + + The service class should refer to an existing class (according to the + documentation :). + +F) Starting TkServ + + The command line syntax of TkServ looks like this: + + tkserv <server> <port> <password> + or + tkserv <Unix domain socket> <password> + + Example: + + tkserv localhost 6667 my-serv.pass + + Where <server> is the address of your IRC server, <port> the port to + which TkServ will connect and <password> the password for the service. + +G) Adding temp k-klines (TKLINE) + + Provided that TkServ recognizes you, you can add temporary k-lines via + the TKLINE command, which has three different variants: + + (1) :TKLINE <password> <lifetime in hours> <user@host> <reason> + (2) :TKLINE <password> <user@host> <reason> + (3) :TKLINE <password> -1 <user@host> + + (1) adds a tkline for <u@h> with an expire time of <lifetime> hours and + with the reason <reason>. + (2) adds a tkline for <u@h> with the default expire time (2 hours) and + with the reason <reason>. + (3) removes any existing tklines found for <user@host>. + + Examples: + + (1) :TKLINE my.pass 5 lamer@lamers.org dont flood + (2) :TKLINE blah. *@foo.com stop spamming + (3) :TKLINE my.pass -1 lamer@lamers.org + + <lifetime> must be > 0 and < 168. + +| [If your client doesn't support SQUERY, the entire cmd line has to be: +| "/quote squery <name of tkserv> :tkline ...". If it does support it, +| then "/squery <name of tkserv> tkline ..." should do it.] +| +| [And yes, ircII-EPIC4 supports SQUERY and SERVLIST! ;-)] +| +| If a non-opered user tries to use TKLINE without having a matching entry +| in the access file, he gets "Only IRC-Operators may use this command" as +| an error message. This is not correct anymore, but i didn't bother to +| change it (since it may prevent kids from playing around with TkServ :). + +H) Online help/info + +TkServ does also have a little online help which is accessible via +"/squery <service name> help". + +I) Quitting the service + +To make TkServ quit IRC you have to send him the following SQUERY: + +QUIT <password> + +Where <password> corresponds to password that you indicated at startup. +Be aware that anyone who knows that password can make your TkServ quit. + +J) Debugging + +If you #define TKSERV_DEBUG in the config.h file, everything which is sent +to the server from the service and from the server to the service will be +displayed to the standard output. + + +IV) Misc, or what goes where + +TkServ will create the following permanent files in your ircd directory: + +ircd.conf.tkserv (backup of the ircd.conf file) +tkserv.log (TkServ's log file) + +The latter will contain most of the error messages (in case something goes +wrong - what we all don't hope ;) as well as logs of successful TKLINE +requests. + +The tkserv.access file has to be in the directory specified in the config.h +file. If no tkserv.access file is found, no one will be able to add temp +k-lines. + +Now and then you should zero your TkServ logfile because this won't happen +by itself. =) + + +V) Credits + +See the CREDITS file. + + +VI) Bugs, comments, suggestions... + +Send everything to kl@snafu.de or to Kasi@IRC. + + +VII) The TkServ-mailinglist + +There's now a mailinglist for TkServ out there. It is used for general +announcements (bugs, new releases, etc.) concerning TkServ. Since it's a +read-only mailinglist, it doesn't have much traffic. You can subscribe to +it by sending a mail to tkserv@kl.Snafu.DE with "subscribe" in the subject +or in the body of the mail. + + +Enjoy, -Kasi diff --git a/contrib/tkserv/proto.h b/contrib/tkserv/proto.h new file mode 100644 index 0000000..edf23b7 --- /dev/null +++ b/contrib/tkserv/proto.h @@ -0,0 +1,24 @@ +void sendto_server(char *buf, ...); +void sendto_user(char *text, ...); +void process_server_output(char *line); +void parse_server_output(char *buffer); +int server_output(int fd, char *buffer); + +void service_pong(void); +void service_notice(char **args); +void service_squery(char **args); +int service_userhost(char *args); +void squery_help(char **args); +void squery_tkline(char **args); +void squery_quit(char **args); + +void sendlog(char *text, ...); +char *ts(void); + +int is_opered(void); +int is_authorized(char *pwd, char *host); + +void exec_cmd(char *cmd, ...); +int add_tkline(char *host, char *user, char *reason, int lifetime); +int check_tklines(char *host, char *user, int lifetime); +void rehash(int what); diff --git a/contrib/tkserv/tkserv.access.example b/contrib/tkserv/tkserv.access.example new file mode 100644 index 0000000..4269c93 --- /dev/null +++ b/contrib/tkserv/tkserv.access.example @@ -0,0 +1,10 @@ +foo@bar.com foo.pass *netcom.com,*.net +someone@SomeOrg.org aldkf.23 eleet.org,165.55.45.* +~blah@ppp*.blah.de igh.pass +user@users.Online.net ukuk.ua1 +some@ip*.user.com blah 204.85.*,194.55.43.* +you.get@the.picture.com pass ppp*.lame.com,*.org,dialin*.whitehouse.gov,*.net,*.uk +disallow@something.com bleh !*.de,!*.fr,*.net,*.org,*.com,!195.144.45.* +disallow@another.host.fr yo !hugo.fr,!admin.irc.fr,*.fr,*.ca,195.55.66.* +!luser@who.doesnt.need.to.be.opered.de yeh *.de + diff --git a/contrib/tkserv/tkserv.c b/contrib/tkserv/tkserv.c new file mode 100644 index 0000000..92f281d --- /dev/null +++ b/contrib/tkserv/tkserv.c @@ -0,0 +1,1022 @@ +/* +** Powered by Linux. :-) +** +** Copyright (c) 1998 Kaspar 'Kasi' Landsberg, <kl@berlin.Snafu.DE> +** +** File : tkserv.c v1.2 +** Author : Kaspar 'Kasi' Landsberg, <kl@snafu.de> +** Desc. : Temporary K-line Service. +** For further info see the README file. +** Location : http://www.snafu.de/~kl/tkserv +** Usage : tkserv <server> <port> +** E.g. : tkserv localhost 6667 +** +** This program is distributed under the GNU General Public License 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 details. +** +** Note: The C version of this service is based on parts of the +** ircII-EPIC IRC client by the EPIC Software Labs and on +** the NoteServ service by Kai 'Oswald' Seidler - see +** http://oswald.pages.de for more about NoteServ. +** Thanks to both. =) +** +** PS: Casting rules the world! (doh) +*/ + +#include "os.h" +#undef strcasecmp +#include "config.h" +#include "tkconf.h" +#include "proto.h" + +/* Max. kill reason length */ +#define TKS_MAXKILLREASON 128 + +/* Used max. length for an absolute Unix path */ +#define TKS_MAXPATH 128 + +/* Max. buffer length (don't change this?) */ +#define TKS_MAXBUFFER 8192 + +/* don't change this either(?) */ +#define TKS_MAXARGS 250 + +/* The version information */ +#define TKS_VERSION "Hello, i'm TkServ v1.2." + +static char *nuh; +FILE *tks_logf; +int fd = -1, tklined = 0; + +/* +** Returns the current time in a formated way. +** Yes, "ts" stands for "time stamp". I know, +** this hurts, but i couldn't find any better +** description. ;-> +*/ +char *tks_ts(void) +{ + static char tempus[256]; + time_t now; + struct tm *loctime; + + /* Get the current time */ + now = time(NULL); + + /* Convert it to local time representation */ + loctime = localtime(&now); + + strftime(tempus, 256, "@%H:%M %m/%d", loctime); + + return(tempus); +} + +/* logging routine, with timestamps */ +void tks_log(char *text, ...) +{ + char txt[TKS_MAXBUFFER]; + va_list va; + + tks_logf = fopen(TKSERV_LOGFILE, "a"); + va_start(va, text); + vsprintf(txt, text, va); + + if (tks_logf != NULL) + fprintf(tks_logf, "%s %s\n", txt, tks_ts()); + else + { + perror(TKSERV_LOGFILE); + va_end(va); + return; + } + + va_end(va); + fclose(tks_logf); +} + +/* an optimized system() function */ +void exec_cmd(char *cmd, ...) +{ + char command[TKS_MAXBUFFER]; + va_list va; + + va_start(va, cmd); + vsprintf(command, cmd, va); + system(command); + va_end(va); +} + +/* sends a string (<= TKS_MAXBUFFER) to the server */ +void sendto_server(char *buf, ...) +{ + char buffer[TKS_MAXBUFFER]; + va_list va; + + va_start(va, buf); + vsprintf(buffer, buf, va); + write(fd, buffer, strlen(buffer)); + va_end(va); + +#ifdef TKSERV_DEBUG + printf("%s", buffer); +#endif +} + +/* sends a NOTICE to the SQUERY origin */ +void sendto_user(char *text, ...) +{ + char *nick, *ch; + char txt[TKS_MAXBUFFER]; + va_list va; + + nick = (char *) strdup(nuh); + ch = (char *) strchr(nick, '!'); + *ch = '\0'; + + va_start(va, text); + vsprintf(txt, text, va); + sendto_server("NOTICE %s :%s\n", nick, txt); + va_end(va); +} + +void process_server_output(char *line) +{ + char *ptr; + static char *args[TKS_MAXARGS]; + int i, argc = 0; + + while ((ptr = (char *) strchr(line, ' ')) && argc < TKS_MAXARGS) + { + args[argc] = line; + argc++; + *ptr = '\0'; + line = ptr + 1; + } + + args[argc] = line; + + for (i = argc + 1; i < TKS_MAXARGS; i++) + args[i] = ""; + + /* + ** After successfull registering, backup the ircd.conf file + ** and set the perms of the log file -- the easy way :) + */ + if ((*args[0] == ':') && (!strcmp(args[1], "SERVSET"))) + { + chmod(TKSERV_ACCESSFILE, S_IRUSR | S_IWRITE); + chmod(TKSERV_LOGFILE, S_IRUSR | S_IWRITE); + exec_cmd("cp "CPATH" "TKSERV_IRCD_CONFIG_BAK); + tks_log("Registration successful."); + } + + /* We do only react upon PINGs, SQUERYs and &NOTICES */ + if (!strcmp(args[0], "PING")) + service_pong(); + + if ((*args[0] == ':') && (!strcmp(args[1], "SQUERY"))) + service_squery(args); + + if (!strcmp(args[0], "&NOTICES")) + service_notice(args); +} + +/* reformats the server output */ +void parse_server_output(char *buffer) +{ + char *ch, buf[TKS_MAXBUFFER]; + static char tmp[TKS_MAXBUFFER]; + + /* server sent an empty line, so just return */ + if (!buffer && !*buffer) + return; + + while ((ch = (char *) strchr(buffer, '\n'))) + { + *ch = '\0'; + + if (*(ch - 1) == '\r') + *(ch - 1) == '\0'; + + sprintf(buf, "%s%s", tmp, buffer); + *tmp = '\0'; + process_server_output(buf); + buffer = ch + 1; + } + + if (*buffer) + strcpy(tmp, buffer); +} + +/* reads and returns output from the server */ +int server_output(int fd, char *buffer) +{ + int n = read(fd, buffer, TKS_MAXBUFFER); + buffer[n] = '\0'; + +#ifdef TKSERV_DEBUG + printf("%s", buffer); +#endif + + return(n); +} + +/* is the origin of the /squery opered? */ +int is_opered(void) +{ + char *nick, *ch, *token, *u_num, *userh; + char buffer[TKS_MAXBUFFER]; + + nick = (char *) strdup(nuh); + ch = (char *) strchr(nick, '!'); + *ch = '\0'; + sendto_server("USERHOST %s\n", nick); + + /* get the USERHOST reply (hopefully) */ + server_output(fd, buffer); + + token = (char *) strtok(buffer, " "); + token = (char *) strtok(NULL, " "); + u_num = (char *) strdup(token); + token = (char *) strtok(NULL, " "); + token = (char *) strtok(NULL, " "); + userh = (char *) strdup(token); + + /* if we got the USERHOST reply, perform the check */ + if (!strcmp(u_num, "302")) + { + char *ch; + ch = (char *) strchr(userh, '=') - 1; + + /* is the origin opered? */ + if (*ch == '*') + { + char *old_uh, *new_uh, *ch; + + old_uh = (char *) (strchr(nuh, '!') + 1); + new_uh = (char *) (strchr(userh, '=') + 2); + + if (ch = (char *) strchr(new_uh, '\r')) + *ch = '\0'; + + /* Does the u@h of the USERHOST reply correspond to the u@h of our origin? */ + if (!strcmp(old_uh, new_uh)) + return(1); + else + /* + ** race condition == we sent a USERHOST request and got the USERHHOST reply, + ** but this reply doesn't correspond to our origin of the SQUERY -- + ** this should never happen (but never say never ;) + */ + sendto_user("A race condition has occured -- please try again."); + } + } + else + /* + ** race condition == we sent a USERHOST request but the next message from + ** the server was not a USERHOST reply (usually due to lag) + */ + sendto_user("A race condition has occured -- please try again (and ignore the following error message)."); + + return(0); +} + +/* +** Look for an entry in the access file and +** see if the origin needs to be opered +*/ +int must_be_opered() +{ + FILE *fp; + + /* if the access file exists, check for auth */ + if ((fp = fopen(TKSERV_ACCESSFILE, "r")) != NULL) + { + char buffer[TKS_MAXBUFFER]; + char *access_uh, *token, *uh; + + while (fgets(buffer, TKS_MAXBUFFER, fp)) + { + uh = (char *) (strchr(nuh, '!') + 1); + token = (char *) strtok(buffer, " "); + + if (token) + access_uh = (char *) strdup(token); + + /* check for access file corruption */ + if (!access_uh) + { + tks_log("Corrupt access file. RTFM. :-)"); + + return(0); + } + + /* do we need an oper? */ + if (*access_uh == '!') + { + if (!fnmatch((char *) (strchr(access_uh, '!') + 1), uh, 0)) + return(0); + } + } + } + else + tks_log("%s not found.", TKSERV_ACCESSFILE); + + return(1); +} + +/* check whether origin is authorized to use the service */ +int is_authorized(char *pwd, char *host) +{ + FILE *fp; + + /* if the access file exists, check for authorization */ + if ((fp = fopen(TKSERV_ACCESSFILE, "r")) != NULL) + { + char buffer[TKS_MAXBUFFER]; + char *access_uh, *access_pwd; + char *token, *uh, *ch, *tlds = NULL; + + while (fgets(buffer, TKS_MAXBUFFER, fp)) + { + uh = (char *) (strchr(nuh, '!') + 1); + token = (char *) strtok(buffer, " "); + + if (token) + access_uh = (char *) strdup(token); + + if (*access_uh == '!') + access_uh = (char *) (strchr(access_uh, '!') + 1); + + token = (char *) strtok(NULL, " "); + + if (token) + access_pwd = (char *) strdup(token); + + token = (char *) strtok(NULL, " "); + + if (token) + tlds = (char *) strdup(token); + else + if (ch = (char *) strchr(access_pwd, '\n')) + *ch = '\0'; + + /* check for access file corruption */ + if (!access_uh || !access_pwd) + { + tks_log("Corrupt access file. RTFM. :-)"); + + return(0); + } + + /* check uh, pass and TLD */ + if (!fnmatch(access_uh, uh, 0)) + if (!strcmp(pwd, access_pwd)) + if (!tlds) + return(1); + else + { + char *token, *ch; + + /* blah */ + if (ch = (char *) strchr(tlds, '\n')) + *ch = '\0'; + + token = (char *) strtok(tlds, ","); + + /* '!' negates the given host/domain -> not allowed to tkline */ + if (*token == '!') + { + if (!fnmatch(((char *) strchr(token, '!') + 1), host, 0)) + { + sendto_user("You are not allowed to tkline \"%s\",", host); + return(0); + } + } + else if (!fnmatch(token, host, 0)) + return(1); + + /* walk thru the list */ + while (token = (char *) strtok(NULL, ",")) + { + if (*token == '!') + { + if (!fnmatch((char *) (strchr(token, '!') + 1), host, 0)) + { + sendto_user("You are not allowed to tkline \"%s\",", host); + return(0); + } + } + else if (!fnmatch(token, host, 0)) + return(1); + } + + sendto_user("You are not allowed to tkline \"%s\".", host); + } + } + + } + else + tks_log("%s not found.", TKSERV_ACCESSFILE); + + return(0); +} + +/*************** ircd.conf section ****************/ + +/* Appends new tklines to the ircd.conf file */ +int add_tkline(char *host, char *user, char *reason, int lifetime) +{ + FILE *iconf; + + if (iconf = fopen(CPATH, "a")) + { + time_t now; + + now = time(NULL); + fprintf(iconf, "K:%s:%s:%s:0 # %d %u tkserv\n", + host, reason, user, lifetime, now); + fclose(iconf); + rehash(1); + tks_log("K:%s:%s:%s:0 added for %d hour(s) by %s.", + host, reason, user, lifetime, nuh); + + return(1); + } + else + tks_log("Couldn't write to "CPATH); + + return(0); +} + +/* Check for expired tklines in the ircd.conf file */ +int check_tklines(char *host, char *user, int lifetime) +{ + FILE *iconf, *iconf_tmp; + + if ((iconf = fopen(CPATH, "r")) && (iconf_tmp = fopen(TKSERV_IRCD_CONFIG_TMP, "w"))) + { + int count = 0, found = 0; + time_t now; + char buffer[TKS_MAXBUFFER]; + char buf_tmp[TKS_MAXBUFFER]; + + /* just in case... */ + chmod(TKSERV_IRCD_CONFIG_TMP, S_IRUSR | S_IWRITE); + + now = time(NULL); + + while (fgets(buffer, TKS_MAXBUFFER, iconf)) + { + if ((*buffer != 'K') || (!strstr(buffer, "tkserv"))) + fprintf(iconf_tmp, buffer); + else + { + /* + ** If lifetime has a value of -1, look for matching + ** tklines and remove them. Otherwise, perform + ** the expiration check. + */ + if (lifetime == -1) + { + char *token; + char buf[TKS_MAXBUFFER]; + + strcpy(buf, buffer); + token = (char *) strtok(buf, ":"); + token = (char *) strtok(NULL, ":"); + + if (!strcasecmp(token, host)) + { + token = (char *) strtok(NULL, ":"); + token = (char *) strtok(NULL, ":"); + + if (!strcasecmp(token, user)) + { + count++; + found = 1; + } + else + fprintf(iconf_tmp, buffer); + } + else + fprintf(iconf_tmp, buffer); + } + else + { + char *ch, *token; + char buf[TKS_MAXBUFFER]; + unsigned long int lifetime, then; + + strcpy(buf, buffer); + ch = (char *) strrchr(buf, '#'); + token = (char *) strtok(ch, " "); + token = (char *) strtok(NULL, " "); + lifetime = strtoul(token, NULL, 0); + token = (char *) strtok(NULL, " "); + then = strtoul(token, NULL, 0); + + if (!(((now - then) / (60 * 60)) >= lifetime)) + fprintf(iconf_tmp, buffer); + else + found = 1; + } + } + } + + fclose(iconf); + fclose(iconf_tmp); + exec_cmd("cp %s %s", TKSERV_IRCD_CONFIG_TMP,CPATH); + unlink(TKSERV_IRCD_CONFIG_TMP); + + if (found) + rehash(-1); + + return(count); + } + else + tks_log("Error while checking for expired tklines..."); +} + +/* reloads the ircd.conf file -- the easy way */ +void rehash(int what) +{ + exec_cmd("kill -HUP `cat "PPATH"`"); + + if (what != -1) + tklined = what; +} + +/*************** end of ircd.conf section **************/ + +/*************** The service command section *************/ + +/* On PING, send PONG and check for expired tklines */ +void service_pong(void) +{ + sendto_server("PONG %s\n", TKSERV_NAME); + check_tklines(NULL, NULL, 0); +} + +/* +** If we get a rehash, tell the origin that the tklines are active/removed +** and check for expired tklines... +*/ +void service_notice(char **args) +{ + if ((!strcmp(args[4], "reloading") && (!strcmp(args[5], TKSERV_IRCD_CONF))) || + (!strcmp(args[3], "rehashing") && (!strcmp(args[4], "Server")))) + { + if (tklined) + { + sendto_user("TK-line%s.", (tklined > 1) ? "(s) removed" : " active"); + tklined = 0; + } + } +} + +/* parse the received SQUERY */ +void service_squery(char **args) +{ + char *cmd, *ch; + + nuh = (char *) strdup(args[0] + 1); + cmd = (char *) strdup(args[3] + 1); + + if (ch = (char *) strchr(cmd, '\r')) + *ch = '\0'; + + if (!strcasecmp(cmd, "admin")) + { + sendto_user(TKSERV_ADMIN_NAME); + sendto_user(TKSERV_ADMIN_CONTACT); + sendto_user(TKSERV_ADMIN_OTHER); + } + + else if (!strcasecmp(cmd, "help")) + squery_help(args); + + else if (!strcasecmp(cmd, "info")) + { + sendto_user("This service is featuring temporary k-lines."); + sendto_user("It's available at http://www.snafu.de/~kl/tkserv."); + } + + else if (!strcasecmp(cmd, "quit")) + squery_quit(args); + + else if (!strcasecmp(cmd, "tkline")) + squery_tkline(args); + + else if (!strcasecmp(cmd, "version")) + sendto_user(TKS_VERSION); + + else + sendto_user("Unknown command. Try HELP."); +} + +/* SQUERY HELP */ +void squery_help(char **args) +{ + char *ch, *help_about; + + help_about = args[4]; + + if (help_about && *help_about) + { + if (ch = (char *) strchr(help_about, '\r')) + *ch = '\0'; + + if (!strcasecmp(help_about, "admin")) + sendto_user("ADMIN shows you the administrative info for this service."); + + if (!strcasecmp(help_about, "help")) + sendto_user("HELP <command> shows you the help text for <command>."); + + if (!strcasecmp(help_about, "info")) + sendto_user("INFO shows you a short description about this service."); + + if (!strcasecmp(help_about, "tkline")) + { + sendto_user("TKLINE adds a temporary entry to the server's k-line list."); + sendto_user("TKLINE is a privileged command."); + } + + if (!strcasecmp(help_about, "version")) + sendto_user("VERSION shows you the version information of this service."); + } + else + { + sendto_user("Available commands:"); + sendto_user("HELP, INFO, VERSION, ADMIN, TKLINE."); + sendto_user("Send HELP <command> for further help."); + } +} + +/* SQUERY TKLINE */ +void squery_tkline(char **args) +{ + int lifetime, i; + char *passwd, *pattern, *host, *ch, *user = "*"; + char reason[TKS_MAXKILLREASON]; + + /* Before we go thru all this, make sure we don't waste our time... */ + if (must_be_opered()) + { + if (!is_opered()) + { + sendto_user("Only IRC-Operators may use this command."); + return; + } + } + + i = 5; + + while (args[i] && *args[i]) + { + if (strchr(args[i], ':')) + { + sendto_user("Colons are only allowed in the password."); + return; + } + + i++; + } + + if (args[5] && *args[5]) + { + if (isdigit(*args[5]) || (*args[5] == '-')) + lifetime = atoi(args[5]); + else + { + sendto_user("The lifetime may only contain digits."); + return; + } + } + else + { + sendto_user("Usage: TKLINE <password> [<lifetime>] <u@h> <reason>"); + return; + } + + /* TKLINE <pass> <lifetime> <u@h> <reason> */ + if ((lifetime > 0) && !(args[7] && *args[7])) + { + sendto_user("Usage: TKLINE <password> <lifetime> <u@h> <reason>"); + return; + } + + /* TKLINE <pass> <u@h> <reason> (default expiration) */ + if ((lifetime == 0) && !(args[6] && *args[6])) + { + sendto_user("Usage: TKLINE <password> <u@h> <reason>"); + return; + } + + /* TKLINE <pass> -1 <u@h> (removal of tklines) */ + if ((lifetime == -1) && !(args[6] && *args[6])) + { + sendto_user("Usage: TKLINE <password> -1 <u@h>"); + return; + } + + if ((lifetime >= 768) || (lifetime < -1)) + { + sendto_user("<lifetime> must be greater than 0 and less than 768."); + return; + } + + /* I don't want to get confused, so all this may be a bit redundant */ + + if (lifetime > 0) + { + passwd = args[4]; + pattern = args[6]; + strcpy(reason, args[7]); + i = 8; + + /* I know... */ + while(args[i] && *args[i]) + { + strncat(reason, " ", TKS_MAXKILLREASON - strlen(reason) - 1); + strncat(reason, args[i], TKS_MAXKILLREASON - strlen(reason) - 1); + i++; + } + + if (ch = (char *) strchr(reason, '\r')) + *ch = '\0'; + } + + if (lifetime == 0) + { + if (!(strchr(args[5], '@') || strchr(args[5], '*') || + strchr(args[5], '.'))) + { + sendto_user("<lifetime> must be greater than 0."); + return; + } + + passwd = args[4]; + lifetime = 2; /* Default lifetime */ + pattern = args[5]; + strcpy(reason, args[6]); + i = 7; + + while(args[i] && *args[i]) + { + strncat(reason, " ", TKS_MAXKILLREASON - strlen(reason) - 1); + strncat(reason, args[i], TKS_MAXKILLREASON - strlen(reason) - 1); + i++; + } + + if (ch = (char *) strchr(reason, '\r')) + *ch = '\0'; + } + + if (lifetime == -1) + { + passwd = args[4]; + pattern = args[6]; + + if (ch = (char *) strchr(pattern, '\r')) + *ch = '\0'; + } + + + /* Don't allow "*@*" and "*" in the pattern */ + if (!strcmp(pattern, "*@*") || !strcmp(pattern, "*")) + { + sendto_user("The pattern \"%s\" is not allowed.", pattern); + tks_log("%s tried to tkline/untkline \"%s\".", nuh, pattern); + return; + } + + /* Split the pattern up into username and hostname */ + if (ch = (char *) strchr(pattern, '@')) + { + host = (char *) (strchr(pattern, '@') + 1); + user = pattern; + *ch = '\0'; + } + else /* user defaults to "*" */ + host = pattern; + + /* + ** Make sure there's a dot in the hostname. + ** The reason for this being that i "need" a dot + ** later on and that i don't want to perform + ** extra checks whether it's there or not... + ** Call this lazyness, but it also makes the service faster. ;-) + */ + if (!strchr(host, '.')) + { + sendto_user("The hostname must contain at least one dot."); + return; + } + + if (!is_authorized(passwd, host)) + { + sendto_user("Authorization failed."); + return; + } + + if (lifetime == -1) + { + int i; + + i = check_tklines(host, user, lifetime); + sendto_user("%d tkline%sfor \"%s@%s\" found.", i, + (i > 1) ? "s " : " ", user, host); + + if (i > 0) + rehash(2); + } + else + if (!add_tkline(host, user, reason, lifetime)) + sendto_user("Error while trying to edit the "CPATH" file."); +} + +/* SQUERY QUIT +** Each time we receive a QUIT via SQUERY we check whether +** the supplied password matches the one in the conf file or not. +** If not, an error is sent out. If yes, we close the connection to +** the server. +*/ +void squery_quit(char **args) +{ + char *ch; + + if (ch = (char *) strchr(args[4], '\r')) + *ch = '\0'; + + if (!strcmp(args[4], TKSERV_PASSWORD)) + { + tks_log("Got QUIT from %s. Terminating.", nuh); + sendto_server("QUIT :Linux makes the world go round. :)\n"); + } + else + { + sendto_user("I refuse to QUIT. Have a look at the log to see why."); + tks_log("Got QUIT from %s with wrong password. Continuing.", nuh); + } +} + +/**************** End of service command section ***************/ + +int main(int argc, char *argv[]) +{ + + char *host, *port, buffer[TKS_MAXBUFFER], last_buf[TKS_MAXBUFFER]; + char tmp[TKS_MAXPATH]; + + int is_unix = (argv[1] && *argv[1] == '/'); + int sock_type = (is_unix) ? AF_UNIX : AF_INET; + int proto_type = SOCK_STREAM; + int eof = 0; + + struct in_addr LocalHostAddr; + struct sockaddr_in server; + struct sockaddr_in localaddr; + struct hostent *hp; + struct timeval timeout; + + fd_set read_set; + fd_set write_set; + + if ((is_unix) && (argc != 2)) + { + fprintf(stderr, "Usage: %s <server> <port>\n", argv[0]); + fprintf(stderr, " %s <Unix domain socket>\n", argv[0]); + exit(1); + } + else if (argc != 3) + { + fprintf(stderr, "Usage: %s <server> <port>\n", argv[0]); + fprintf(stderr, " %s <Unix domain socket>\n", argv[0]); + exit(1); + } + + if (!strcmp(TKSERV_DIST, "*")) + { + printf("Your service has a global distribution. Please make sure that\n"); + printf("you read the part about the service distribution in the README.\n"); + } + + tks_log("Welcome to TkServ. Lean back and enjoy the show..."); + + if ((fd = socket(sock_type, proto_type, 0)) < 0) + { + perror("socket"); + exit(1); + } + + /* copy the args into something more documentable */ + host = argv[1]; + + if (!is_unix) + port = argv[2]; + + /* Unix domain socket */ + if (is_unix) + { + struct sockaddr_un name; + memset(&name, 0, sizeof(struct sockaddr_un)); + name.sun_family = AF_UNIX; + strcpy(name.sun_path, host); + + if (connect(fd, (struct sockaddr *) &name, strlen(name.sun_path) + 2) == -1) + { + perror("connect"); + close(fd); + exit(1); + } + } + + memset(&localaddr, 0, sizeof(struct sockaddr_in)); + localaddr.sin_family = AF_INET; + localaddr.sin_addr = LocalHostAddr; + localaddr.sin_port = 0; + + if (bind(fd, (struct sockaddr *) &localaddr, sizeof(localaddr))) + { + perror("bind"); + close(fd); + exit(1); + } + + memset(&server, 0, sizeof(struct sockaddr_in)); + memset(&LocalHostAddr, 0, sizeof(LocalHostAddr)); + + if (!(hp = gethostbyname(host))) + { + perror("resolv"); + close(fd); + exit(1); + } + + memmove(&(server.sin_addr), hp->h_addr, hp->h_length); + memmove((void *) &LocalHostAddr, hp->h_addr, sizeof(LocalHostAddr)); + server.sin_family = AF_INET; + server.sin_port = htons(atoi(port)); + + if (connect(fd, (struct sockaddr *) &server, sizeof(server)) == -1) + { + perror("connect"); + exit(1); + } + + /* register the service with SERVICE_WANT_NOTICE */ + sendto_server("PASS %s\n", TKSERV_PASSWORD); + sendto_server("SERVICE %s localhost %s 33554432 0 :%s\n", TKSERV_NAME, TKSERV_DIST, TKSERV_DESC); + sendto_server("SERVSET 33619968\n"); + + timeout.tv_usec = 1000; + timeout.tv_sec = 10; + + /* daemonization... i'm sure it's not complete */ + switch (fork()) + { + case -1: + perror("fork()"); + exit(3); + case 0: + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + if (setsid() == -1) + exit(4); + break; + default: + return 0; + } + + /* listen for server output and parse it */ + while (!eof) + { + FD_ZERO(&read_set); + FD_ZERO(&write_set); + FD_SET(fd, &read_set); + + if (select(FD_SETSIZE, &read_set, &write_set, NULL, &timeout) == -1) + { + perror("select"); + } + + if (!server_output(fd, buffer)) + { + printf("Connection closed.\n"); + printf("Last server output was: %s\n", last_buf); + eof = 1; + } + + strcpy(last_buf, buffer); + parse_server_output(buffer); + } + + close(fd); + + exit(0); +} +/* eof */ diff --git a/doc/2.10-New b/doc/2.10-New new file mode 100644 index 0000000..8903783 --- /dev/null +++ b/doc/2.10-New @@ -0,0 +1,18 @@ + * +a (away) user mode + This user mode is used to propagate users' away status between + servers. + + * added channel mode +e (exceptions to bans). + * added channel mode +I (invitations). + * invites can now be used to override channel bans and limit. + * banned users cannot speak on channel without +o/+v. + * ! channels introduced (can't be collided); + A quite detailed technical description can be found on the web: + http://www.stealth.net/~kalt/irc/channel.html + + * NJOIN for 2.10 <-> 2.10 communication on connect bursts instead of + the combined JOIN/MODE introduced by 2.9 (and now deprecated) + + * a slave process is now used to authenticate incoming connections. + The slave's modular design makes it easy to add new authentication + modules. diff --git a/doc/2.9-New b/doc/2.9-New new file mode 100644 index 0000000..17d78e2 --- /dev/null +++ b/doc/2.9-New @@ -0,0 +1,60 @@ + * +a (anonymous) channel mode + + This channel mode is only allowed on &local channels. + + * +s user mode removed; + * &KILLS, &NOTICES, &ERRORS, &CHANNEL, &HASH, &NUMERICS, &SERVERS + channels created and used by the server for server notices + (comments on what goes where please) and dividing notices up this + way was better than using more user modes (they default to the + server being on them and +amnt); + + &KILLS : server and oper KILLS + &NOTICES : warnings and notices + &ERRORS : server errors + &LOCAL : notices concerning local clients. + &CHANNEL : fake modes + &HASH : hash tables growth + &NUMERICS : numerics received by the server + &SERVERS : servers joining and leaving the net + + * + channels reintroduced (can't have modes); + * Config doesn't prompt for cc/includes/libs; + * M-line doesn't define port, PORTNUM removed from config.h (must use + P-lines or use inetd); + * BIND 4.9.2 libresolv stuff included; + * USERHOST will return as many id's as requested. + * RECONNECT to pickup error'd sserver-server links (not activated) + * chooses next bigger prime for hash table sizes rather than + needing exact primes + * hash tables grow to suit rather than being static in size + * adaptive growth of sendq (suggested by msa) + * Server parameter in USER message tokenised betweem 2.9 servers + * whowas tables grow to suit rather than being static in size + * NICK+USER+UMODE combined into NICK for 2.9 <-> 2.9 communication + * MODE +ov and JOIN combined into JOIN for 2.9 <-> 2.9 communication + on connect bursts + * QUIT removed when possible for 2.9 <-> 2.9 communication on split + * autoconf'iscated ircd. + * userlog has single character appended to show cause of quit. + * i lines (user mode +r) + + i lined users have a restricted access: They are forbidden + MODE, KICK and TOPIC on #channels. They don't get channel + operator status when creating a #channel, and cannot + change their nickname once connected. + + * enhanced nick delay to prevent collisions + + The nickname of users splitting away is locked for 15 minutes, + and cannot be used by local clients. + + * channel history to prevent op riding + + A user with channel operator status on #foo splitting away + means that no local user can re-create the channel #foo during + the next 15 minutes. It doesn't stop users from using #foo as + as the channel is not empty. + +Some transition documentation from 2.8 to 2.9 version can be found in + http://www.irc.org/~irc/server/ diff --git a/doc/Authors b/doc/Authors new file mode 100644 index 0000000..07f8ee0 --- /dev/null +++ b/doc/Authors @@ -0,0 +1,180 @@ +/************************************************************************ + * IRC - Internet Relay Chat, doc/AUTHORS + * Copyright (C) 1990 + * + * AUTHORS FILE: + * This file attempts to remember all contributors to the IRC + * developement. Names can be only added this file, no name + * should ever be removed. This file must be included into all + * distributions of IRC and derived works. + * + * 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 email addresses listed in here may or may not be up to date. + +IRC was conceived of and written by Jarkko Oikarinen <jto@tolsun.oulu.fi>. +IRC was originally written in University of Oulu, Computing Center. +Jan 1991 - IRC 2.6 jto@tolsun.oulu.fi + - Multiple Channels and protocol changes + +Contributions were made by a cast of dozens, including the following: + +Markku Jarvinen <mta@tut.fi>: Emacs-like editing facility for the client + +Kimmo Suominen <kim@kannel.lut.fi>: HP-UX port + +Jeff Trim <jtrim@orion.cair.du.edu>: enhancements and advice + +Vijay Subramaniam <vijay@lll-winken.llnl.gov>: advice and ruthless publicity + +Karl Kleinpaste <karl@cis.ohio-state.edu>: user's manual + +Greg Lindahl <gl8f@virginia.edu>: AUTOMATON code, the Wumpus GM automaton, +myriad bug fixes + +Bill Wisner <wisner@hayes.fai.alaska.edu>: numerous bug fixes and code +enhancements + +Tom Davis <conslt16@zeus.unl.edu> and Tim Russell <russell@zeus.unl.edu>: +VMS modifications + +Markku Savela <msa@tel4.tel.vtt.fi>: advice, support, and being the +incentive to do some of our *own* coding. :) + +Tom Hopkins <hoppie@buengf.bu.edu>: bug fixes, quarantine lines, +consolidation of various patches. + +Christopher Davis <ckd@cs.bu.edu>: EFnet/Anet gateway coding, +many automata ;), documentation fixing. + +Helen Rose <hrose@cs.bu.edu>: documentation updating, and fixing. + +Tom Hinds <rocker@bucsf.bu.edu>: emacs client updating. + +Tim Miller <cerebus@bu-pub.bu.edu>: various server and client-breaking +features. + +Darren Reed <avalon@coombs.anu.edu.au>: various bug fixes and enhancements. +Introduced nickname and channelname hash tables into the server. + +The version 2.2 release was coordinated by Mike Bolotski +<mikeb@salmon.ee.ubc.ca>. + +The version 2.4 release was coordinated by Markku Savela and +Chelsea Ashley Dyerman + +The version 2.5.2 release was coordinated by Christopher Davis, Helen Rose, +and Tom Hopkins. + +The versions 2.6.2, 2.7, 2.8 and 2.9 releases were coordinated by Darren Reed. + +Contributions for the 2.8 release from the following people: +Matthew Green <phone@cairo.anu.edu.au> +Chuck Kane <ckane@ece.uiuc.edu> +Matt Lyle <matt@oc.com> +Vesa Ruokonen <ruokonen@lut.fi> + +Markku Savela <Markku.Savela@vtt.fi> / April 1990 +Fixed various bugs in 2.2PL1 release server (2.2msa.4) and changed +sockets to use non-blocking mode (2.2msa.9). [I have absolutely +nothing to do with clients :-] + +Chelsea Ashley Dyerman <chelsea@earth.cchem.berkeley.edu> / April 1990 +Rewrote the Makefiles, restructuring of source tree. Added libIrcd.a to +the Makefile macros, numerous reformatting of server text messages, and +added mkversion.sh to keep track of compilation statistics. Numerous +bug fixes and enhancements, and co-coordinator of the 2.4 release. + +jarlek@ifi.uio.no added mail functions to irc. + +Armin Gruner <gruner@informatik.tu-muenchen.de> / May, June 1990: +* Patched KILL-line feature for ircd.conf, works now. + Enhancement: Time intervals can be specified in passwd-field. + Result: KILL-Line is only active during these intervals +* Patched PRIVMSG handling, now OPER can specify masks for sending + private messages, advantage: msg to all at a specified server or host. +* Little tests on irc 2.5 alpha, fixed some little typos in client code. + Change: common/debug.c has been moved to ircd/s_debug.c, and a + irc/c_debug.c has been created, for the benefit that wrong server msg + are displayed if client does not recognize them. (strange, if a server + sends an 'unknown command', isn't it?) + +Tom Hopkins <hoppie@buengf.bu.edu> / September, October 1990: +* Patched msa's K lines for servers (Q lines). +* Consolidated several patches, including Stealth's logging patch. +* Fixed several minor bugs. +* Has done lots of other stuff that I can't seem to remember, but he + always works on code, so he has to have done alot more than three + lines worth. :) + +Various modifications, bugreports, cleanups and testing by: + +Hugo Calendar <hugo@ucscb.ucsc.edu> +Bo Adler <thumper@ugcs.caltech.edu> +Michael Sandrof <mike@uniteq.com> +Jon Solomon <jsol@cs.bu.edu> +Jan Peterson <jlp@hamblin.math.byu.edu> +Nathan Glasser <nathan@brokaw.lcs.mit.edu> +Helen Rose <hrose@kei.com> +Mike Pelletier <stealth@caen.engin.umich.edu> +Basalat Ali Raja <gwydion@gnu.ai.mit.edu> +Eric P. Scott <eps@toaster.sfsu.edu> +Dan Goodwin <fornax@wpi.wpi.edu> +Noah Friedman <friedman@ai.mit.edu> + +The 2.9 release brought many improvements to the protocol: adaptive growth +of sendq, hash tables, whowas table, extended NICK syntax, server tokens, +extended JOIN syntax, restricted usermode, nick and channel delay, +suppression of server-server QUITs during splits, suppression of usermode s.. + +Contributions for the 2.9 release from the following people: +Vesa Ruokonen <ruokonen@lut.fi>: V configuration lines, many bug fixes. +Christophe Kalt <kalt@stealth.net>: nick and channel delay, suppressed QUITs +during netsplits, many bug fixes. + +The versions 2.9.3, 2.9.4, 2.9.5 releases were coordinated by Christophe Kalt. + +Christophe Kalt <kalt@stealth.net>: server link compression using zlib, added +B configuration lines, extended IP bans and K lines to work on resolved hosts, +finished service code, virtual IP support. + +Various modifications, bugreports, cleanups and testing by: + +Chris Behrens <cbehrens@concentric.net> +Helmut Springer <delta@RUS.Uni-Stuttgart.DE> +Magnus Tjernstrom <d92-mtm@oook.campus.luth.se> +Olivier Galibert <Olivier.Galibert@mines.u-nancy.fr>: service code testing +Alain Nissen <Alain.Nissen@ulg.ac.be>: source tree restructuration, many +portability issues, new configure.in +Roar Thronæs <roart@nvg.ntnu.no> added IPv6 support + +The versions 2.10 releases were coordinated by Christophe Kalt. + +Christophe Kalt <kalt@stealth.net>: added channel modes e and I, designed and +implemented !channels, brought away status back to life, added NJOIN message, +made invitation override bans, wrote iauth. + +Various modifications, bugreports, cleanups and testing by: + +Helmut Springer <delta@RUS.Uni-Stuttgart.DE> +Michael 'Eumel' Neumayer <eumel@42.org> +Kurt Roeckx <Q@ping.be> cleaned up the compression code, among many things +Roar Thronæs <roart@nvg.ntnu.no> for more IPv6 work +Piotr Kucharski <chopin@sgh.waw.pl> for his work on the anti socks module +Michal Svoboda <svobodam@eva.vsp.cz> removed useless anUser linked list + +Thanks go to those persons not mentioned here who have added their advice, +opinions, and code to IRC. diff --git a/doc/BUGS b/doc/BUGS new file mode 100644 index 0000000..32e914f --- /dev/null +++ b/doc/BUGS @@ -0,0 +1,13 @@ +# @(#)$Id: BUGS,v 1.14 1999/03/07 22:59:31 kalt Exp $ + +The list is probably not as scary as it once was. +Anyone with some free time is welcome to fix those =) + +* The server still occasionnally crashes because of some bug + in the hash tables. (Vesa already fixed this bug several + times but it keeps crashing :^) + +* RECONNECT is still in some unknown state. (and deactivated + for various reasons) + +* The operator count showed by /LUSERS becomes incorrect (negative). diff --git a/doc/ChangeLog b/doc/ChangeLog new file mode 100644 index 0000000..9869542 --- /dev/null +++ b/doc/ChangeLog @@ -0,0 +1,1956 @@ +2.10.3 + +1999-08-13 Christophe Kalt + + * channel.c/match_modeid(): logic fix (reported by Michal Svoboda). + + * os.h: added YET ANOTHER KLUDGE for linux and poll(). + + * ircd.c: assume "-s" option in CYGWIN environment. + + * configure.in: update for CYGWIN environment. + +1999-08-13 Piotr Kucharski + + * mod_socks.c/socks_read(): allow more methods in socks5 check. + +1999-08-01 Piotr Kucharski + + * ircd.c/bad_command(): -d command line option no longer exists, + while -s was added. + +1999-07-28 Christophe Kalt + + * struct_def.h: IsChannelName() macro cannot use cid_ok() for the + client. + + * channel.c/m_njoin(): inverse condition prevented modes from + being sent to users and 2.9 servers. + +1999-07-27 Piotr Kucharski + + * s_id.c/cid_ok(): quite unfortunate typo which made joining + !channels impossible (from Michal Svoboda). + +1999-07-25 Christophe Kalt + + * channel.c: sanity checks to drop modes on +channels even when + received from servers (from Michal Svoboda). + + * struct_def.h, channel.c, s_id.c: added checks to ensure !name + validity (from Michal Svoboda). + +1999-07-23 Christophe Kalt + + * s_bsd.c/inetport(): fixed test for IPv6 (from KIKUCHI Takahiro). + + * ircd.c: + * better casting for sbrk() for OSF 4.0. + * setup_me(): fixed syntax for IPv6. + +1999-07-21 Piotr Kucharski + + * channel.c/set_mode(): send ERR_UNKNOWNMODE to 'mode O' issued + on non-!channels. + +1999-07-21 Christophe Kalt + + * s_misc.c/exit_one_client(): generate fake PARTs for users + quitting anonymous channels. + + * send.c/sendto_common_channels(): skip anonymous channels. + + * Makefile.in: ircdwatch needs clsupport.o which needs clmatch.o. + + * channel.c: added notices to warn users about +a channels. + +1999-07-20 Kurt Roeckx + + * channel.c: + * m_njoin: send +v for uniqops in the right case + * send_channel_members: send +v inside njoin for ops too + * m_invite: send back numerics if the channel doesn't exist + +1999-07-18 Piotr Kucharski + + * channel.c/set_mode(), m_kick(): send ERR_NOTONCHANNEL, not + ERR_CHANOPRIVSNEEDED, thus disable stealth secret channel probing; + furthermore, use rather sptr->name, not parv[0] in sending errors; + +1999-07-17 Christophe Kalt + + * ircd.c/setup_me(), s_bsd.c: fixed that really old bug about the + I line format to match connections received on the loopback + interface (from Eugene L. Vorokov). + + * configure.in: fixed previous changes about poll() (reported by + KIKUCHI Takahiro). + +1999-07-17 Kurt Roeckx + + * s_user.c/m_kill(): killer could end up < path + +1999-07-14 Christophe Kalt + + * configure.in, os.h: use ncurses.h (from KIKUCHI Takahiro). + + * configure.in: SunOS has poll(), but we don't want to use it + (reported by KIKUCHI Takahiro). + + * mod_lhex.c: replaced strtoul() with sscanf(). + +1999-07-11 Christophe Kalt + + * a_defines.h was missing support_def.h (from KIKUCHI Takahiro). + + * Makefile.in: ircdwatch.c uses strerror(), needs clsupport.o + (from KIKUCHI Takahiro). + + * config.h.dist, ircd.c, s_debug.c: renamed CONNECTTIMEOUT to + ACCEPTTIMEOUT, and changed from 30 to 90. + +1999-07-11 Piotr Kucharski + + * mod_socks.c: + * socks_write(): a typo made iauth allow open proxies and + caused a lot of BADPROTO warnings (from KIKUCHI Takahiro). + * socks_init(): buffer overflow with tmpbuf[] being too + small to hold too many iauth options (also from Takahiro). + +1999-07-09 Christophe Kalt + + * configure.in, os.h, s_bsd.c: IPv6 updates (from KIKUCHI Takahiro). + +1999-07-05 Christophe Kalt + + * s_bsd.c/read_message(): can't use iauth_options when USE_IAUTH + is undefined. + +1999-07-05 Piotr Kucharski + + * channel.c/m_invite(): invite to :-channels was sometimes + lost with no error. + +1999-07-04 Christophe Kalt + + * a_conf_def.h, a_conf.c, a_io.c: added the "timeout" option. + + * mod_socks.c: added PROXY_BADPROTO & OPT_PROTOCOL to + differentiate between unexpected and bad protocol. + + * s_id.c: fixed alphabet_id[] (noted by Michal Svoboda), and + rewrote some code. + +1999-07-04 Piotr Kucharski + + * s_user.c/m_nick(): fix performance bug introduced in code + preventing insidious collisions + + * mod_socks.c/socks_open_proxy(): now reports in logs versions + of open proxies found + +1999-07-02 Kurt Roeckx + + * configure.in, Makefile.in: Added -I for inet6. + +1999-07-02 Christophe Kalt + + * res.c/proc_answer(): portability fix from hybrid6. + + * send.c/sendto_match_butone(): finally looked closely at why this + was sending $*.mask to the wrong servers, fixed. + + * struct_def.h, send.c/sendto_match_butone(), list_ext.h, + list.c/make_client(), ircd.c/setup_me(), s_misc.c/exit_client(), + s_serv.c, s_service.c/m_service(), s_user.c/m_user(): removed old + code conditional to NO_USRTOP being undefined. + + * s_user.c: + * m_nick(): new delay on nicks to prevent insidious + collisions (from Piotr Kucharski). + * m_private(): dropped restrictions on mass msg/notices. + + * s_auth.c/read_authports(): can't call set_clean_username with + ->auth pointing to ->username (from Piotr Kucharski). + + * mod_socks.c: couple typos. + + * a_conf.c/conf_read(): ->popt wasn't initialized. + +1999-06-27 Christophe Kalt + + * s_misc.c/exit_one_client(): made BETTER_NDELAY a little more + friendly (from Piotr Kucharski). + + * a_io.c/sendto_ircd(): added error output in write error notice. + + * hash.c/hash_channel_name(): added shortname parameter to disable + guess and fix bug (From Q). + + * channel.c/m_join(): reject local user join for duplicates. + + * mod_socks.c: more options, less bugs (from Piotr Kucharski). + + * s_user.c: + * m_nick(): kill nicks introduced by server if parc != 8 + instead of simply sending a notice. + * register_user(): static variable wasn't declared as such. + + * ircd.c, s_serv.c: used mybasename(); + + * support_ext.h, support.c: added mybasename(); + +1999-06-20 Christophe Kalt + + * mod_socks.c: added code to allow checks for v5 as well as v4, + depending on configuration (from Piotr Kucharski). + + * configure.in, ircd.c/ircd_writetune(), s_serv.c/m_rehash(): use + basename, and check if it needs libgen. + + * channel.c/m_njoin(): simple optimization resulting from change + to sendto_match_servs_notv() below. + + * send_ext.h, send.c: sendto_serv_{not,}v and + sendto_match_servs_{not,}v now return an integer. + +1999-06-16 Christophe Kalt + + * iauth.c/main(): send version to ircd upon startup. + + * mod_rfc931.c/rfc931_work(): removed checks on weird chars, let + ircd deal with this. + + * s_auth.c: + * start_auth(): abort if getpeername() fails (problem + reported by Wolfgang Scherer). + * added set_clean_username(), used in read_iauth() and + read_authports(). + * read_iauth(): added o message (a->i). + * read_iauth(): added V message (a->i). + + * struct_def.h, s_serv.c: added SV_OLDSQUIT, and made m_squit() + smarter (ugh, it's a kludge). + +1999-06-07 Christophe Kalt + + * s_user.c: + * m_nick(): added notice to warn of NICK messages coming + from servers with parc != 8. + * register_user(): fixed unaccurate notices about iauth. + + * config.h.dist: increased HANGONRETRYDELAY & HANGONGOODLINK values. + +1999-06-06 Christophe Kalt + + * struct_def.h, send.c/sendto_match_butone(), list_ext.h, + list.c/make_client(), ircd.c/setup_me(), s_misc.c/exit_client(), + s_serv.c, s_service.c/m_service(), s_user.c/m_user(): added + reorder_client_list() and NO_USRTOP defines. This reduces memory + usage (Original code from Michal Svoboda). + + * channel.c/reop_channel(): desynched could be caused by server + reops (channel mode +r) (reported by Thomas Kuiper). + +1999-05-01 Christophe Kalt + + * s_conf_ext.h, s_conf.c, s_serv.c: added a new list for K/k lines + only as an easy way to improve overall performance. + + * service_def.h: updated SERVICE_MASK_ALL. + +1999-04-19 Christophe Kalt + + * channel.c/m_njoin(): need to use sendto_match_servs*(); duh! + + * send_ext.h, send.c: added sendto_match_servs_notv(). + + * s_serv.c/m_squit(): fixed logic in previous change. + + * packet.c/dopacket(): fixed uncompression code. + +1999-04-15 Christophe Kalt + + * service_def.h, channel.c/m_topic(), s_service.c/m_servset(): + added SERVICE_WANT_TOPIC. + + * s_serv.c/m_squit(): fixed serious and old bug that caused + servers to be removed from memory (but not dependants!!!) while + squit is going upstream. + + * s_debug.c/send_usage(): divide by zero bugfix (reported by Aaron + Campbell). + + * channel.c/m_njoin(): ignore channels with an invalid mask. + + * common/parse.c: extended MSG_NOU to include services. + +1999-04-10 Christophe Kalt + + * Makefile.in, a_conf_def.h, a_externs.h, a_conf.c, mod_lhex_ext.h, + mod_lhex.c: New module (from Andrew Snare). + + * s_debug.c: increased size of debugbuf[] to avoid overflows (from + Eugene L. Vorokov). + + * send.c/send_message(): catch more unlikely errors (from Eugene + L. Vorokov). + + * s_bsd.c/set_sock_opts(): silently ignore errors for SO_SNDLOWAT. + + * common/os.h: FreeBSD portability (from KIKUCHI Takahiro). + + * s_bsd.c/read_message(): + * debug notice format bugfix (from Q). + * INET6 fix (from KIKUCHI Takahiro). + + * s_conf.c: + * initconf(): allow service type to be in hex in the + configuration (from Thomas Kuiper). + * find_conf_flags(): case sensitivity fix (from Q). + +1999-03-19 Christophe Kalt + + * mod_socks.c/socks_work(): closed proxies would get rejected on + first attempt and accepted later as the "closed" status was in the + cache. + + * s_user.c/register_user(): fixed iauth failure notice timing bug. + +1999-03-13 Christophe Kalt + + * struct_def.h, ircd.c, s_auth.c, s_bsd.c, s_user_ext.h, s_user.c, + a_struct_def.h, iauth.c, a_conf.c, a_io.c: added XOPT_EARLYPARSE, + `P' message for iauth, `extinfo' option for iauth. + + * a_io.c/next_io(): if xxx_start() returns 1, count module as left. + +1999-03-11 Christophe Kalt + + * chkconf.c: + * finally shut off MyFree() redefinition warning. + * fixed undefined behaviour with ++ operator (effet de bord). + + * a_io.c/init_io(): bzero bugfix (reported by Tomas Edwardsson). + + * a_conf_def.h, a_conf.c: + * conf_err(): send conf errors to ircd as well. + * conf_match(): extended iauth.conf syntax for hostname + and IP matching. + * added conf_ipmask() to allow use of a.b.c.d/z format for IP. + + * configure.in: use "cc -Ae" on HPUX (reported by Jens Riecken). + + * ircd.c/main(): iauth's presence needs to be checked before + setting up the signal handlers. + +1999-03-09 Christophe Kalt + + * a_struct_def.h, a_conf_ext.h, a_conf_def.h, a_conf.c, a_io.c, + mod_pipe.c, mod_rfc931.c, mod_socks.c: rewrote next_io() and + conf_match() to use new more flexible logic. + + * os.h, a_conf.c, iauth.c, configure.in, Makefile.in, acconfig.h: + added DSM support. + +1999-03-08 Christophe Kalt + + * struct_def.h, a_conf.c, a_conf_ext.h, iauth.c, ircd.c, s_auth.c, + s_auth_ext.h, s_bsd.c, s_user.c, s_user_exit.c: added + XOPT_{REQUIRED,NOTIMEOUT,EXTWAIT}, added iauth_spawn counter; + removed iauth_required variable. + + * struct_def.h, s_auth.c, s_user.c: added FLAGS_DONEXAUTH to get + rid of the approximation from yesterday. + + * s_bsd.c/read_message(): use CLR_READ_EVENT() before modifying fd. + +1999-03-07 Christophe Kalt + + * res_comp.c: added missing prototypes. + + * struct_def.h, a_conf.c, a_conf_ext.h, iauth.c, s_auth_ext.h, + s_auth.c, s_user.c: added option to reject new user connections if + iauth is dead (approximate!). + + * struct_def.h, ircd.c, res.c, s_auth.c, s_bsd.c: removed all + references to {Set,Clear,Do}Access macros (unused for a LONG time). + + * ircd.c: + * check_pings(): fixed "immediate ping timeout" bug. + * main(): check for iauth's presence after changing [ug]id. + + * s_bsd.c/do_dns_async(): notify iauth when no PTR record is found. + + * Makefile.in: fix for M4 file path (Matthew Sullivan). + +1999-03-04 Christophe Kalt + + * ircd.c/io_loop(), s_bsd.c/start_iauth(): keep trying to restart + iauth (up to once every 90 seconds) to avoid being iauth-less. + + * struct_def.h, mod_socks.c, s_auth.c, s_user.c: added new message + type from iauth to ircd to allow denying connections without any + message sent to &AUTH; used by the socks module. + +1999-02-22 Christophe Kalt + + * s_err.c: RPL_TRACESERVICE changed to show values in hexadecimal + (from Thomas Kuiper). + + * s_service.c/m_service(): fixed error message. + +1999-02-20 Christophe Kalt + + * configure, configure.in, Makefile.in, config.h.dist, buildm4, + send.c, ircd.c, s_bsd.c, s_conf.c, s_misc.c, s_serv.c, s_user.c, + chkconf.c, a_conf.c, a_log.c: paths overhaul. + + * c_msg_ext.h, c_msg.c: fixed m_server() prototype. + +1999-02-19 Kurt Roeckx + + * packet.c/dopacket(), s_bsd.c/read_packet(): bugfix. + +1999-02-18 Christophe Kalt + + * res.c/proc_answer(): fixed T_PTR processing (problem reported by + Michal Svoboda). + + * channel.c: + * del_modeid(): bugfix when called with NULL. + * can_join(): readability (from Q). + + * s_serv.c/check_version(): + * removed code about 2.10.0[ab]*. + * never used NJOIN with 0209* servers (bugfix). + + * s_err.c: removed extraneous %s in RPL_UNIQOPIS. + +1999-02-09 Kurt Roeckx + + * hash.c/hash_find_channels(): cleanup. + + * ircd.c/main(), ircd_ext.h: various cleanups. + + * res_comp_ext.h: added prototype for ircd_getshort(). + + * s_bsd.c/read_message(): typo fix (=! -> !=). + + * s_conf.c/attach_conf(): stops detecting listen sockets as + clients from same IP address. + + * s_err.c: removed / from replies. + + * s_serv.c/m_links(): removed unused variable. + + * s_user.c/who_channel(): removed unused variables. + +1999-02-05 Christophe Kalt + + * match.c/match(): removed predictable if's (from Tero Jänkä). + + * s_serv.c/m_server_estab(): flush_connections() called once + during burst. + + * s_debug.c: updated. + + * ircd.c/io_loop(), s_bsd.c/read_message(), s_bsd_ext.h, config.h: + new logic inspired from irce, removed PREFER_SERVER. + + * s_bsd.c: + * added read_listeners(). + * set_sock_opts() now sets SO_SNDLOWAT. + * add_connection() now sends a message to client being + reject by the anti-clone crap. + + * send.c: added flush_fdary() function. + + * common_def.h, config.h, send.c: removed SENDQ_ALWAYS define, + simplified code for when it was undefined as it is only used by + the client now. + +2.10.2 + +1999-02-03 Christophe Kalt + + * mod_rfc931.c/rfc931_work(): get rid of any \n in replies. + + * a_io.c/parse_ircd(): when receiving a "DNS timeout" message, + inform ircd if we're already done (otherwise, it keeps waiting + until timeout). + + * s_bsd.c/completed_connection(): tell iauth not to wait for DNS + information for servers we connect to. + + * s_auth.c/read_iauth(): + * fixed "Garbage" notices to &AUTH. + * send E message to iauth when parsing garbage. + +1999-01-28 Christophe Kalt + + * s_serv.c/m_server_estab(): added notices to &DEBUG. + + * struct_def.h, s_auth.c: renamed MotdItem to LineItem and moved + around some defines. + + * s_bsd_ext.h: added missing ';' for utmp_open() definition. + + * channel.c/m_list(): !shortname now reports +p/+s channels (but + still hides member count and topic for +s channels). + + * match.c/match(): rearranged if test to suppress harmless read + overflow errors (reported by Insure++). + + * s_user.c/m_nick(): lp needs to be initialized (reported by Insure++). + + * hash.c/hash_find_channels(): bugfix (spottoed by Q). + + * mod_rfc931.c/rfc931_init(): fix for a silly bug (from Piotr). + +1999-01-19 Christophe Kalt + + * resolv_def.h, res_comp.c, res_init.c: updated (BIND 4.9.7-REL). + + * packet.c/dopacket(): don't call unzip_packet() without data at + beginning of connection only! (from Q). + + * numeric_def.h, s_err.c, channel.c: added numerics RPL_UNIQOPIS + (325), ERR_BANLISTFULL (478) and ERR_UNIQOPPRIVSNEEDED (485). + + * channel.c: + * m_njoin(): missing return value (reported by Insure++). + * m_mode(): use ERR_RESTRICTED for restricted clients. + * m_join(): it's now possible to create !!#foo if #foo exists. + * m_list(): now works for !shortname. + + * hash_ext.h, hash.c: added hash_find_channels(). + + * configure.in, os.h: + * update for autoconf 2.13. + * let's trust autoconf to decide to use poll() or not. + + * s_bsd.c: sendto_flags() doesn't exist, it's sendto_flag(). + + * mod_rfc931.c: + * stats weren't initialized. + * added undocumented "protocol" option (it's boring!). + + * mod_socks.c: + * fixed never occuring memory leak. + * improved stats (from Piotr Kucharski). + + * s_user_ext.h, s_user.c, s_service.c: added a parameter to + do_nick_name() [UID]. + +1999-01-12 Christophe Kalt + + * a_log_def.h, mod_pipe_ext.h, a_externs.h, mod_pipe.c, a_conf.c: + finally wrote the pipe module. + + * struct_def.h, a_conf_def.h, a_io_ext.h, iauth.c, mod_rfc931.c, + mod_socks.c, s_auth.c, s_auth_ext.h, s_misc.c: iauth now sends + statistics to ircd, shown by /stats t. + + * a_conf_def.h, a_conf.c, a_log_def.h, mod_socks.c: SOCKS module + overhaul: added caching, rewrote code to use v4 instead of v5, and + to be smarter (Based on work from Piotr Kucharski). + + * s_user.c: do_nick_name() now rejects "anonymous". + + * packet.c/dopacket(): don't call unzip_packet() without data. + + * channel.c: extension to del_modeid() from Kaspar Landsberg. + + * s_bsd.c: don't call dopacket() again for compressed links just + because the output buffer was filled up. + +1998-12-31 Christophe Kalt + + * ircd.c: removed extraneous flush_connections() call in io_loop(). + + * ircd.c, s_bsd.c, list.c, list_ext.h: removed unused 'active' code. + + * struct_def.h, parse.c: removed various unused aClient fields. + +1998-12-24 Christophe Kalt + + * s_service.c: using FLAGS_CBURST for services has too many + implications; reverted. + + * struct_def.h, s_bsd.c, s_zip.c: removed requirement for + inflate() to never fill up the uncompression output buffer, an + unlikely situation which is now dealt with. (mostly from Q). + +1998-12-21 Christophe Kalt + + + * s_user.c: + * [RFC] suppressed an error reply for notices in m_message(). + * server notices to +n channels were failing. (Reported by Q). + + * a_defines.h: INET6 fix for OSF (from Roar Thronæs). + + * os.h: INET6 fix for OSF (from Roar Thronæs). + + * channel.c: added check against 'duplicate joins' in m_njoin(). + +1998-12-14 Christophe Kalt + + * channel.c: + * yet another +a/+r fix in set_mode(). + * send_channel_modes() would occasionnally send duplicate + bans. (Reported by Robert Martin-Legene <robert@irc.ircnet.dk>) + + * iauth.c, a_io.c: added nonexistant INET6 code. + + * os.h, nameser_def.h, resolv_def.h: OSF portability fix from Roar + Thronæs. + + * s_auth.c: added missing INET6 code. (Roar Thronæs) + +1998-09-25 Christophe Kalt + + * configure.in: Check for IPv6 system type and update $LIBS (from + KIKUCHI Takahiro <kick@kyoto.wide.ad.jp>) + + * bsd.c, os.h, parse.c, struct_def.h, support.c, support_ext.h, + c_bsd.c, c_version.c, c_version_ext.h, irc.c, swear.c, channel.c, + chkconf.c, ircd.c, nameser_def.h, res.c, res_def.h, res_init.c, + resolv_def.h, s_auth.c, s_bsd.c, s_conf.c, s_debug.c, s_misc.c, + s_serv.c, s_user.c, acconfig.h, configure.in: merged 2.9.5+IPv6. + +1998-04-12 Christophe Kalt + + * configure.in, s_debug.c: vsyslog() isn't necessarely available + even if USE_STDARG is defined. (Digital Unix) + +1998-04-04 Christophe Kalt + + * c_version_ext.h, c_version.c, irc.c, swear.c: Digital Unix 4.0B + port (Roar Thronæs <roart@nvg.ntnu.no>) + +1998-12-12 Christophe Kalt + + * channel.c: +a/+r fix for !channels. + +1998-11-20 Christophe Kalt + + * irc.c: allocate me.info (fix by Helmut Franzke <hf@rp-online.de>). + +2.10.1 + +1998-11-12 Christophe Kalt + + * Doc references to @stealth.net changed to @irc.org. + + * s_serv.c: report_ping() now sends some extra info to &DEBUG. + + * s_bsd.c: send_ping() window set to 20 minutes (instead of 10), + and never close it. + +1998-11-03 Christophe Kalt + + * s_serv.c: changed m_trace() to only show unknowns to opers and + local clients. + + * a_io.c: fd remap processing bugfix (from Q@ping.be). + + * s_bsd.c: fixed ircd/iauth problem with servers ircd connects to. + +1998-10-31 Christophe Kalt + + * parse.c: reordered msgtab[]. + + * s_serv.c: added more restrictions to m_links(), m_stats() [t], + m_motd() and m_lusers() for remote clients. (*sigh*) + + * channel.c: fixed count_channels() not to count empty channels. + +1998-10-28 Christophe Kalt + + * s_user.c: optimized m_whois() (pointed out by several people). + + * s_user.c, channel.c: channel creator flag is now removed on -o. + + * channel.c: + * !channel creation is now done with !! rather than !#. + * fixed channel counters (affects /lusers & /stats z). + * m_njoin(): simple optimization. + +Sat Oct 10 18:55:38 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * a_io.c: don't TST_* if cldata[i].?fd <= 0 in loop_io(). + + * ircd.s, s_auth.c, s_bsd.c, s_bsd_ext.h: always attempt to + restart iauth in start_iauth() after receiving a SIGUSR1. + + * s_service.c: reverted part of last change. + + * s_user.c: last change introduced a bug. (typo, reported by N. Aust) + + * channel.c: fixed match_modeid() to handle remote clients + properly now that it's used from can_send(). + +Thu Oct 8 18:33:50 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * configure.in: always compile with -g flag, and never strip. + + * channel.c: + * renamed sub1_from_channel() to free_channel(). + * always send modes for empty channels during netjoin. + * fixed old (2.9.x) memory leak in collect_channel_garbage(). + + * s_id.c: + * linked list corruption bugfix in collect_chid(). + * added logic to avoid excessive caching in cache_chid(). + + * s_service.c: stdarg bugfix in check_service_butone (from O.G.). + +Sun Sep 27 15:12:53 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * s_user.c: prefix bugfix (reported by mrg). + +2.10.0p1 + +Fri Sep 25 22:21:06 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * channel.c: check for +r mode before calling reop_channel(). + +2.10.0 + +Wed Sep 23 19:55:14 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * configure.in, os.h: don't trust poll() to work if it exists. + + * channel.c: + * removed FULLV2_10 ifdef's + * don't send empty NJOIN in m_njoin() (Reported by Beeth). + + * channel.c, s_debug.c, config.h.dist: removed MIRC_KLUDGE. + + * chkconf.c: added warning about old V line format. + + * config.h.dist: OPER_DIE is now defined by default. + + * s_user.c: reverted last change, and hostnames are now truncated. + + * os.h: preprocessor syntax fix. + + * s_conf.c: stupid typo in match_ipmask(). + + * s_auth.c: added a new debugging notice. + + * s_debug.c: flags update. + + * ircd.c: + * added some debugging info in restart notice. + * changed strdup() in mystrdup() (from Andrew Snare). + +Sun Sep 20 15:22:25 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * os.h, configure.in: configure now checks for poll() existence to + decide if it should be used. + + * res_init.c, s_conf.c: strncpy() bugfixes (from Q). + + * s_auth.c, mod_rfc931.c: '[' is no longer allowed in ident replies. + + * channel.c: don't let chanops set +a on !channels. + + * a_io.c: (weirdbug)fix. + + * s_err.c: numeric 004 update. + + * s_user.c: connections rejected by iauth are now shown as K-lined + in &LOCAL. + + * s_bsd.c: new PASS syntax (Q). + +Sun Sep 13 20:32:08 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * config.h.dist, ircd.c: removed MYNAME. + + * Makefile.in, config.h.dist: SPATH/APATH cleanup. + + * parse.c: ABW fix (Leon Brouwers <leonb@sci.kun.nl> and purify). + +Sat Sep 12 18:53:39 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * ircd.c, s_bsd.c: SIGCHLD handling code to avoid zombies. + + * s_bsd.c: + * udpfd used in place of adfd in in read_message(). + * silently deal with linux accept() way of life. + + * a_io.c: loop_io() bugfix for select() systems. + + * ircd.c: + * me.info from ircd.conf was overridden in setup_me(). + * server_reboot() created a zombie. + + * s_user.c: allow servers to speak on channels (reported by Q). + + * channel.c: + * NJOIN bugfix related to unique ops (reported by Q). + * removed old core from msa. + + * various little cleanups. + + * res.c: buffer overflow fix. (thanks to Leon Brouwers + <leonb@sci.kun.nl> and purify) + +Tue Sep 8 21:23:27 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * s_user.c: user mode +a propagation bugfix. + + * ircd.c: die immediately if no listener exists after reading the conf. + + * send_ext.h, send.c, channel.c: backward compatibility fix for eI + channel modes (added sendto_match_servs_v()). + +Mon Sep 7 18:03:34 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * s_bsd.c: inversed test for -s in start_iauth(). + + * channel.c: + * keys starting with ':' don't propagate correctly. + * m_njoin() didn't send modes properly to clients. + + * s_serv.c: + * slightly changed the PASS syntax again. + * 2.10 alphas didn't recognize peers as such (reported by Q). + +Sun Aug 23 22:16:40 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * struct_def.h, ircd.c, list.c, list_ext.h, s_conf.c, s_serv.c, + s_service.c, s_user.c: aClient's info is now dynamically allocated + to overcome server handshake limitations. + +Sat Aug 22 15:20:10 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * channel.c: fixed ^G bug (only triggered in channel creation) + + * struct_def.h, channel.c, s_err.c, s_user.c: AWAY is back. + +Sun Aug 16 16:01:15 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * ircd.c:, s_bsd.c: added -s switch. + +Sat Aug 8 14:21:20 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * s_serv.c: Roger's diff broke compression. (reported by Andre Koopal) + + * Makefile.in: iauth didn't know where to find zlib.h (reported + by delta) + + * a_log.c: typos in parameter names (reported by delta). + +Fri Aug 7 23:54:10 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * mod_rfc931.c: added sanity check on replies. + +Fri Aug 7 00:03:45 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * mod_rfc931.c: read RFC 1413 and fixed the reply parser. + + * numeric_def.h, s_err.c, s_auth_ext.h, s_auth.c, s_serv.c: added + /stats a to show iauth's configuation. + + * s_auth.c, a_*.[ch], mod_*.c: + * SIGUSR2 will cause iauth to close and reopen log file(s). + * worked around delayed messages from the iauth caused by + ircd's fd remapping habit. + * reduced memory usage by dynamically allocating `inbuffer'. + * added G message (a->i). + * added E message (i->a) and cleaned up errors messages in + parse_ircd(). + * added a/A messages (a->i) to transmist configuration. + * revisited next_io() and hopefully fixed the logic. + + * ircd.c, res.c, s_auth.c, s_auth_ext.h, s_bsd.c, s_user.c: + * stdarg'ized sendto_iauth(). + * iauth is now automatically restarted. + * fixed bcopy() length in read_iauth(). + * added notices to track the "" username bug. + +Tue Aug 4 21:43:53 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * a_io.c: numerous bug fixes.. + + * mod_rfc931.c: fix to prevent crash when receiving data from + broken ident servers. + + * a_conf.c, a_conf_def.h, a_externs.h, a_log_def.h: added module + `socks'. (Based on a 2.9.5 diff from Jonathan Chapman) + + * a_log.c: added timestamps to `auth' log. + + * s_misc.c: EXITC_AREF is a special case like EXITC_REF. + + * parse.c: penalty bugfix. + + * ircd.c, s_auth.c, s_bsd.c, s_bsd_ext.h: + * cleaned up iauth startup procedure, added start_iauth() + which is called upon SIGUSR1. + * various fixes in read_iauth(). + +Sun Aug 2 18:34:20 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * s_mist_ext.h, s_misc.c, support_ext.h, support.c: moved + myctime() from s_misc.c to support.c. + + * s_bsd.c, a_io.c: added `R' message from ircd to iauth. + + * s_serv.c: updated check_version() not to use NJOIN with 2.9.5 links. + + * parse.c: restricted SQUERY to users. + + * channel.c: + * m_njoin(): conversion bugfix (Reported by Q). + * added FULLV2_10 #if's. + + * struct_def.h, channel.c, s_err.c, s_misc.c: added channel mode `r'. + + * send.c: reference to NULL pointer in sendto_match_servs() + (Reported by Core). + + * sys_def.c, chkconf.c: MyFree() redefinitions (from Core). + + * Makefile.in: "make install-server" path problems. + +Sun Jul 19 15:32:48 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * s_conf.c, ircd.c: unitialized K line comment in check_pings(). + + * channel.c: + * beI modes to multiple channels were corrupted. + * mode parameters starting with : don't propagate correctly. + * !channel creation propagation was broken (reported by Eumel). + + * send.c, struct_def.h, channel.s, res.c, ircd.c, s_auth.c, + s_auth_ext.h, s_bsd.c, s_bsd_ext.h, s_conf.c, s_user.c, + Makefile.in, config.h.dist: added iauth. + +Fri Jun 12 19:00:03 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * ircd.c: fix for inetd support (from Jonathan Chapman + <jonathan@clover.net>). + + * parse.c, s_debug.c: more LOCOP_* fixes (from Michael Neumayer). + + * s_user.c: oper counter bugfix (from Magnus Tjernstrom). + + * channel.c: + * fixed join #a,#b,.. desynch bug (reported by viha@vip.fi). + * fixed netjoin +p/+s desynch problem (same). + +Sun May 31 14:18:41 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * send.c, channel.c: '-' leftovers (Michael Neumayer <eumel@42.org>). + +Mon May 25 15:13:51 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * struct_def.h, channel.c, hash.c, s_misc.c: changed new channels + prefix to ! (instead of -). + + * parse.c: undefining LOCOP_* had no effect (reported by Eumel). + + * s_service.c: SERVICE_WANT_OPER burst fix (from Jonathan Chapman). + + * s_bsd.c: SO_LINGER patch (from Andrew Snare <ajs@pigpond.com>). + + * configure.in: better logic for --resconf. + + * channel.c: + * m_invite() fix for &channels. + * add_modeid() always used RPL_BANLIST. + * bIe modes coming from a server were rejected + add_modeid() if another mode with the same pattern existed. + + * c_debug_ext.h, c_debug.c, chkconf.c, s_misc.c, s_zip.c: fixes + for DEBUGMODE (from Andrew Snare <ajs@pigpond.com> & Magnus + Tjernstrom <d92-mtm@ludd.luth.se>) + + * hash.c: bigger_prime() useless optimization from Magnus :-) + +Tue May 5 19:26:25 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * config.h.dist, Makefile.in, struct_def.h, s_externs.h, send.c, + channel.c, hash.c, s_debug.c, s_err.c, s_misc.c, s_serv.c, + s_user.c: implemented new channels. + + * struct_def.h, parse.c, channel.c, ircd.c, s_debug.c, s_misc.c, + s_serv.c, s_user.c, whowas.c, config.h.dist: replaced BIG_NET #define. + +Fri Apr 24 20:30:21 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * irc.c: missing refresh() (from Dave Hill <ddhill@zk3.dec.com>). + + * s_conf.c, s_service.c: portability fixes from Avalon. + + * channel.c, s_user.c: adapted undernet's Bquiet. + +Sun Apr 5 17:50:08 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * configure, configure.in, config.h.dist: added --logdir option. + + * s_serv.c: + * moved user wallops from #wallops to +wallops. + * stricter m_server() check for unregistered users. + + * send.c: wallops were sent to services and unregistered clients. + +Sat Apr 4 19:05:26 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * struct_def.h, packet.c, s_bsd.c: (never triggered) link + compression bugfix (Roger Espel Llima <espel@llaic.u-clermont1.fr>). + + * config.h.dist, ircd.c, s_debug.c: added PREFER_SERVER #define. + + * s_user.c: + * m_oper() notice bug fix (Michael 'Eumel' Neumayer). + * completely disabled AWAY. + + * struct_def.h, parse.c, channel.c, ircd.c, s_debug.c, s_misc.c, + s_serv.c, s_user.c, whowas.c, config.h.dist: added BIG_NET #define. + + * s_misc.c; Y2K fix. + +Tue Mar 31 18:52:41 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * s_serv.c: removed now obsolete USE_NJOIN. + + * numeric_def.h, struct_def.h, channel.c, s_debug.c, s_err.c, + s_serv.c: added channel modes +e (EFnet's exceptions to bans) and + +I (invitations); raised MAXBANS (should be renamed) to 30. + + * support.c: extended make_version(). + + * channel.c: + * notify user when a ban is rejected because "redundant". + * /invite (from chanop) now overrides bans & limit. + + * s_debug.c, s_serv.c: /stats r no longer restricted to DEBUGMODE. + + * s_bsd.c: getrlimit()/setrlimit() is now used regardless of + poll() availibility. + +Sun Mar 22 14:01:24 1998 Christophe Kalt <kalt@millennium.stealth.net> + + * channel.c: MIRC_KLUDGE sent bogus modes on channel creation. + + * os.h, support.c, s_bsd.c: CYGWIN32 cleanup from Dave Miller. + + * s_user.c: hunt_server() cleanup. + + * s_conf.c: match_ipmask() choked on a.b.c.d/z (reported by Helmut + Springer <delta@RUS.Uni-Stuttgart.DE>). + +2.9.5 + +Tue Feb 17 21:25:02 1998 Christophe Kalt + + * s_bsd.c: w32 doesn't have a working fork(). + + * ircd.c: deal with "getpwuid(getuid())" returning NULL. + + * configure.in, os.h, support.c: use our own truncate() when + needed (CYGWIN32), and CYGWIN32 portability. (Thanks to Dave + Miller <yahoo@molalla.net>). + + * config.guess: update. + + * s_user.c: broadcast restriction wasn't right (Yegg). + + * send.c, ircd.c: removed noisy debugging notices. + +Sat Feb 7 09:21:52 1998 Christophe Kalt + + * s_user.c: + * oper log is now more verbose. + * broadcast messages/notices are now less restricted. + + * hash.c: nitpicking (from Magnus Tjernstrom). + + * configure.in: quoting cleanup (from Alain). + + * send_ext.h, s_debug.h: STDARG prototyping cleanup (from Alain). + +Fri Jan 23 17:39:17 1998 Christophe Kalt + + * os.h: linux 2.1 implements poll() but the header files are a + mess (what did you expect?), kludge to get it work (from Vesa). + + * channel.c: fixes related to MIRC_KLUDGE. + + * s_conf.c: + * find_kill() fix and cleanup (mostly from Vesa). + * find_bounce() stricter check and fix (from Vesa). + + * parse.c: m_njoin() is only used by the server. + +Fri Jan 23 17:38:36 1998 Christophe Kalt + + * channel.c: + * buffer overflow fix. + * bugfix from Avalon. + * join/invite were propagated for &channels. (reported by DLR) + * invite/kick were propagated beyond masks. (reported by DLR) + * multiple kicks could desynch channels. + + * s_user.c: stricter check on unregistered NICK changes (Avalon). + + * hash.c: hash_find_server() didn't handle z.stealth.net (1 + letter) masked by *.stealth.net (DLR). + + * msg_def.h, struct_def.h, channel_ext.h, parse.c, channel.c, + s_serv.c: added send_channel_members() and m_njoin(). + + * send_ext.h, send.c: added sendto_serv_notv(). + + * buidm4: yet another m4 booboo. (fix from Mario) + +Wed Jan 7 11:40:59 1998 Christophe Kalt + + * s_user.c: strncpy() lameness. + + * s_conf.c: added match_ipmask() (from Vesa). + + * configure.in, send_ext.h: "checking for working stdarg" always + failed because of a quoting problem. + +Thu Dec 18 21:48:18 1997 Christophe Kalt + + * channel.c: abusive usage of /names now forbidden. + + * class.c: imposed a minimum of 60 seconds for connect frequencies. + + * struct_def.h, s_misc.c, s_serv.c: check_link() tuning and statistics. + +Tue Dec 16 17:12:16 1997 Christophe Kalt + + * s_conf.c: finished D lines. + + * numeric_def.h, struct_def.h, list.c, s_err.c, s_serv.c: added + check_link() to prevent server links from being flooded by replies + to user requests. + + * s_bsd.c: try to prevent the server from flooding with UDP pings. + + * channel.c: #foo:*.tld modes were always sent during the burst. + +Wed Nov 12 21:02:15 1997 Christophe Kalt + + * struct_def.h, s_conf_ext.h, s_conf.c, ircd.c, chkconf.c, + numeric_def.h, s_err.c , s_serv.c: added D configuration + lines. (/stats h) + + * send.c, s_service.c: allocate more dbufs during a service burst + if needed. + + * channel.c: cosmetics, and fixed the use of MAXPENALTY in m_kick(). + + * s_debug.c: too many parameters in a call to sendto_one(). + +2.9.4 + +Sat Oct 18 09:37:33 1997 Christophe Kalt + + * setup.h.in, configure.in: (Alain Nissen) + * additional header files checked. + * non-blocking system test fixed. + + * os.h: curses/termcap stuff is now only used for the client (AN). + + * swear_ext.h, swear.c: portability issues (Alain Nissen). + + * c_bsd.c, s_bsd.c, os.h: SELECT_FDSET_TYPE (defined in os.h) used + as pointer type in select() calls; HPUX compilation problem + fixed. (Alain Nissen) + + * buildm4: typo & missing quote. (again!) + +Fri Oct 10 23:48:25 1997 Christophe Kalt + + * s_serv.c: improved m_die() and m_restart() in case a service is + used for user log. + + * os.h, acconfig.h, configure.in, res.c, s_bsd.c: (Alain Nissen) + * kludge to deal with broken hostent declaration in + netdb.h on some linux systems. + * test for sigaction & sigset functions added back; signal + implementation test fixed. + + * s_conf.c: + * more explicit K line message when reason specified in + ircd.conf. + * extended I lines syntax. + + * s_service_ext.h, s_service.c, s_misc.c: faster split handling is + possible now that 2.8.x protocol is history. + + * channel.c: + * m_join() was unefficient on net joins. + * MIRC_KLUDGE would never show +ov modes. + + * s_user.c: + * services can now send to channels (if the modes allow it). + * prefixes for restricted connections were gone. + + * buildm4: missing quote. + +2.9.4b + +Wed Oct 1 21:57:45 1997 Christophe Kalt + + * chkconf.c: added knowledge of B lines. + + * s_debug.c: more info on dbufs for better tuning. + + * channel.c: bans on IP are now matched against resolving clients. + + * s_conf.c: K lines on IP can now be matched against resolving clients. + + * buildm4: update for Y and K line macros, and added macros for + B,V,i and k lines (Mario Holbe). + + * s_conf.c: Y global limit per host didn't work. + +Wed Sep 24 18:25:45 1997 Christophe Kalt + + * acconfig.h, configure.in, setup.h.in, resolv_def.h, res_init.c: + added --resconf=FILE option to configure (Alain Nissen). + + * s_conf.c: fixed bug with Y limits. + +Tue Sep 23 11:36:30 1997 Christophe Kalt + + * common_def.h: added CHKCONF_COMPILE statement. + + * bsd_ext.h: incorrect declaration for writeb. + + * support_ext.h, support.c: dumpcore() was broken. + + * class_def.h, class_ext.h, class.c, s_conf.c, s_err.c: it's now + possible to combine a limit per host and per user@host for the + same class. + + * s_user.c: + * RPL_ENDOFWHO wasn't correct. + * who_find() / m_whois() didn't always respect +a mode. + * @ restriction in username could be bypassed. + * unlikely but nonetheless possible ghost generation. + + * ircd.c: setgid() was called after setuid() (reported by Nicole + Haywood <kole@mail.usyd.edu.au>) + + * parse.c: avoid a match() call if possible. + +Sun Sep 14 19:44:27 1997 Christophe Kalt + + * ircd.c: redundant/useless code commented out. + + * struct_def.h, parse.c, s_err.c, s_serv.c: `stats m' is more verbose. + + * os.h, Makefile.in: zlib.h was missing from includes. + + * s_user.c: 2 fixes (a NULL pointer, and a non reinitialized one). + +Thu Sep 11 21:43:20 1997 Christophe Kalt + + * class_def.h, class_ext.h, class.c, s_bsd.c, s_conf.c, s_err.c, + s_user.c: added 2 fields to Y lines and implemented [u@]h global + limits. + + * service_def.h, channel.c, s_service.c: added SERVICE_WANT_VCHANNEL. + + * channel.c: server channels now have a topic. + + * s_conf.c: negative class numbers are now forbidden. + + * s_conf_ext.h, s_conf.c, s_bsd.c: new B lines format. + +Sun Sep 7 20:02:50 1997 Christophe Kalt + + * s_conf.c: B lines now catch "unauthorized connections". + + * s_user.c: m_who() limit wasn't coded. fixed this and rewrote + m_who() because recursivity and penalty don't go together. + + * s_err.c: REPL_SERVLIST type field is now in hexa. + + * service_def.h, send.c, s_misc.c, s_user.c: extended services + capabilities so they can do logging. + + * s_serv.c, s_user.c: added MD5 support for crypt() (from Urvos Juvan). + + * res.c: hostnames containing * or ? are now rejected. + + * s_conf.c: service type field stripped from optional bits (in S + lines). + + * s_serv.c: server token wasn't sent to services in m_server_estab(). + + * s_service.c: SERVICE_WANT_PREFIX wasn't honored by m_squery(). + + * struct_def.h, parse.c, s_serv.c, s_user.c: + * added MyService() macro and updated several tests. + * next_client() was ignoring services. + +Tue Aug 19 08:38:54 1997 Christophe Kalt + + * channel.c: m_names() could still have a truncated reply. + + * more cleaning from Alain.Nissen@ulg.ac.be: + + * struct_def.h, bsd.c, s_bsd.c: removed references to "pyr". + * res_comp.c: removed res_getshort() [never used]. + * removed all references to VMS. + +Mon Aug 11 13:34:15 1997 Christophe Kalt + + * The following changes are from Alain.Nissen@ulg.ac.be + + * all files (in short): + * include/ was removed. + * all .c have a corresponding _ext.h to declare external + variables and functions. + * [sc]_externs.h are #includes *_ext.h. + * [sc]_defines.h are #includes *_def.h. + * all .c have the same list of #include. + * os.h has all system #includes and portability tests. + + * Also, several bug and portability fixes: + + * c_bsd.c: move renamed in tcap_move (portability). + * c_msg.c: + * added test on DOCURSES before including it. + * various casts. + * edit.c: + * return type of suspend_irc() changed to RETSIGTYPE. + * added int argument to suspend_irc(). + * use of signal(SIGTSTP,...) now depends on + whether the signal exists rather than the OS. + * help.c: helplist rewritten properly. + * irc.c: + * strdup() replaced with mystrdup(). + * do_log() takes 2 arguments. + * return type of quit_intr() changed to RETSIGTYPE. + * added int argument to quit_intr(). + * screen.c: such a mess + * LINES is only present under curses. + * idem for refresh(). + * clear_to_eol() is supposed to take 2 arguments, + but what are they? + * swear.c: added to clients targets + * channel.c: delch renamed in del_ch. + * chkconf.c, parse.c: newline renamed in irc_newline. + * ircd.c: s_monitor(), s_die(), s_rehash(), s_restart() + return type changed from VOIDSIG to RETSIGTYPE. + * res.c: now using SOCK_LEN_TYPE. + * res_comp.c, res_init.c: various portability changes. + * s_auth.c: now using SOCK_LEN_TYPE. + * s_bsd.c: now using SOCK_LEN_TYPE. + * s_conf.c: several portability fixes. + * s_err.c: local_replies[] and local_replies[] rewritten. + * s_service.c: changed test on USE_STDARG. + * bsd.c: + * return type for dummy() is now RETSIGTYPE. + * dummy() now takes one int argument. + * dbuf.c: removed unused DBUF_INIT. + * support.c: + * many changes concerning #if tests. + * added solaris_gethostbyname() to use instead of + Solaris 2.3 broken gethostbyname(). + * added irc_memcmp() to use if system's memcmp() + is broken. + * nameser.h: now using WORDS_BIGENDIAN. + * configure.in: + * simpler solaris 2.x detection when looking for zlib. + * added test for cursesX. + * added check for sys_errlist definition in sys/errno.h + * and more... + * Makefile.in: CFLAGS split in S_CFLAGS, C_CFLAGS and + CC_CFLAGS (ircd, irc, chkconf). + +Fri Aug 8 10:51:24 1997 Christophe Kalt + + * channel.c: m_names() behaviour wasn't consistent with m_who() + concerning +p channels (Michael 'Eumel' Neumayer). + + * configure.in: minor changes (Alain Nissen). + + * s_user.c: missing argument to err_str() (Kai Seidler). + + * config.h.dist, h.h, struct.h, common.c, channel.c, s_bsd.c, + s_debug.c, s_err.c, s_misc.c, s_serv.c, s_service.c, s_user.c: + removed support for 2.8 protocol. + + * config.h.dist, msg.h, channel.c, note.c, s_bsd.c, s_debug.c, + s_misd.c, s_user.c: removed NOTE. + + * s_bsd.c: wrong argument to bzero(). + + * Makefile.in, buildm4: rev.sh replaced by config.guess and + buildm4 wasn't ran by `make install-server'. + +2.9.3 + +Wed Jul 23 11:23:30 1997 Christophe Kalt + + * res.c: queries were never resent when reaching timeout (C. Behrens). + + * acconfig.h, configure.in: better sys_errlist test (A. Nissen). + + * version.c.SH.in: portability (A. Nissen). + + * acconfig.h, configure.in, common.h, config.h.dist: AIX cleanup + and optimization flags (A. Nissen). + + * configure.in: typo. + +Thu Jul 17 23:04:48 1997 Christophe Kalt + + * c_numeric.c, irc.c: fixes from Vesa. + + * send.c: buffer overflow fix. + + * h.h, res_init.c: portability fixes. + +Wed Jul 16 21:35:50 1997 Christophe Kalt + + * s_serv.c: m_die() referenced data after freeing it. + + * support.c, res.c: silly changes to make purify happier. + + * s_bsd.c: fixed memory corruption problem. + + * s_user.c: m_whois() voice flag changed back to + (from !). + + * h.h, support.c, configure.in: reverted back: use inet_* if + present, use our own inet* if not. Our functions must be + different to avoid some crazy clash when bind 8.x is on installed + the system. Should we teach configure.in about -lbind? + +Tue Jul 15 00:18:01 1997 Christophe Kalt + + * inet_addr.c moved to support.c, renamed functions (inet_addr, + inet_aton, inet_ntoa, inet_netof) to avoid clashes; always used + even if the system has it. + + * New configure and Makefile from Alain Nissen. (many many files + changed, removed, created, rewritten) + + * buildm4: update (Mario Holbe). + + * struct.h, s_bsd.c: fixed the P line rehash bug(?). + + * h.h, ircd.c: let's be nice to SunOS' cc. + +Mon Jun 30 21:41:11 1997 Christophe Kalt + + * dbuf.c, send.c: earlier changes broke the client. + + * config.h.dist, struct.h, dbuf.h, dbuf.c: new magic formula to + compute BUFFERPOOL. Added MAXSERVERS for this purpose. + + * s_serv.c: buffer overflow (Chris Behrens). + +Thu Jun 26 19:18:24 1997 Christophe Kalt + + * struct.h, channel.c, hash.c, parse.c, send.c, s_misc.c, + s_service.c: + * cleanup. + * added &SERVICES. + + * s_bsd.c: wrong buffer size given to getsockopt(). + +Thu Jun 19 18:35:37 1997 Christophe Kalt + + * h.h, struct.h, s_debug.c, send.c, dbuf.c: + * dbuf stats. + * send_message() #ifndef SENDQ_ALWAYS was not uptodate, + tried to bring it back up to date. + + * res.c: fixed possible buffer overflow. + + * h.h, s_debug.c, send.c: fixes for STDARG (Olivier Galibert) + + * ircd.c: server_reboot() would crash when called because of "out + of memory". + +Mon Jun 9 20:49:55 1997 Christophe Kalt + + * config.h.dist, h.h, struct.h, send.c, ircd.c, list.c, s_debug.c, + s_serv.c, s_user.c: removed #define KRYS, it is now always `defined'. + + * config.h.dist, h.h, common.h, service.h, sys.h, configure.in, + send.c, support.c, s_auth.c, s_service.c, s_debug.c, s_conf.c: + removed references to varargs, added support for stdargs. + It is controlled by #define USE_STDARG set by configure. (adapted + from Olivier Galibert) + + * ircd.c: CHROOT is really called CHROOTDIR. + + * s_user.c: + * extended m_message() to accept n!u@h as recipient. + * removed notice for bogus PONG. + + * s_serv.c: /SQUIT now requires 2 arguments from opers. + +Sun Jun 1 16:57:39 1997 Christophe Kalt + + * dbuf.h, dbuf.c: #define DBUF_TAIL is back. + + * s_conf.c: fixed B lines behaviour, port number is now mandatory. + + * send.c: missing arg to dead_link(). (Olivier Galibert) + + * s_serv.c, numeric.h, s_err.c: added /stats B to see B lines (and + fixed /stats V reply). + + * service.h, channel.c, s_misc.c, s_service.c, s_serv.c, s_user.c: + * numerous bugfixes related to local services (if + USE_SERVICES is defined). + * extended services option to allow 2.9 NICK syntax, and + let them see tokens if they want. (adapted from O.Galibert) + +Wed May 21 21:17:51 1997 Christophe Kalt + + * channel.c, s_service.c, service.h: finished service code (whee). + + * s_serv.c: services were incorrectly sent during burst. + + * s_bsd.c: ident MUST be done before anything else is read from a + client. + +Thu May 15 16:27:13 1997 Christophe Kalt + + * struct.h, s_conf.h, s_serv.c: created k: lines to be able to + deny access based on OTHER ident replies. + + * s_user.c: changed 001 reply to return n!u@h (more zen). + + * s_serv.c: + * if A: is bogus, trash it and complain instead of crashing. + * get_client_name() is non-reentrant. *sigh* + +Wed May 7 22:11:04 1997 Christophe Kalt + + * s_user.c: nick chasing kill bug fix. (Chris Behrens) + + * h.h, ircd.c, s_conf.c, s_user.c: K-lined users now exit + displaying the Kline comment, if any. + + * s_conf.c: fixed notice ERR_YOUWILLBEBANNED, and don't disconnect + then. + + * inet.h, nameser.h, resolv.h, inet_addr.c, portability.h, res.c, + res_comp.c, res_init.c, res_mkquery.c: updated. (BIND 4.9.5-P1) + + * channel.c: notice for service could use free'ed memory. + +Sun Apr 27 16:40:08 1997 Christophe Kalt + + * send.c: fixed couple buglets (added by Chris Behrens :^). + + * s_user.c: removed dummy m_note() which was unused and buggy, and + would let any oper _broadcast_ NOTE queries to the net. + + * m_note.c: Modified m_note() in note.c not to send any NOTE + commands to other servers. + + This is lame, someone help me and port note to be a service. + Then, I'll finally take it out of the server !! :-) + +Thu Apr 24 18:51:25 1997 Christophe Kalt + + * send.c: better (faster) sendto_common_channel() (from Chris Behrens). + + * s_serv.c: fixed connected burst for services with hostmasks. + + * s_user.c: fixed origin check in m_pong(). + + * res.c: added a check on hostnames. (From Darren Reed) + +Sun Apr 20 20:30:21 1997 Christophe Kalt + + * s_conf.c: find_bounce() had an inversed test. (how could it work + when I tested it??) + + * s_serv.c: SERVER message would occasionnally (and incorrectly) + be dropped. + + * s_misc.c: simple optimization in exit_client(). + + * s_service.c, s_serv.c: things looked wrong, SERVICE syntax + inchorent. Minor memory leak. + + * s_bsd.c, s_misc.c: various "typos" fixed. (UDP & non POLL) + + * send.c, h.h: removed sendto_all_butone(). (unused) + +Tue Apr 15 19:41:32 1997 Christophe Kalt + + * sock.h: added a check to make sure FD_SETSIZE is big enough. + + * s_bsd.c, struct.h, s_misc.c: added more UDP stats. + + * s_bsd.c: fixed udp_pfd/res_pfd mess, and cleaned the code. (whee) + + * h.h, struct.h, numeric.h, s_err.c, s_conf.c, s_bsd.c: added B lines. + + * channel.c: defining USE_SERVICE would cause buffer corruption + when propagating channel modes to servers. (Found by Michael Neumayer) + +Wed Apr 2 15:25:54 1997 Christophe Kalt + + * list.c, s_serv.c: added some error notices for users without server. + + * s_bsd.c: fixed UDP port binding when no IP is given. + + * configure.in: add -cckr to CFLAGS on SGI when using cc(1) + +Thu Mar 27 19:03:09 1997 Christophe Kalt + + * h.h, send.c, s_bsd.c, s_user.c, s_serv.c: amount of transferred + data added to file logs. + + * config.h.dist: define SVR4 if __svr4__ is there. + + * packet.c: drop server sending an unknown command. + + * s_user.c: changed m_who() for better performance (from Chris + Behrens), also put a limit on its number of arguments. + + * h.h, struct.h, list.c: better IsMember (from Chris Behrens). + + * s_serv.c: don't let a user introduce a new server. + +Fri Mar 21 19:53:36 1997 Christophe Kalt + + * h.h, struct.h, ircd.c, s_conf.c, s_misc.c, s_serv.c, + config.h.dist: server can now cache the MOTD in memory (from Chris + Behrens). See CACHED_MOTD #define. + + * service.h, channel.c, s_serv.c, s_service.c, s_user.c: additions + for services. + + * s_misc.c: added missing parameter for check_service_butone(). + + * INSTALL completed and converted to sgml + + * s_serv.c: MyRealloc(NULL, size) isn't portable. + +Tue Mar 18 17:59:26 1997 Christophe Kalt + + * 2.9.3b10 + + * channel.c, hash.c, res.c, s_serv.c, s_service.c, s_user.c, + whowas.c: penalties tuned again. (added Volker Paulsen's anti SPAM + hack). + + * s_err.c, s_serv.c: minor changes to RPL_STATS* + + * s_bsd.c: authclnts[] was not always initialized. + + * ircd.c: buffer in ircd_readtune() lacked initialization. + + * s_service.c: fixed buffer overflow. + + * send.c, support.c: # of arguments cleanup. + + * list.c, res.c, s_service.c: casts to suppress warnings. + + * h.h, dbuf.c: bufalloc, dbufblocks, poolsize now + unsigned. (some checks might be needed, poolsize can really get + big). + + * s_misc.c: removed duplicate code in exit_client(). + + * parse.c: + + * Added more notices when generating SQUITs for unknown + servers. + * removed bogus else. + +Fri Feb 28 09:34:36 1997 Christophe Kalt + + * s_err.c, s_serv.c: Added 2 more fields to RPL_TRACELINK. + +Thu Feb 27 14:50:37 1997 Christophe Kalt + + * s_serv.c: /connect by servername didn't work for c lines (from Eumel) + +Wed Feb 26 16:48:36 1997 Christophe Kalt + + * s_bsd.c: removed (old) redundant code concerning VIF. + + * config.h.dist: CLONE_MAX and CLONE_PERIOD could be undefined. + + * common.c: match() cleanup. + +Thu Feb 13 17:27:53 1997 Christophe Kalt + + * res.c, res_init.c, res_mkquery.c, ircd.c, s_bsd.c: renamed + res_init() to ircd_res_init() to avoid conflict (ULTRIX). + + * hash.c, struct.c: cleanup of hashing functions. + + * match.c, parse.c, send.c, common.h, channel.c, hash.c, s_bsd.c, + s_misc.c, s_serv.c, s_service.c, s_user.c, note.c, ignore.c: + + * _match() changed to match() and the check for maximum + "recursion" slightly changed. + * match() and matches() removed (stubs from when match + was recursive?). + * All occurrences of matches() changed to match(). + * this saves one function call per match. + + * send.c: Added 2 parameters to sendto_serv_butone(). + + * s_err.c, s_serv.c: Added one field to RPL_TRACELINK. + +Sun Jan 26 20:02:34 EET 1997 Vesa Ruokonen (ruokonen@aapo.it.lut.fi) + + * 2.9.3b8 + + * support.c, h.h, list.c: gcc -Wall cleanups. + * h.h, struct.h, chkconf.c, s_conf.c, s_serv.c: + created V:lines for checking connecting client parameters. + passed as PASS command parameters. A matching V:line. + refuses the connection (version number & compile flags). + * struct.h, channel.c, s_debug.c: + penalty threshold used for limiting KICK params. + * struct.h: initial QUEUELEN calculation tuned. (->BUFFERPOOL). + * c_msg.c: more verbose m_pong(). + * channel.c, s_serv.c, s_user.c, whowas.c: + penalties tuned for commands generating global bcast. + * hash.c: converted multiplication to hashtable lookup to speed. + up function calls. (from Core) + * ircd.c, s_bsd.c: added truncation for non-appended writes. (_root_) + * s_user.c: prefix for voice capability in channel list of WHOIS reply + changed from '+' to '!'. + * s_user.c: drop PONGs with bad origin. + store connection parameters from PASS temporarily to info + field in contstant locations. + * s_user.c: m_umode() fixed (from Core). + +Wed Jan 15 14:42:43 1997 Christophe Kalt + + * s_bsd.c: + + * mysk was initialized by empty password in M line. + +Tue Jan 14 24:62:34 EET 1997 Vesa Ruokonen (ruokonen@aapo.it.lut.fi) + + * parse.c, channel.c, s_user.c: cleanup of find_functions(), + _nickserv replaced by _service. + * h.h, : setup_ping() takes aConfItem pointer as parameter now. + * sys.h: #elif expanded to #else #if for compability + * s_bsd.c: inetport(P:line) changed to support VIFs better. + More info about listening ports into /stats l. + UDP ping is initialized from M:line, not anymore from P:line. + * s_numeric.c: cleanups in numeric processing. + * Makefile.in, Makefile.irc, Makefile.ircd: makedepend fix + * configure.in: zlib check moved to end, as it can interfere + other checks when libs aren't in default paths. + +Mon Jan 13 09:11:04 1997 Christophe Kalt + + * ircd.c: + + * made the display of version (flag -v) more verbose. + + * regenerated configure (with autoconf 2.12; thanks digital). + + * s_user.c: + + * fixed, and extended KILL reasons for `standard' + collisions. (both victims u@h are now shown). + + * send.c: + + * fixed the logic when sending mass message/notice to a + server mask. + + * configure.in, Makefile.in: + + * fixed detection & use of zlib using the environment + variable ZLIB_HOME (from Vesa). + +Thu Jan 9 13:09:36 1997 Christophe Kalt + + * struct.h, ircd.c: + + * added -b command line switch to let the server start + even if the ircd.tune file is corrupted (mostly from + Magnus Tjernstrom). + + * s_conf.c: + + * udp listen was setup even if port was defined to be 0. + +Wed Jan 8 12:35:03 1997 Christophe Kalt + + * h.h, s_bsd.c, s_conf.c: + + * port field in M configuration line is used again, now to + define on which port the server will listen for UDP pings. + + * hash.c: + + * restricted commands to opers (from Vesa). + + * send.c: + + * sendto_match_butone() had a broken behaviour, + brought back the old (2.8.21) behaviour. + + * s_bsd.c: + + * fixed negociation of compression for outgoing + connections. + + * moved the "rejected connection" notice to &LOCAL. + + * SLOW_ACCEPT #ifdef's changed to #ifndef's to get what + one should expect from the define name ! + + * made inetport() more readable, and added check on empty + string parameter (from Vesa). + + * highfd isn't defined when _DO_POLL_ is defined, so don't + use it in debug notices (from Vesa). + + * break changed to continue because ??? (from Vesa). + + * s_user.c: + + * fixed KILL notice sent on nick collision (was using + ident reply for remote clients). + + * allowed oper!user@host.foo to send global message/notice + to #*.foo + + * s_serv.c, s_user.c, s_bsd.c, s_debug.c: + + * changed the PASS command semantic (from Vesa). + +Fri Jan 3 14:47:52 1997 Christophe Kalt + + * s_bsd.c: + + * completed virtual hosts support (M line). + + * config.h.dist: + + * AIX has poll(), use it. + +Mon Dec 30 15:08:20 1996 Christophe Kalt + + * s_bsd.c, h.h: + + * added support for virtual hosts (P line). + +Wed Dec 18 12:08:29 1996 Christophe Kalt + + * bsd.c: + + * fixed read_message() bugs resulting from the merge. + + * channel.c: + + * limited the number of possible kicks to MAXMODEPARAMS. + +Mon Dec 16 09:36:54 1996 Christophe Kalt + + * list.c: + + * don't free serv->user too early. + + * removed duplicated(?) away memory count. + +Fri Dec 13 10:28:43 1996 Christophe Kalt - Hmm, Friday the 13th! + + * config.h.dist, s_auth.c, s_user.c, s_debug.c: + + * minor tuning. + +Thu Dec 12 10:34:47 1996 Christophe Kalt + + * struct.h, s_auth.c, s_debug.c: + + * added memory usage stats for ident replies. + + * send.c, s_auth.c, s_misc.c: + + * fixed boundaries problems with long ident replies. + +Wed Dec 11 17:42:29 1996 Christophe Kalt + + * struct.h, send.c, s_auth.c, s_bsd.c, list.c, s_conf.c, s_misc.c, + s_user.c: + + * added auth field to struct Client to eventually store + long `OTHER' ident replies. It is only used in logs, and + notices (not in matches against configuration lines). + + * config.h.dist: + + * added #define SLOW_ACCEPT (default). + + * added #define CLONE_CHECK (default). + + * s_bsd.c: + + * fixed config line reference counter. + + * added CLONE_CHECK code (check_clones() from + pgoncalves@mail.telepac.pt (Pedro Goncalves)). + + * added SLOW_ACCEPT (previous behaviour) code. + + * merged the 2 versions of read_message(), fixing some + (buggy) difference between them. + + * merged two for() in read_message(). + + +Mon Dec 2 11:02:54 1996 Christophe Kalt + + * s_user.c: + + * changed error notice + + * send.c: + + * #*.mask messages now propagated to other servers. + + * s_service.c: + + * added missing else. + + * config.h.dist, s_debug.c, channel.c: + + * removed all references to V28PlusOnly + * made NoV28Link defined by default + +Wed Nov 27 18:09:42 1996 Christophe Kalt + + * struct.h, class.c, ircd.c, s_bsd.c, s_conf.c, s_serv.c: + + * added lowercase c config line + +Tue Oct 1 22:29:31 1996 Christophe Kalt + + * added config.h to dependancies in Makefile.ircd + + * config.h.dist, h.h, struct.h, packet.c, send.c, ircd.c, s_bsd.c, + s_debug.c, s_serv.c, s_user.c, s_err.c, list.c, Makefile.ircd, + configure.in: + + * added #define ZIP_LINKS and s_zip.c. + * made configure look for the zlib (-lgz). + * implemented server-server zlib compression. diff --git a/doc/Etiquette b/doc/Etiquette new file mode 100644 index 0000000..b531954 --- /dev/null +++ b/doc/Etiquette @@ -0,0 +1,84 @@ +/************************************************************************ + * IRC - Internet Relay Chat, doc/etiquette + * Copyright (C) 1990, Lea Viljanen and Ari Husa + * + * 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. + */ + +HOW TO BEHAVE ON IRC + +Authors: Lea Viljanen (LadyBug) viljanen@kreeta.helsinki.fi + Ari Husa (luru) so-luru@tolsun.oulu.fi +Revised, March 1994: Helen Rose (Trillian) hrose@kei.com + +1) Language + + The most widely understood and spoken language on IRC is English. +However! As IRC is used in many different countries, English is by +no means the only language. If you want to speak some other language +than English (for example with your friends), go to a separate channel +and set the topic (with /topic) to indicate that. For example + /topic #channelname Finnish only! +would mean that this channel would be reserved for Finnish discussion. +On the other hand, you should check the topic (with /list command) +before you move to a channel to see if there are any restrictions about +language. + On a channel not restricted by /topic, please speak a language +everybody can understand. If you want to do otherwise, change channels +and set the topic accordingly. + + +2) Hello/Goodbye + + It's not necessary to greet everybody on a channel personally. +Usually one "Hello" or equivalent is enough. And don't expect everybody +to greet you back. On a channel with 20 people that would mean one +screenful of hellos. It's sensible not to greet, in order not to be rude +to the rest of the channel. If you must say hello, do it with a private /msg. +The same applies to goodbyes. + + +3) Discussion + + When you come to a new channel it's advised you to listen +for a while to get an impression of what's discussed. Please feel free +to join in, but do not try to force your topic into the discussion +if that doesn't come naturally. + + +4) {}|[]\ + + IRC has quite a lot of people from Scandinavian countries, +the above characters are letters in their alphabet. This +has been explained on IRC about a thousand and one times, so +read the following, do not ask it on IRC: + + { is an A with 2 dots over it + } is an A with a small circle above it + | is either an O with 2 dots over it or an O with a dash (/) through it + [, ], and \ are the preceding three letters in upper case. + + There are a lot of people from Japan as well, who use Kanji characters +which may look quite exotic as well. As I don't know Kanji I don't +even try to explain any of the characters. + +5) ATTENTION! + + Remember, people on IRC form their opinions about you only by +your actions, writings and comments on IRC. So think before you type. +Do not "dump" to a channel or user (send large amounts of unwanted +information). This is likely to get you /kicked off the channel or +/killed off from irc. Dumping causes network 'burps', connections going +down because servers cannot handle the large amount of traffic any more. diff --git a/doc/INSTALL.appendix b/doc/INSTALL.appendix new file mode 100644 index 0000000..beeb57a --- /dev/null +++ b/doc/INSTALL.appendix @@ -0,0 +1,86 @@ +Appendix A: Difference between IP addresses and hostnames + + + There are 2 different types of INTERNET addresses, NAME addresses and + NUMERIC addresses. NAME addresses look like ENGLISH words (and indeed + they are ENGLISH words that refer to a given host). A NAME address looks + like "tolsun.oulu.fi" - and that particular address refers to the machine + named TOLSUN in Finland. It is a UNIQUE address because no other machine + in the world has its NAME address the same as "tolsun.oulu.fi". Anytime + you say "telnet tolsun.oulu.fi" - you would always connect to TOLSUN in + Finland. NUMERIC addresses refer to those addresses that are made up of + NUMBERS for example "128.214.5.6" is the NUMERIC address for TOLSUN. This + address is also UNIQUE in that no other machine in the world will be use + those NUMERIC numbers. The NUMERIC address is usually more reliable than + the NAME address because not all sites can recognize and translate the + NAME address into it's numeric counterpart. NUMERIC always seems to work + best, but use a NAME address when you can because it is easier to tell + what host you are connected to. + + + Every Unix machine has a file called "/etc/hosts" on it. This file + contains NAME and NUMERIC addresses. When you supply IRC with a NAME + address it will at first try to find it in /etc/hosts, and then (if it's + really smart), use the local Domain Name Server (DNS) to find the NUMERIC + address for the host you want to connect to. Thus if you plan to use NAME + addresses keep in mind that on SOME sites the entry for the TARGET machine + must be found in /etc/hosts or the NAME address will fail. A typical + entry in /etc/hosts looks like this: + + 130.253.1.15 orion.cair.du.edu orion.du.edu orion # BSD 4.3 + + This particular example is the Host ORION at the University of Denver. + Notice that on the far left is the NUMERIC Address for orion. The + next few ENGLISH words are the NAME addresses that can be used for orion, + "orion.cair.du.edu", "orion.du.edu", "orion". ALL of these NAME addresses + will return the NUMERIC address "130.253.1.15" which IRC will use to + connect to the TARGET UNIX. (when I say TARGET UNIX I am refering to the + UNIX you want to connect to for IRC). Any futher questions about + /etc/hosts should be directed to "man hosts". + + +Appendix B: Enabling Summon Messages + + +-----------------------------------------------------------------------+ + | E N A B L I N G / S U M M O N M E S S A G E S | + +-----------------------------------------------------------------------+ + + *NOTE* You must have ROOT or special access to the GROUP tty ('/dev') + to do this. If you want to allow users around the world to summon + users at your site to irc, then you should make sure that summon works. + + The "IRCD" program needs access to the GROUP of '/dev'. This + directory is where user TTY's are stored (as UNIX treats each Terminal + as a FILE!) IRCD needs GROUP ACCESS to /dev so that users can be + SUMMONED to the program by others users that are *in* the program. + This allows people from other Universities around the world to SUMMON + your users to IRC so that they can chat with them. Berkeley, SUN, HP-UX + and most of the newer versions of UNIX check to see if a USER is + accepting MESSAGES via the GROUP access rights on their TTY listing + in the /dev directory. For example an entry in '/dev' looks like this: + + (Unix Path on BSD 4.3 UNIX is: /dev/ttyp0) + + crw------- 1 jtrim 20, 0 Apr 29 10:35 ttyp0 + + You will note that 'jtrim' OWNS this terminal and can READ/WRITE to this + terminal as well (which makes sense because I am ENTERING DATA and + RECEIVEING DATA back from the UNIX). I logged into this particular + UNIX on "April 29th" at "10:35am" and my TTY is "ttyp0". But further + of *note* is that I do not have my MESSAGES ON! (mesg n) -- This is + how my terminal would look with MESSAGES ON (mesg y): + + crw--w---- 1 jtrim 20, 0 Apr 29 10:35 ttyp0 + + With my MESSAGES ON (mesg y) I can receive TALK(1) requests, use the + UNIX WRITE(1) command and other commands that allow users to talk + to one another. In IRC this would also allow me to get IRC /SUMMON + messages. To set up the "IRCD" program to work with /SUMMON type + the following: (using ROOT or an account that has access to '/dev'). + + % chgrp tty ircd + % chmod 6111 ircd + + The above commands read: "Give IRCD access to GROUP tty (which is /dev) + and then when ANYONE runs the IRCD allow SETUID and SETGID priviliges + so that they can use the /SUMMON command. diff --git a/doc/INSTALL.info b/doc/INSTALL.info new file mode 100644 index 0000000..c74be27 --- /dev/null +++ b/doc/INSTALL.info @@ -0,0 +1,1759 @@ +This is Info file INSTALL.info, produced by Makeinfo-1.55 from the +input file /tmp/sgml2info3035tmp2. + + \input texinfo + + +File: INSTALL.info, Node: Top, Next: Installing IRC-, Prev: (DIR), Up: (DIR) + +Installing IRC - The Internet Relay Chat Program +************************************************ + + SGML version by Christophe Kalt + $Id: INSTALL.info,v 1.38 1999/08/13 17:22:12 kalt Exp $ + + This document describes how to install, and configure IRC 2.10.3. + +* Menu: + +* Installing IRC-:: +* The config-h file:: +* Editing the Makefile and compiling:: +* The ircd-conf file:: +* Related resources:: +* Reporting a bug:: + + +File: INSTALL.info, Node: Installing IRC-, Next: The config-h file, Prev: Top, Up: Top + +Installing IRC- +*************** + +* Menu: + +* The configure script:: +* Notes for Cygwin32 users:: +* Notes concerning IPv6 support:: + + +File: INSTALL.info, Node: The configure script, Next: Notes for Cygwin32 users, Up: Installing IRC- + +The configure script +==================== + + This package uses a GNU configure script for its configuration. You +simply need to untar the distribution and run the "configure" script. +This will run configure which will probe your system for any +peculiarities it has and setup the Makefile and a file of default +#define's ($arch/setup.h). + + There are a few options to "configure" to help it out, or change the +default behaviour: +`--prefix=DIR' + changes the default directory into which ircd will install using + "make install". This defaults to /usr/local + +`--sbindir=DIR' + changes the default directory where the system admin executable + files will go. It is important to set this properly. (default is + prefix/sbin) + +`--logdir=DIR' + changes the default directory where the irc log files will go. + (default is prefix/var/log/ircd) + +`--sysconfdir=DIR' + changes the default directory where the irc server configuration + files will go. (default is prefix/etc) + +`--localstatedir=DIR' + changes the default directory where the irc server state files + will go. (default is prefix/var/run) + +`--resconf=FILE' + defines the file to be used by ircd to initialize its resolver. + (default is /etc/resolv.conf) + +`--zlib-include=DIR' + specifies in which directory the include file from the zlib is + located. + +`--zlib-library=DIR' + specifies in which directory the zlib library is located. + +`--zlib-prefix=DIR' + specifies the prefix for zlib location. It overrides the 2 + previous options. (The include directory is supposed to be in + prefix/include, and the library in prefix/lib). + +`--with-zlib' + is the default. "configure" looks on your system to find the + zlib. If found, ircd will be linked using it. This does NOT mean + you can use server link compression, for this you also need to + define ZIP_LINKS (see section below). + +`--without-zlib' + tells "configure" not to look for the zlib. Defining this will + keep you from using server link compression. + +`--enable-ip6' + Enable IPv6 support (See notes below) + +`--enable-dsm' + Enable Dynamically Shared Modules support for iauth + + +File: INSTALL.info, Node: Notes for Cygwin32 users, Next: Notes concerning IPv6 support, Prev: The configure script, Up: Installing IRC- + +Notes for Cygwin32 users +======================== + + The daemon of 2.10.3 release compiles properly on W32 systems which +have the GNU-Win32 environment () setup. At the time of the release, +tests were made using the version b20.1 of the Cygwin32 library. + + When compiling on such system, you want to make sure that you have +carefully followed the Cygwin32 installation notes. In particular, you +will need to make sure that the following files exist: `/bin/cp.exe', +`/bin/mv.exe', `/bin/rm.exe' and `/bin/sh.exe'. + + Also, the IRC server needs a `resolv.conf' file in order to +initialize the resolver. This file can be anywhere (see configure +options), and is typically in `/etc' on UNIX systems. + + Finally, iauth is automatically disabled. Even though the iauth +program compiles properly, extra work is required to have a working +communication channel between the IRC server and the iauth program. + + +File: INSTALL.info, Node: Notes concerning IPv6 support, Prev: Notes for Cygwin32 users, Up: Installing IRC- + +Notes concerning IPv6 support +============================= + + The only part of the software that doesn't use IPv6 is the server +internal resolver. It relies on the name servers defined in +"/etc/resolv.conf" to be IPv4 addresses. + + This version was tested on the following IPv6 systems: BSD/OS+KAME, +Digital Unix, FreeBSD+KAME, Linux, NetBSD+INRIA. + + Because IPv6 numeric addresses contain ":" characters, `the +separator for the server configuration file was changed to "%"'. + + +File: INSTALL.info, Node: The config-h file, Next: Editing the Makefile and compiling, Prev: Installing IRC-, Up: Top + +The config-h file +***************** + + The second step consists of defining options before the compilation. +This is done by editing the "config.h" file and changing the various +#DEFINE's. + +* Menu: + +* Define what type of UNIX your machine uses-:: +* DEBUGMODE:: +* CPATH MPATH LPATH PPATH TPATH QPATH OPATH:: +* CACHED_MOTD:: +* CHROOTDIR:: +* ENABLE_SUMMON ENABLE_USERS:: +* SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE:: +* OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY:: +* ZIP_LINKS ZIP_LEVEL:: +* SLOW_ACCEPT:: +* CLONE_CHECK:: +* Other #define's:: + + +File: INSTALL.info, Node: Define what type of UNIX your machine uses-, Next: DEBUGMODE, Up: The config-h file + +Define what type of UNIX your machine uses- +=========================================== + + Pick the machine type which best describes your machine and change +the #undef to #define (if needed).Some flavours of Unix require no +#define and in such cases all others should be #undef'd. + + +File: INSTALL.info, Node: DEBUGMODE, Next: CPATH MPATH LPATH PPATH TPATH QPATH OPATH, Prev: Define what type of UNIX your machine uses-, Up: The config-h file + +DEBUGMODE +========= + + Define DEBUGMODE if you want to see the ircd debugging information +as the daemon is running. Normally this function will be undefined as +ircd produces a considerable amount of output. DEBUGMODE must be +defined for either of -t or -x command line options to work. Defining +this induces a large overhead for the server as it does a large amount +of self diagnostics whilst running. + + `This should only be defined for test purposes, and never used on a +production server.' + + +File: INSTALL.info, Node: CPATH MPATH LPATH PPATH TPATH QPATH OPATH, Next: CACHED_MOTD, Prev: DEBUGMODE, Up: The config-h file + +CPATH MPATH LPATH PPATH TPATH QPATH OPATH +========================================= + + Define CPATH to be the directory path to the "ircd.conf" file. This +path is usually /usr/local/lib/ircd/ircd.conf. The format of this file +will be discussed later. + + The LPATH #define should be set to "/dev/null" unless you plan to +debug the ircd program. Note that the logfile grows very quickly. + + Define MPATH to be the path to the "motd" (message of the day) file +for the server. Keep in mind this is automatically displayed whenever +anyone signs on to your server. + + The PPATH is optional, but if defined, should point to a file which +either doesn't exist (but is creatable) or a previously used PPATH +file. It is used for storing the server's PID so a ps(1) isn't +necessary. + + Define QPATH to be the directory path to the "iauth.conf" file. This +path is usually /usr/local/lib/ircd/iauth.conf. The format of this +file is described by a manual page. + + The OPATH #define should be set to "/dev/null" unless you plan to +debug the iauth program. Note that the logfile grows very quickly. + + +File: INSTALL.info, Node: CACHED_MOTD, Next: CHROOTDIR, Prev: CPATH MPATH LPATH PPATH TPATH QPATH OPATH, Up: The config-h file + +CACHED_MOTD +=========== + + The server sends the "motd" to every client connecting. Every time, +it reads it from the disk. This is quite intensive and can be +undesirable for busy servers. + + Defining CACHED_MOTD will make the server store the "motd" in +memory, and only read it again from the disk when rehashing if the file +has changed. + + +File: INSTALL.info, Node: CHROOTDIR, Next: ENABLE_SUMMON ENABLE_USERS, Prev: CACHED_MOTD, Up: The config-h file + +CHROOTDIR +========= + + To use the CHROOTDIR feature, make sure it is #define'd and that the +server is being run as root. The server will chroot to the directory +name provded by "IRCDDIR" (in Makefile). + + +File: INSTALL.info, Node: ENABLE_SUMMON ENABLE_USERS, Next: SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE, Prev: CHROOTDIR, Up: The config-h file + +ENABLE_SUMMON ENABLE_USERS +========================== + + For security conscious server admins, they may wish to leave +ENABLE_USERS undefined, disabling the USERS command which can be used +to glean information the same as finger can. ENABLE_SUMMON toggles +whether the server will attempt to summon local users to irc by writing +a message similar to that from talk(1) to a user's tty. + + +File: INSTALL.info, Node: SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE, Next: OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY, Prev: ENABLE_SUMMON ENABLE_USERS, Up: The config-h file + +SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE +========================================== + + On large IRC networks, the number of invisible users is likely to be +large and reporting that number cause no pain. To aid and effect this, +SHOW_INVISIBLE_LUSERS is provided to cause the LUSERS command to report +the number of invisible users to all people and not just operators. The +NO_DEFAULT_INVISIBLE define is used to toggle whether clients are +automatically made invisible when they register. + + +File: INSTALL.info, Node: OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY, Next: ZIP_LINKS ZIP_LEVEL, Prev: SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE, Up: The config-h file + +OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY +================================================== + + The three operator only commands, KILL, REHASH and RESTART, may all +be disabled to ensure that an operator who does not have the correct +privilidges does not have the power to cause untoward things to occur. +To further curb the actions of guest operators, LOCAL_KILL_ONLY can be +defined to only allow locally connected clients to be KILLed. + + +File: INSTALL.info, Node: ZIP_LINKS ZIP_LEVEL, Next: SLOW_ACCEPT, Prev: OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY, Up: The config-h file + +ZIP_LINKS ZIP_LEVEL +=================== + + As of the 2.9.3 version of the server, server-server connections may +be compressed using the zlib. In order to compile the server with this +feature, you MUST have the zlib package (version 1.0 or higher) already +compiled and define ZIP_LINKS in the config.h file. Compression use for +server-server connections is separately configured in the ircd.conf +file for each server-server link. ZIP_LEVEL allows you to control the +compression level that will be used. Values above 5 will noticeably +increase the CPU used by the server. + + The zlib package may be found at . The data format used by the zlib +library is described by RFCs (Request for Comments) 1950 to 1952 in the +files (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip +format). These documents are also available in other formats from + + +File: INSTALL.info, Node: SLOW_ACCEPT, Next: CLONE_CHECK, Prev: ZIP_LINKS ZIP_LEVEL, Up: The config-h file + +SLOW_ACCEPT +=========== + + This option is defined by default and is needed on some OSes. It +creates an artificial delay in processing incoming connections. On a +given port, no more than 1 connection per 2 seconds will be processed. + + Undefining this will let the server process connections as fast as +it can which can cause problems on some OSes (such as SunOS) and be +abused (fast massive join of clonebots..), for these reasons, if you +decide to undefine SLOW_ACCEPT you MUST define CLONE_CHECK. + + +File: INSTALL.info, Node: CLONE_CHECK, Next: Other #define's, Prev: SLOW_ACCEPT, Up: The config-h file + +CLONE_CHECK +=========== + + This option acts as a wrapper, by checking incoming connections +early before starting ident query. By default, the server will not +accept more than 2 connections from the same host within 10 seconds. + + +File: INSTALL.info, Node: Other #define's, Prev: CLONE_CHECK, Up: The config-h file + +Other #define's +=============== + + The rest of the user changable #define's should be pretty much self +explanatory in the config.h file. It is *NOT* recommended that any of +the file undef the line with "STOP STOP" in it be changed. + + +File: INSTALL.info, Node: Editing the Makefile and compiling, Next: The ircd-conf file, Prev: The config-h file, Up: Top + +Editing the Makefile and compiling +********************************** + + This package now uses GNU autoconf to probe your system and generate +the correct Makefile. However you need to edit it to specify specific +information, such as "prefix", "irc_mode", "ircd_mode" and "ircd_dir". + + Now to build the package, type "make all". If everything goes will, +you can then install it by typing "make install". + + If you have trouble compiling ircd, copy Makefile.in to Makefile and +edit Makefile as appropriate. + + +File: INSTALL.info, Node: The ircd-conf file, Next: Related resources, Prev: Editing the Makefile and compiling, Up: Top + +The ircd-conf file +****************** + + After installing the ircd and irc programs, edit the ircd.conf file +as per the instructions in this section and install it in the location +you specified in the config.h file. There is a sample conf file called +example.conf in the doc/ directory. + + Appendix A (See INSTALL.appendix) describes the differences between +IP addresses and host names. If you are unfamiliar with this, you +should probably scan through it before proceeding. + + The ircd.conf file contains various records that specify +configuration options. The record types are as follows: + 1. Machine information (M) + + 2. Administrative info (A) + + 3. Port connections (P) + + 4. Connection Classes (Y) + + 5. Client connections (I,i) + + 6. Operator privileges (O) + + 7. Restrict lines (R) + + 8. Excluded accounts (K,k) + + 9. Server connections (C,c,N) + + 10. Deny auto-connections (D) + + 11. Hub connections (H) + + 12. Leaf connections (L) + + 13. Version limitations (V) + + 14. Excluded machines (Q) + + 15. Service connections (S) + + 16. Bounce server (B) + + 17. Default local server (U) + + Except for types "M" and "A", you are allowed to have multiple +records of the same type. In some cases, you can have concurrent +records. `It is important to note that the last matching record will +be used'. This is especially useful when setting up I records (client +connections). + +* Menu: + +* Machine information:: +* Administrative info:: +* Port connections:: +* Connection Classes:: +* Client connections:: +* Operator priviliges:: +* Restrict connections:: +* Excluded accounts:: +* Server connections:: +* Deny auto-connections:: +* Hub connections:: +* Leaf connections:: +* Version limitations:: +* Excluded machines:: +* Service connections:: +* Bounce server:: +* Default local server (for local clients) `*OBSOLETED*':: + + +File: INSTALL.info, Node: Machine information, Next: Administrative info, Up: The ircd-conf file + +Machine information +=================== + +`Introduction' + IRC needs to know a few things about your UNIX site, and the "M" + command specifies this information for IRC. The fomat of this + command is: + +`Format' + M:<Server NAME>:<YOUR Internet IP#>:<Geographic Location>:<Port> + +`M' + "M" specifies a Machine description line + +`Server NAME' + The name of YOUR server adding any Internet DOMAINNAME that might + also be present. If this hostname can be resolved, the IP# found + will be used to for outgoing connections. Otherwise the default + interface address of the host is used. The server name may not be + FQDN of another host. (This means all outgoing connections will + be done from the same IP#, even if your host has several IP#). + +`YOUR Internet IP#' + If the machine on which you run the server has several IP + addresses, you can define which IP# to use for outgoing + connections. This overrides overrides the "Server NAME". + + See Also the "Port Connections" section. + +`Geographic Location' + Geographic Location is used to say WHERE YOUR SERVER is, and gives + people in other parts of the world a good idea of where you are! + If your server is in the USA, it is usually best to say: <CITY> + <STATE>, USA. Like for Denver I say: "Denver Colorado, USA". + Finnish sites (like tolsun.oulu.fi generally say something like + "Oulu, Finland". + +`Port' + Defines the port on which your server will listen for UDP pings + from other servers. This should be the port were other servers + are set to autoconnect. (Also see the port field description in + connect lines). + +`Example:' + M:tolsun.oulu.fi::Oulu, Finland:6667: + + This line reads: My Host's name is "tolsun.oulu.fi" and my site is + located in "Oulu, Finland". + + M:orion.cair.du.edu::Denver Colorado, USA:6667: + + This line reads: My Hosts name is "orion.cair.du.edu" and my site + is located in "Denver Colorado, USA". + + +File: INSTALL.info, Node: Administrative info, Next: Port connections, Prev: Machine information, Up: The ircd-conf file + +Administrative info +=================== + +`Introduction' + The "A" line is used for administrative information about a site. + The e-mail address of the person running the server should be + included here in case problems arise. + +`Format' + A:<Your Name/Location>:<Your Electronic Mailing Addr>:<other>:: + +`A' + This specifies an Admin record. + +`Your Name & Location' + Use this field to say tell your FULL NAME and where in the world + your machine is. Be sure to add your City, State/Province and + Country. + +`Your Electronix Mailing Addr' + Use this field to specify your Electronic Mailing Address + preferably your Internet Mailing Address. If you have a UUCP or + ARAPnet address - please add that as well. Be sure to add any + extra DOMAIN information that is needed, for example "mail + jtrim@orion" probably won't work as a mail address to me if you + happen to be in Alaska. But "mail jtrim@orion.cair.du.edu" would + work because you know that "orion" is part of the DOMAIN + "cair.du.edu". So be sure to add your DOMAINNAMES to your mailing + addresses. + +`Other' + This is really an OTHER field - you can add what you want here. + +`Example' + (the line is just one line in the confuration file, here it is cut + into two lines to make it clearer to read): + + A:Jeff Trim - Denver Colorado, USA:INET jtrim@orion.cair.du.edu + UUCP {hao,isis}!udenva!jtrim:Terve! Heippa! Have you said hello + in Finnish today?;):: + + Would look like this when printed out with the /admin command: + + Jeff Trim - Denver Colorado, USA INET jtrim@orion.cair.du.edu + UUCP {hao,isis}!udenva!jtrim Terve! Hei! Heippa! Have you said + hello in Finnish today? ;) + + Note that the A record cannot be split across multiple lines; it + will typically be longer than 80 characters and will therefore + wrap around the screen. + + +File: INSTALL.info, Node: Port connections, Next: Connection Classes, Prev: Administrative info, Up: The ircd-conf file + +Port connections +================ + +`Introduction' + The port line adds flexibility to the server's ability to accept + connections. By use of this line in the ircd.conf file, it is easy + to setup both Unix Domain ports for the server to accept + connections on as well as extra internet ports. + +`Format' + P:<Internet IP#>:<*>:<Internet IP Mask>:<Port>: + P:<Directory>:<*>:<*>:<Port>: + + * Internet Ports + `Internet IP#' + If the host on which the server runs has several IP + addresses, you can define for which IP address connections + will be accepted. If no is defined here, server will bind to + all interfaces (INADDR_ANY). See also MACHINE CONFIGURATION + section to properly configure outgoing connections. + + P:192.168.1.194:::6664: + + `Internet IP# Mask' + This defines where connections may come from and be accepted. + The IP mask uses either *'s or 0's as wildcards. The + following two lines are the same: + + P:::128.2.*:6664: P:::128.2.0.0:6664: + + The incoming isn't matched against the mask, rather the ip# + string is decoded and compared segment by segment. Thus + + P:::128.2*.1.2:6664: + + will not match 128.20.1.2. + + `Port' + The port number field tells the server which port number it + should listen on for incoming connections. + + * Unix Socket Ports. + `Directory' + The path set in this field should be the directory name in + which to create the unix socket for later listening to. The + server will attempt to create the directory before creating + the unix socket. + + `Port' + The port field when used in combination with a pathname in a + P-line is the filename created in the directory set in the + first field. + + `Example' + P:/tmp/.ircd:::6667: + + Creates a unix socket in the /tmp/.ircd directory called + "6667". The unix socket (file) must be a numerical. + +`Note' + You need at least one P line. + + +File: INSTALL.info, Node: Connection Classes, Next: Client connections, Prev: Port connections, Up: The ircd-conf file + +Connection Classes +================== + +`Introduction' + To enable more efficient use of MAXIMUM_LINKS, connection classes + were implemented. All clients belong to a connection class. + + Each line for a server should have the same number as the sixth + field. If it is absent, the server deaults it to 0, using the + defaults from the config.h file. + + To define a connection class, you need to include a Y: line in the + ircd.conf file. This enables you to define the ping frequency, + connection frequency (for servers) and maximum number of links + that class should have. + + Currently, the Y: line `MUST' appear in the ircd.conf file + `BEFORE' it is used in any other way. + +`Format' + Y:<Class>:<Ping Frequency>:<Connect freq>:<Max + Links>:<SendQ>:<Local Limit>:<Global Limit> + +`Y' + This specifies a Class record. + +`Class' + This is the class number which gains the following attributes and + should match that which is on the end of the C/c/N/I/O/S line. + +`Ping Frequency' + This field defines how long the server will let the connection + remain "silent" before sending a PING message to make sure it is + still alive. Unless you are sure of what you are doing, use the + default value which is in your config.h file. + +`Connect Frequency' + By changing this number, you change how often your server checks + to see if it can connect to this server. If you want to check very + occasionally, use a large value, but if it is an important + connection, you might want a smaller value so that you connect to + it as soon as possible. + +`Max Links' + This field defines the maximum number of links this class will + allow from automatic connections (C lines). Using /CONNECT + overrides this feature. Also defines the maximum number of users + in this class for I/O lines per I/O line. + +`SendQ' + This field defines the "SendQ" value for this class. If this + field is not present, the default (from config.h) is assigned. + +`Local limit' + This field is used to limit the number of local concurrent + connections. The format is <x>.<y> + * x: defines the maximum number of clients from the same host + (IP) will be allowed. + + * y: defines the maximum number of clients from the same + user@host (IP) will be allowed. Read note below. + + Only x or y may be set, any unset value defaults to zero. + +`Global limit' + This field has the same use as the "Local limit" field. But, the + connection counts are done for all clients present on the net + instead of only counting local clients. + +`Note' + leaving any of the fields (except SendQ) out means their value is + 0 (ZERO)!! The SendQ field default value is dynamically + determined. + +`Note' + If you plan to use the local user@host limit, please read the + following very carefully. The "user" value is the ident reply for + the connection. If no reply was given then it defaults to + "unknown" and thus the effective limit will be per host, not per + user@host. Also, some ident servers return encrypted data which + changes for every connection making the limit void. + +`Note' + Only the local limitation is accurate. + +`Note' + If you define a gobal limit, you should also define a local limit + (same or lower) as it won't take more CPU and will make the global + limit more accurate. + +`Note' + The local and global limits only affect users (I lines), not + servers nor services. + +`Example' + Y:23:120:300:5:100000:0:0: (server class) + + This defines class 23 to allow 5 auto-connections, which are + checked every 300 seconds. The connection is allowed to remain + silent for 120 seconds before a PING is sent. NOTE: fields 3 & 4 + are in seconds. The SendQ is set to 100000 bytes. + + Another feature of connection class is the ability to do automatic + routing by using the class as a "priority". If you are connected + to a server which has a class lower than one of the servers that + is "behind" it, the server will disconnect the lower class one and + schedule a "new" connection for the higher class server. + + Y:1:60:0:50:20000:2:5: (client class) + + In case of a client class, the fields are interpreted a bit + differently. This class (number 1) can be used by up to 50 users. + The connections are allowed to remain silent for 60 seconds + before a PING is set. The SendQ is set to 20000 bytes. A new + connection in this class will only be allowed if there aren't more + than 2 other local connections from the same IP address, or more + than 5 other connections on the net from the same hostname. + + Y:2:60:0:50:20000:2.1:5: (client class) + + In case of a client class, the fields are interpreted a bit + differently. This class (number 1) can be used by up to 50 users. + The connections are allowed to remain silent for 60 seconds + before a PING is set. The SendQ is set to 20000 bytes. A new + connection in this class will only be allowed if there aren't more + than 2 other local connections from the same IP address, 1 other + local connection from the same user from the same IP address, or + more than 5 other connections on the net from the same hostname. + + +File: INSTALL.info, Node: Client connections, Next: Operator priviliges, Prev: Connection Classes, Up: The ircd-conf file + +Client connections +================== + + How to let clients connect to your IRCD. +`Introduction' + A client is a program that connects to the ircd daemon (ircd). + There are clients written in C, GNU Emacs Lisp and many other + languages. The "irc" program is the C client. Each person that + talks via IRC is running their own client. + + The ircd.conf files contains entries that specify which clients + are allowed to connect to your irc daemon. Obviously you want to + allow your own machine's clients to connect. You may want to + allow clients from other sites to connect. These remote clients + will use your server as a connection point. All messages sent by + these clients will pass through your machine. + +`Format' + I:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class> + i:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class> + +`TARGET Host Addr' + Specifies the IP address(es) of the machine(s) that are allowed to + connect. If "user@" prefixes the actual IP address the server + will require that the remote username returned by the ident server + be the same as the one given before the "@". Wildcards are + permitted unless using a bitmask (e.g. 1.2.3.0/24). + +`Password' + The password that must be given by the client to be allowed on the + server. + +`TARGET Host NAME' + Specifies the host name(s) of the machines allowed to connect to + the server. If "user@" prefixes the actual IP address the server + will require that the remote username returned by the ident server + be the same as the one given before the "@". Wildcards are + permitted. + + This field can be empty, it then has a special meaning. See Below. + +`Port' + Specifies the port number for which this configuration line is + valid. An empty field, or "0" matches all ports. + +`Class' + This field should refer to an existing class. Connections classes + are usefull to limit the number of users allowed on the server. + +`Note' + The server first checks if the client hostname (or any aliases) + matches the `TARGET Host NAME' field. If a match is found, the + client is accepted. If not, the server checks if the IP address + of the client matches the `TARGET Host Addr' field. The matching + field is used to set the name of the client: for example, if the + client matches the `TARGET Host Addr' field, it will show on IRC + with a numerical address (even if this address is resolvable). If + the `TARGET Host NAME' field is empty, then the host name is + always used (when available). + +`Examples' + For example, if you were installing IRC on tolsun.oulu.fi and you + wanted to allow examples sake let us assume you were making this + file for tolsun and you wanted to let your own clients to connect + to your server, you would add this entry to the file: + + I:x::tolsun.oulu.fi::1 + + If you wanted to let remote clients connect, you could add the + following lines: + + I:x::*.du.edu::1 + + Allow any clients from machines whose names end in ".du.edu" to + connect with no password. + + I:128.214.6.100::nic.funet.fi::1 + + Allow clients from a machine with that IP number to connect. + Numeric match is enough, name is not required anymore. + + I:x:secret:*.tut.fi::1 + + Allow clients from machines matching "*.tut.fi" to connect with + the password "secret". + + I:*::*::1 + + Allow anyone from anywhere to connect your server. + + This is the easiest way, but it also allows people to for example + dump files to your server, or connect 1000 (or how many open + sockets per process your OS allows) clients to your machine and + take your network ports. Of course the same things can be done by + simply telnetting to your machine's SMTP port (for example). + + I:x::*.fi:6667:1 + + Allow clients from machines matching "*.fi" to connect on the port + 6667. + + I:135.11.35.*::*.net::1 + + Allows clients from machines which host name matches "*.net" or + which IP address matches "135.11.35.*" to connect to the server. + If the host name does not match "*.net" then the IP address is + used for these clients, even if the host name is known. + + I:135.11.35.*::::1 + + Allows clients from machines which IP address matches + "135.11.35.*" to connect to the server. If the host name is + known, is it used as address for these clients. + +`NEW!!!' + As of the 2.7.2d version of the server, the server is able to + accept connections on multiple ports. I-lines are required for + each P-line to allow connections to be accepted. For unix sockets, + this means either adding I:/path/port::/path/port or some variation + (wildcards are recognised here). For internet ports, there must be + an I-line which allows the host access as normal, but the port + field of the I-line must match that of the port of the socket + accepting the connectiion. A port number of 0 is a wildcard + (matches all ports). + +`NEW!!!' + As of the 2.9.1 version of the server, i lines are introduced. + They work the same way as I lines, but the clients matching an i + line will have a restricted connection. (no nick/mode change, no + kick). Such users will have their username prefixed by +, = or - + depending on the ident reply. + + +File: INSTALL.info, Node: Operator priviliges, Next: Restrict connections, Prev: Client connections, Up: The ircd-conf file + +Operator priviliges +=================== + + How to become the IRC administrator on your site +`Introduction' + To become an IRC Administrator, IRC must know who is authorized to + become an operator and what their "Nickname" and "Password" is. + +`Format' + O:<TARGET Host NAME>:<Password>:<Nickname>:<Port>:<Class> + +`O' + Speficies Operator record. If you use capital letter ("O") in it, + it specifies a global operator. Small letter ("o") specifies a + local operator. Local operator has basically the same rights + except global operator with some restrictions. + +`TARGET Host NAME' + Tells IRC which host you have the privileges FROM. This means + that you should be logged into this host when you ask for the + priviliges. If you specify "tolsun.oulu.fi" then IRC will expect + your CLIENT to be connected at "tolsun.oulu.fi" - when you ask for + OPERATOR privileges from "tolsun.oulu.fi". You cannot be logged in + at any other host and be able to use your OPERATOR privileges at + tolsun, only when you are connected at TOLSUN will this work - + this is a safeguard against unauthorized sites. + +`Password' + If your AUTHORIZATION Password - this is the password that let's + IRC know you are who you say you are! Never tell anyone your + password and always keep the "ircd.conf" file protected from all + of the other users. + +`Nickname' + The Nickname you usually go by - but you can make this what you + want. + +`Port' + Unused. + +`Class' + The class field should refer to an existing class (preferably + having a lower number than that for the relevant I-line) and + determines the maximum number of simultaneous uses of the O-line + allowable through the max. links field in the Y-line. + +`Example' + O:orion.cair.du.edu:pyunxc:Jeff::1 + + There is an OPERATOR at "orion.cair.du.edu" that can get Operator + priviliges if he specifies a password of "pyunxc" and uses a + NICKNAME of "Jeff". + + +File: INSTALL.info, Node: Restrict connections, Next: Excluded accounts, Prev: Operator priviliges, Up: The ircd-conf file + +Restrict connections +==================== + + Let an external program decide if a client should be allowed or not. +`Introduction' + R lines provide a convenient way to handle user access to the + server with an external program. The outside program given three + parameters: the client's username (set by the USER command), the + client's hostname, and the client's ident reply ("unknown" if + none). + + It is expected to return a reply line where the first word is + either "Y" or "N" meaning `Yes Let them in" or "No don't let them + in". If the first word begins with neither "Y" or "N" the default + is to let the person on. + +`Format' + R:<Target Host Name>:<Program>:<User>::: + +`R' + This specifies a restrict record. + +`Target Host Name' + In this field you specify the Hostname that the user is connecting + from. If you wanted to restrict connects to IRC from + "orion.cair.du.edu" then you would want to enter + "orion.cair.du.edu". + +`Program' + This is the external program to run to know if the user is allowed + on your server. + +`User' + The Username of the user you want removed from IRC. For example + "root". + + +File: INSTALL.info, Node: Excluded accounts, Next: Server connections, Prev: Restrict connections, Up: The ircd-conf file + +Excluded accounts +================= + + Remove an errant user from IRC on your site. +`Introduction' + Obviously it is hoped that you wouldn't have to use this command. + Unfortunately sometimes a user can become unmanageable and this is + your only recourse - the KILL USER command. THIS COMMAND ONLY + AFFECTS YOUR SERVER - If this user can connect to another SERVER + somewhere else in the IRC-Network then you would have to talk to + the administrator on that site to disable his access from that + IRCD Server as well. + +`Format' + K:<Host Name>:<time interval(s)|comment>:<User>:<port>: + +`Format' + k:<Host Name>:<time interval(s)|comment>:<Auth>:<port>: + +`K' + "K" tells the IRCD that you are making a KILL USER command entry. + +`Host Name' + In this field you specify the Hostname or the IP address (Single + IP, Wildcard notation or bitmask notation) that the user is + connecting from. If you wanted to REMOVE connects to IRC from + "orion.cair.du.edu" then you would want to enter + "orion.cair.du.edu". If you want to REMOVE ALL HOSTS access you + can use "*" (Wild Card notation) and no matter what host the + USERNAME (specified in Field 4) connects from s/he will be denied + access. Removing all hosts isn't very smart thing to do though, + why would you run an ircd if you allow nobody to connect to it + anyways ? + + If you specify an IP address, IP mask, or an IP bitmask, it will + match clients connecting from the matching addresses, no matter if + they resolve or not. + + You can prefix an IP address, an IP mask, or IP bitmask by "=" in + which case only non resolving matching hosts will be banned. + +`time interval(s)|comment' + Either leave this field empty or put a comment, then the line + active continuously for the specified user/host machine. You may + also specify intervals during the line should be active, see + examples below. + +`User' + The USERNAME of the user you want removed from IRC. For example + "root". + +`Auth' + If the user's ident server replies with the OTHER type (as opposed + to the UNIX type), the reply is not used to set the user's + username. (lowercase) k lines can be used in these case to reject + users based on their ident reply. + + This field will be matched against the ident server reply. It is + important to note that OTHER replies are prefixed with a "-" by + the ircd, while UNIX replies are not. + +`Port' + The port on which the Kill line will be effective. 0 means all + ports. + +`Examples' + K:orion.cair.du.edu::jtrim:0: + + If user "jtrim" connects to IRC from host "orion.cair.du.edu" then + IMMEDIATELY REMOVE HIM from my IRCD. + + k:*.stealth.net::-43589:0: + + If a user connects from any host that has the suffix "stealth.net" + and if that host ident server returns "-43589" - then IMMEDIATELY + REMOVE THEM from my IRCD. + + K:*.cair.du.edu::root:0: + + If user "root" connects to IRC from any host that has the suffix + "cair.du.edu" - then IMMEDIATELY REMOVE THEM from my IRCD. + + K:*::vijay:0: + + This line reads "I don't care WHAT HOST user "vijay" is on, I will + NEVER allow username "vijay" to login to my IRCD." + + K:*.oulu.fi:0800-1200,1400-1900:*:0: + + This disallows all users from hosts with enddomain "oulu.fi" + access to your server between 8 and 12am, 2 and 7pm. Users get + kicked off if they're already signed on when the line becomes + active (they'll get a warning 5 minutes before). + + K:192.11.35.*::*:0: + + This line disallows all hosts whose IP address matches + "192.11.35.*" to login to the ircd. + + K:=192.11.35.*::*:0: + + This line disallows all hosts whose IP address matches + "192.11.35.*" and which didn't resolve to login to the ircd. + + +File: INSTALL.info, Node: Server connections, Next: Deny auto-connections, Prev: Excluded accounts, Up: The ircd-conf file + +Server connections +================== + + How to connect to other servers, How other servers can connect to you + + `WARNING:' The hostnames used as examples are really only examples +and not meant to be used (simply because they don't work) in real life. + + Now you must decide WHICH hosts you want to connect to and WHAT +ORDER you want to connect to them in. For my example let us assume I +am on the machine "rieska.oulu.fi" and I want to connect to irc daemons +on 3 other machines: + * "garfield.mit.edu" - Tertiary Connection + + * "irc.nada.kth.se" - Secondary Connection + + * "nic.funet.fi" - Primary Connection + + And I prefer to connect to them in that order, meaning I first want +to try connecting to "nic.funet.fi", then to "irc.nada.kth.edu", and +finally to "garfield.mit.edu". So if "nic.funet.fi" is down or +unreachable, the program will try to connect to "irc.nada.kth.se". If +irc.nada.kth.se is down it will try to connect to garfield and so forth. + + PLEASE limit the number of hosts you will attempt to connect to down +to 3. This is because of two main reasons: + 1. to save your server from causing extra load and delays to users + + 2. to save internet from extra network traffic (remember the old + rwho program with traffic problems when the number of machines + increased). + +`Format' + C:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<TARGET + PORT>:<Class> + + for example: + + C:nic.funet.fi:passwd:nic.funet.fi:6667:1 + + - or - + + C:128.214.6.100:passwd:nic.funet.fi:6667:1 + + - or - + + C:root@nic.funet.fi:passwd:nic.funet.fi:6667:1 + + Each field is separated with a ":" charcter: + +`C' + This field tells the IRC program which option is being configured. + "C" corresponds to a server Connect option. + +`TARGET Host Addr' + Specifies the host name or IP address of the machine to connect + to. If "user@" prefixes the actual hostname or IP address the + server will require that the remote username returned by the ident + server be the same as the one given before the "@". + +`Password' + The password of the other host. A password must always be present + for the line to be recognized. + +`TARGET Host NAME' + The full hostname of the target machine. This is the name that the + TARGET server will identify itself with when you connect to it. + If you were connecting to nic.funet.fi you would receive + "nic.funet.fi" and that is what you should place in this field. + +`TARGET PORT' + The INTERNET Port that you want to connect to on the TARGET + machine. Most of the time this will be set to "6667". If this + field is left blank, then no connections will be attempted to the + TARGET host, and your host will accept connections FROM the TARGET + host instead. The port field can contain 2 ports, separated by a + . In this case, the first port is used when auto-connecting, the + second port is used for the UDP pings to the targer server. + +`Class' + The class field should refer to an existing class and determines + the maximum number of simultaneous uses of the C-line allowable + through the max. links field in the Y-line. + +`NEW!!!' + As of the 2.9.3 version of the server, server connections can be + compressed with the zlib library. To define a compressed + connection, you must have compiled the server with ZIP_LINKS + defined (cf 2.h), and use a _lowercase_ C line. + + Some examples: + * C:nic.funet.fi::nic.funet.fi:6667:1 This reads: Connect to host + "nic.funet.fi", with no password and expect this server to + identify itself to you as "nic.funet.fi". Your machine will + connect to this host to port 6667. + + * C:18.72.0.252:Jeff:garfield.mit.edu:6667:1 This reads: Connect to + a host at address "18.72.0.252", using a password of "Jeff". The + TARGET server should identify itself as "garfield.mit.edu". You + will connect to Internet Port 6667 on this host. + + * C:irc.nada.kth.se::irc.nada.kth.se:1 This reads: do not attempt to + connect to "irc.nada.kth.se", if "irc.nada.kth.se" requests a + connection, allow it to connect. + + Now back to our original problem, we wanted OUR server CONNECT to 3 +hosts, "nic.funet.fi", "irc.nada.kth.se" and "garfield.mit.edu" in +that order. So as we enter these entries into the file they must be +done in `reverse' order of how we could want to connect to them. + + Here's how it would look if we connected "nic.funet.fi" first: + + C:garfield.mit.edu::garfield.mit.edu:6667:1 +C:irc.nada.kth.se::irc.nada.kth.se:6667:1 +C:nic.funet.fi::nic.funet.fi:6667:1 + + Ircd will attempt to connect to nic.funet.fi first, then to irc.nada +and finally to garfield. + + `Reciprocal entries:' Each "C" entry requires a corresponding "N" +entry that specifies connection priviliges to other hosts. The "N" +entry contains the password, if any, that you require other hosts to +have before they can connect to you. These entries are of the same +format as the "C" entries. + +`Format' + The format for the NOCONNECT entry in the "ircd.conf" is: + N:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<Domain + Mask>:<Class> + + Let us assume that "garfield.mit.edu" connects to your server and + you want to place password authorization authorization on + garfield. The "N" entry would be: + + N:garfield.mit.edu:golden:garfield.mit.edu:: + + This line says: expect a connection from host "garfield.mit.edu", + and expect a login password of "golden", and expect the host to + identify itself as "garfield.mit.edu". + + N:18.72.0.252::garfield.mit.edu:: + + This line says: expect a Connection from host "18.72.0.252", and + don't expect login password. The connecting host should identify + itself as "garfield.mit.edu". + +`N' + "N" corresponds to a server Noconnect option. + +`TARGET Host Addr' + Specifies the host name or IP address of the machine to connect + to. If "user@" prefixes the actual hostname or IP address the + server will require that the remote username returned by the ident + server be the same as the one given before the "@". + +`Password' + The password of the other host. A password must always be present + for the line to be recognized. If CRYPT_LINK_PASSWORD is defined + in config.h, this password must be crypted. + +`TARGET Host NAME' + The full hostname of the target machine. This is the name that the + TARGET server will identify itself with when you connect to it. + If you were connecting to nic.funet.fi you would receive + "nic.funet.fi" and that is what you should place in this field. + +`Domain Mask' + Domain masking, see below. + +`Class' + The class field should refer to an existing class. + +`Wildcards domains' + To reduce the great amount of servers in IRCnet wildcard DOMAINS + were introduced in 2.6. To explain the usage of wildcard domains + we take an example of such: + + *.de - a domain name matching all machines in Germany. + + Wildcard domains are useful in that ALL SERVERS in Germany (or any + other domain area) can be shown as one to the rest of the world. + Imagine 100 servers in Germany, it would be incredible waste of + netwotk bandwidth to broadcast all of them to all servers around + the world. + + So wildcard domains are a great help, but how to use them ? + + They can be defined in the N-line for a given connection, in place + of "Domain Mask" you write a magic number called wildcard count. + + Wildcard count tells you HOW MANY PARTS of your server's name + should be replaced by a wildcard. For example, your server's name + is "tolsun.oulu.fi" and you want to represent it as "*.oulu.fi" to + "nic.funet.fi". In this case the wildcard count is 1, because only + one word (tolsun) is replaced by a wildcard. + + If the wildcard count would be 2, then the wildcard domain would + be "*.fi". Note that with wildcard name "*.fi" you could NOT + connect to "nic.funet.fi" because that would result in a server + name `collision' (*.fi matches nic.funet.fi). + + I advice you to not to use wildcard servers before you know for + sure how they are used, they are mostly beneficial for backbones + of countries and other large areas with common domain. + + +File: INSTALL.info, Node: Deny auto-connections, Next: Hub connections, Prev: Server connections, Up: The ircd-conf file + +Deny auto-connections +===================== + +`Introduction' + D lines were implemented to give server administrators more + control on how auto connections are done. This will most likely + only be useful for big networks which have complex configurations. + +`Format' + D:<Denied Server Mask>:Denied Class:<Server Name>:Server Class: + +`Denied Server Mask' + This field is matched against all servers currently present on the + network. + +`Denied Class' + If this field contains a class number, it will match if any server + in that class is currently present on the network. Note that this + can be true for any server, even the ones not directly connected. + +`Server Mask' + This field is matched against the server name that the server + wants to auto connect to. + +`Server Class' + This field is used to match against the class to which belong the + servers for which an autoconnect is set. + +`Examples' + D:*.edu::*.fi:: + + Don't auto-connect to any "*.fi" server if any server present on + the network matches "*.edu". + + D::2:eff.org:3: + + Do now auto-connect to "eff.org", or any server in class "3" if a + server defined to be in class "2" is currently present on the + network. + + +File: INSTALL.info, Node: Hub connections, Next: Leaf connections, Prev: Deny auto-connections, Up: The ircd-conf file + +Hub connections +=============== + +`Introduction' + In direct contrast to L-lines, the server also implements H-lines + to determine which servers may act as a hub and what they may "hub + for". If a server is only going to supply its own name (ie act as + a solitary leaf) then no H-line is required for, else a H-line + must be added. + +`Format' + H:<Server Mask>:*:<Server Name>:: + +`Server Mask' + All servers that are allowed via this H-line must match the mask + given in this field. + +`Server Name' + This field is used to match exactly against a server name, + wildcards being treated as literal characters. + +`Examples' + H:*.edu::*.bu.edu:: + + Allows a server named "*.bu.edu" to introduce only servers that + match the "*.edu" name mask. + + H:*::eff.org:: + + Allows "eff.org" to introduce (and act as a hub for) any server. + +`Note' + It is possible to have and use multiple H-lines (or L-lines) for + the one server. eg: + + H:*.edu:*:*.bu.edu:: H:*.au:*:*.bu.edu:: + + is allowed as is + + L:*.edu:*:*.au:: L:*.com:*:*.au:: + + +File: INSTALL.info, Node: Leaf connections, Next: Version limitations, Prev: Hub connections, Up: The ircd-conf file + +Leaf connections +================ + +`Introduction' + To stop servers which should only act as leaves from hubs becoming + hubs accidently, the L line was introduced so that hubs can be + aware of which servers should and shouldnt be treated as leaves. A + leaf server is supposed to remain a node for the entirity of its + life whilst connected to the IRC server network. It is quite easy, + however for a leaf server to be incorrectly setup and create + problems by becoming a node of 2 or more servers, ending its life + as a leaf. The L line enables the administrator of an IRC "Hub + server" to "stop" a server which is meant to act as a leaf trying + to make itself a hub. If, for example, the leaf server connects + to another server which doesnt have an L-line for it, the one + which does will drop the connection, once again making the server + a leaf. + +`Format' + L:<Server Mask>:*:<Server Name>:<Max Depth>: + +`Server Mask' + Mask of which servers the leaf-like attributes are used on when + the server receives SERVER messages. The wildcards * and ? may be + used within this field for matching purposes. If this field is + empty, it acts the same as if it were a single * (ie matches + everything). + +`Server Name' + The name of the server connected to you that for which you want to + enforce leaf-like attributes upon. + +`Max Depth' + Maximum depth allowed on that leaf and if not specified, a value + of 1 is assumed. The depth is checked each time a SERVER message + is received by the server, the hops to the server being the field + checked against this max depth and if greater, the connection to + the server that made its leaf too deep has its connection dropped. + For the L-line to come into effect, both fields, 2 and 4, must + match up with the new server being introduced and the server which + is responsible for introducing this new server. + + +File: INSTALL.info, Node: Version limitations, Next: Excluded machines, Prev: Leaf connections, Up: The ircd-conf file + +Version limitations +=================== + +`Introduction' + V-lines are used to restrict server connecting to you based on + their version and on compile time options. + +`Format' + V:<Version Mask>:<Flags>:<Server Mask>:: + +`Version Mask' + The matching version number strings will be rejected. + +`Flags' + If any flag specified in this field is found in the peer's flags + string, it will be rejected. + +`Server Mask' + This field is used to match server names. The V line will be used + for servers matching the mask given in this field. + +`Server Type' + Both the `Version Mask' and the `Flags' should be prefixed with + the server type identification. This implementation uses the id + "`IRC"' (starting with version 2.10). + +`Examples' + V:IRC/021001*::*:: + + Disallows any "IRC" server which version is 2.10.1* to connect. + + V:IRC/021001*:IRC/D:*:: + + Disallows any "IRC" server which version is 2.10.1* or which has + been compiled with DEBUGMODE defined to connect. + + V:*/0209*:::: + + Disallows any server using the 2.9 protocol to connect. + +`Note' + It is possible to have and use multiple V-lines for the one server + mask. + + V:IRC/021001*::*:: + + V:IRC/021002*::*:: + + is allowed. + +`Protocol Version' + Only the 4 first digit of the `Version Number' are standard: they + define the protocol version. The remaining of the string is + implementation dependant; matches on this part should be used with + particular identification. + +`Flags' + are not standard. Therefore, this field `should always' contain a + specific identification. + + +File: INSTALL.info, Node: Excluded machines, Next: Service connections, Prev: Version limitations, Up: The ircd-conf file + +Excluded machines +================= + + Disallowing SERVERS in your irc net. +`Introduction' + In some cases people run into difficulties in net administration. + For one reason or another you do not want a certain server to be + in your net (for example because of the security holes it opens for + every server if it's not secured carefully). In that case you + should use Q-lines in your server. When you specify a server name + in Q-line, everytime some server link tries to introduce you a + server (remember, all server names are broadcast around the net), + that name is checked if it matches the Q-lines in your server. If + it matches, then `your server' disconnects the link. Note that just + placing Q-lines to your server probably results in `your server' + being left alone, unless other servers have agreed to have the + same Q-line in their ircd configuration files as well. + +`Example' + Q::of the security holes:foo.bar.baz:: + + This command excludes a server named "foo.bar.baz", the reason is + given to be security holes (you should give a reason, it is + polite). The first field is unused, so leave it empty. + + +File: INSTALL.info, Node: Service connections, Next: Bounce server, Prev: Excluded machines, Up: The ircd-conf file + +Service connections +=================== + +`Introduction' + The Service is a special kind of IRC client. It does not have the + full abilities of a normal user but can behave in a more active + manner than a normal client. + + Services are not intended for interactive usage, and are better + suited for automated clients. + +`Format' + S:<TARGET Host Mask>:<Password>:<Service Name>:<Service + Type>:<Class> + +`TARGET Host Mask' + The host mask should be set to match the host(s) from which the + service will be connecting from. This may be either an IP# or full + name (prefered). + +`Password' + This is the password which must be passed in the SERVICE command. + +`Service Name' + The name used by the service. Services don't have nicknames, but a + static name defined by the S line. + +`Service Type' + The type of service. It defines the priviledges given to the + service. Be very careful in the types you allow. The types can be + found in include/service.h + +`Class' + The class field should refer to an existing class. + +`Notes' + A service is not a very useful sort of client, it cannot join + channels or issue certain commands although most are available to + it. Services are rejected upon sending an unknown or unallowed + command. Services however, are not affected by flood control and + can be granted special privileges. It is therefore `wise to + oversee the use of S-lines with much care.' + + +File: INSTALL.info, Node: Bounce server, Next: Default local server (for local clients) `*OBSOLETED*', Prev: Service connections, Up: The ircd-conf file + +Bounce server +============= + +`Introduction' + This provides you a way to bounce clients to another server. This + information is provided to clients which are denied connection, + either because their connection class is full, or the server is + full, or they are not authorized to connect. + +`Format' + B:<Class|Host Mask>::<Server Name>:<Port>: + +`B' + This specifies a Bounce record. + +`Class|Host Mask' + This field specifies to which client this configuration line + applies to. It can be either a connection class number, a host + mask to be matched against the client's hostname, or an IP + address/mask/bitmask to be matched against the client's IP address. + + When the server is completely full, it rejects clients with the + "All connections in use" message. In this case, the server + doesn't process the connections at all, and has no knowledge of + the client's host name, or class number. For these cases, this + field must be empty. + +`Server Name' + This specifies the IRC server hostname that the client should use. + +`Port' + This specifies the IRC server port that the client should connect + to. + +`Example' + B:2::irc.stealth.net:6660: + + Rejected clients in class 2 are advised to use "irc.stealth.net" + on port 6660. + + B:*.fi::irc.funet.fi:6667: + + Finnish client should use irc.funet.fi when they cannot be taken + anymore. + + B:::irc2.stealth.net:6667: + + When the server is completely full, clients should use the + secondary server. + + +File: INSTALL.info, Node: Default local server (for local clients) `*OBSOLETED*', Prev: Bounce server, Up: The ircd-conf file + +Default local server (for local clients) `*OBSOLETED*' +====================================================== + +`Introduction' + This defines the default connection for the irc client. If you + are running an ircd server on the same machine, you will want to + define this command to connect to your own host. If your site is + not running a server then this command should contain the TARGET + host's connection information and password (if any). + +`Format' + U:<TARGET Host addr>:<Password>:<TARGET Host NAME>:<Internet Port> + +`Examples' + U:tolsun.oulu.fi::tolsun.oulu.fi:6667 + + U:128.214.5.6::tolsun.oulu.fi:6667 + + U:tolsun.oulu.fi::tolsun.oulu.fi + + If the port number is omitted, irc will default to using 6667. + + +File: INSTALL.info, Node: Related resources, Next: Reporting a bug, Prev: The ircd-conf file, Up: Top + +Related resources +***************** + +`Mailing list' + A list is dedicated to the people using ircd. If you have trouble + running ircd, or wish to discuss the future, you can subscribe by + sending an email to , with "`subscribe ircd-users"' in the body. + + If you just have a question and don't want to subscribe to the + list, mail to . Be sure to indicate which version you are using. + +`Development' + Technical discussions and development are carried on + ircd-dev@irc.org. People interested in very early testing, and/or + working on the source code are welcome. This is done by sending + an email to , with "`subscribe ircd-dev"' in the body. + +`FAQ' + It can be found on the WWW, at . + +`WWW 2.9' + Vesa Ruokonen has also put serveral pages related to the 2.9 + servers on the WWW: . + + +File: INSTALL.info, Node: Reporting a bug, Prev: Related resources, Up: Top + +Reporting a bug +*************** + + If you encounter a bug in the software, here is how and where to +report it. + +* Menu: + +* How to report a bug:: +* Where to send a bug report:: + + +File: INSTALL.info, Node: How to report a bug, Next: Where to send a bug report, Up: Reporting a bug + +How to report a bug +=================== + + To save everyone time, make sure that your e-mail contains all the +information related to your problem. In particular, we need to know: +`Package version' + The IRC software version you are using: please include the output + obtained by running "irc -v" for the client, and/or "ircd -v" for + the server. + + Also, let us know if you have applied any patch to the package or + if it is the vanilla version. + +`OS' + Please, indicate which OS version you are running. + +`Configuration' + If it is related to a configuration problem with the server, + include the relevant parts of the configuration file. + +`Backtrace' + If the bug results in a crash, please include the backtrace. + (This can be done, for example, by running "gdb" on the core file, + and typing "where"). + +`Fix' + If you have a fix, don't forget to include it. + + +File: INSTALL.info, Node: Where to send a bug report, Prev: How to report a bug, Up: Reporting a bug + +Where to send a bug report +========================== + + Reports should be sent to . Your report will be reviewed and +forwarded to the appropriate mailing list. + + + +Tag Table: +Node: Top122 +Node: Installing IRC-630 +Node: The configure script855 +Node: Notes for Cygwin32 users3143 +Node: Notes concerning IPv6 support4196 +Node: The config-h file4794 +Node: Define what type of UNIX your machine uses-5466 +Node: DEBUGMODE5866 +Node: CPATH MPATH LPATH PPATH TPATH QPATH OPATH6530 +Node: CACHED_MOTD7758 +Node: CHROOTDIR8234 +Node: ENABLE_SUMMON ENABLE_USERS8558 +Node: SHOW_INVISIBLE_LUSERS NO_DEFAULT_INVISIBLE9094 +Node: OPER_KILL OPER_REHASH OPER_RESTART LOCAL_KILL_ONLY9777 +Node: ZIP_LINKS ZIP_LEVEL10409 +Node: SLOW_ACCEPT11420 +Node: CLONE_CHECK12038 +Node: Other #define's12378 +Node: Editing the Makefile and compiling12703 +Node: The ircd-conf file13343 +Node: Machine information15375 +Node: Administrative info17471 +Node: Port connections19506 +Node: Connection Classes21716 +Node: Client connections27167 +Node: Operator priviliges32680 +Node: Restrict connections34800 +Node: Excluded accounts36115 +Node: Server connections40081 +Node: Deny auto-connections48520 +Node: Hub connections49893 +Node: Leaf connections51109 +Node: Version limitations53192 +Node: Excluded machines54949 +Node: Service connections56256 +Node: Bounce server57849 +Node: Default local server (for local clients) `*OBSOLETED*'59551 +Node: Related resources60434 +Node: Reporting a bug61372 +Node: How to report a bug61632 +Node: Where to send a bug report62645 + +End Tag Table diff --git a/doc/INSTALL.sgml b/doc/INSTALL.sgml new file mode 100644 index 0000000..b24e36f --- /dev/null +++ b/doc/INSTALL.sgml @@ -0,0 +1,1388 @@ +<!doctype linuxdoc system> + +<article> + +<title>Installing IRC - The Internet Relay Chat Program +<author>SGML version by Christophe Kalt +<date>$Id: INSTALL.sgml,v 1.38 1999/08/13 17:19:52 kalt Exp $ +<abstract> +This document describes how to install, and configure IRC 2.10.3. +</abstract> + +<sect>Installing IRC. +<sect1>The configure script +<p> +This package uses a GNU configure script for its configuration. +You simply need to untar the distribution and run the +``configure'' script. This will run configure which will probe +your system for any peculiarities it has and setup the Makefile +and a file of default #define's ($arch/setup.h). +<p> +There are a few options to ``configure'' to help it out, or +change the default behaviour: +<descrip> +<tag/--prefix=DIR/ changes the default directory into which +ircd will install using ``make install''. This defaults +to /usr/local +<tag/--sbindir=DIR/ changes the default directory where the +system admin executable files will go. It is important to +set this properly. (default is prefix/sbin) +<tag/--logdir=DIR/ changes the default directory where the +irc log files will go. (default is prefix/var/log/ircd) +<tag/--sysconfdir=DIR/ changes the default directory where +the irc server configuration files will go. (default is prefix/etc) +<tag/--localstatedir=DIR/ changes the default directory +where the irc server state files will go. (default is prefix/var/run) +<tag/--resconf=FILE/ defines the file to be used by ircd to +initialize its resolver. (default is /etc/resolv.conf) +<tag/--zlib-include=DIR/ specifies in which directory the +include file from the zlib is located. +<tag/--zlib-library=DIR/ specifies in which directory the +zlib library is located. +<tag/--zlib-prefix=DIR/ specifies the prefix for zlib +location. It overrides the 2 previous options. (The +include directory is supposed to be in prefix/include, and +the library in prefix/lib). +<tag/--with-zlib/ is the default. ``configure'' looks on your +system to find the zlib. If found, ircd will be linked using +it. This does NOT mean you can use server link compression, +for this you also need to define ZIP_LINKS (see section below). +<tag/--without-zlib/ tells ``configure'' not to look for the zlib. +Defining this will keep you from using server link compression. +<tag/--enable-ip6/ Enable IPv6 support (See notes below) +<tag/--enable-dsm/ Enable Dynamically Shared Modules support for iauth +</descrip> + +<sect1>Notes for Cygwin32 users +<p> +The daemon of 2.10.3 release compiles properly on W32 +systems which have the GNU-Win32 environment (<url +url="http://www.cygnus.com/misc/gnu-win32/">) setup. At the +time of the release, tests were made using the version b20.1 +of the Cygwin32 library. +<p> +When compiling on such system, you want to make sure that +you have carefully followed the Cygwin32 installation +notes. In particular, you will need to make sure that the +following files exist: <bf>/bin/cp.exe</bf>, +<bf>/bin/mv.exe</bf>, <bf>/bin/rm.exe</bf> and +<bf>/bin/sh.exe</bf>. +<p> +Also, the IRC server needs a <bf>resolv.conf</bf> file in +order to initialize the resolver. This file can be anywhere +(see configure options), and is typically in <bf>/etc</bf> +on UNIX systems. +<p> +Finally, iauth is automatically disabled. Even though the +iauth program compiles properly, extra work is required to +have a working communication channel between the IRC server +and the iauth program. + +<sect1>Notes concerning IPv6 support +<p> +The only part of the software that doesn't use IPv6 is the +server internal resolver. It relies on the name servers +defined in ``/etc/resolv.conf'' to be IPv4 addresses. +<p> +This version was tested on the following IPv6 systems: +BSD/OS+KAME, Digital Unix, FreeBSD+KAME, Linux, NetBSD+INRIA. +<p> +Because IPv6 numeric addresses contain ``:'' characters, +<bf>the separator for the server configuration file was +changed to ``%''</bf>. + +<sect>The config.h file +<p> +The second step consists of defining options before the +compilation. This is done by editing the ``config.h'' file +and changing the various #DEFINE's. + +<sect1>Define what type of UNIX your machine uses. +<p> +Pick the machine type which best describes your machine and +change the #undef to #define (if needed).Some +flavours of Unix require no #define and in such cases +all others should be #undef'd. + +<sect1>DEBUGMODE +<p> +Define DEBUGMODE if you want to see the ircd debugging +information as the daemon is running. Normally this function +will be undefined as ircd produces a considerable amount of +output. DEBUGMODE must be defined for either of -t or -x +command line options to work. Defining this induces a large +overhead for the server as it does a large amount of self +diagnostics whilst running. +<p> +<bf>This should only be defined for test purposes, and never +used on a production server.</bf> + +<sect1>CPATH, MPATH, LPATH, PPATH, TPATH, QPATH, OPATH +<p> +Define CPATH to be the directory path to the ``ircd.conf'' +file. This path is usually /usr/local/lib/ircd/ircd.conf. The +format of this file will be discussed later. +<p> +The LPATH #define should be set to ``/dev/null'' unless +you plan to debug the ircd program. Note that the logfile grows +very quickly. +<p> +Define MPATH to be the path to the ``motd'' (message of the +day) file for the server. Keep in mind this is +automatically displayed whenever anyone signs on to your +server. +<p> +The PPATH is optional, but if defined, should point to a +file which either doesn't exist (but is creatable) or a +previously used PPATH file. It is used for storing the +server's PID so a ps(1) isn't necessary. +<p> +Define QPATH to be the directory path to the ``iauth.conf'' +file. This path is usually /usr/local/lib/ircd/iauth.conf. +The format of this file is described by a manual page. +<p> +The OPATH #define should be set to ``/dev/null'' unless +you plan to debug the iauth program. Note that the logfile grows +very quickly. + +<sect1>CACHED_MOTD +<p> +The server sends the ``motd'' to every client connecting. +Every time, it reads it from the disk. This is quite +intensive and can be undesirable for busy servers. +<p> +Defining CACHED_MOTD will make the server store the ``motd'' +in memory, and only read it again from the disk when +rehashing if the file has changed. + +<sect1>CHROOTDIR +<p> +To use the CHROOTDIR feature, make sure it is #define'd +and that the server is being run as root. The server will +chroot to the directory name provded by ``IRCDDIR'' (in +Makefile). + +<sect1>ENABLE_SUMMON, ENABLE_USERS +<p>For security conscious server admins, they may wish to +leave ENABLE_USERS undefined, disabling the USERS command +which can be used to glean information the same as finger +can. ENABLE_SUMMON toggles whether the server will attempt +to summon local users to irc by writing a message similar to +that from talk(1) to a user's tty. + +<sect1>SHOW_INVISIBLE_LUSERS, NO_DEFAULT_INVISIBLE +<p> +On large IRC networks, the number of invisible users is +likely to be large and reporting that number cause no pain. +To aid and effect this, SHOW_INVISIBLE_LUSERS is provided to +cause the LUSERS command to report the number of invisible +users to all people and not just operators. The +NO_DEFAULT_INVISIBLE define is used to toggle whether +clients are automatically made invisible when they register. + +<sect1>OPER_KILL, OPER_REHASH, OPER_RESTART, LOCAL_KILL_ONLY +<p>The three operator only commands, KILL, REHASH and +RESTART, may all be disabled to ensure that an operator who +does not have the correct privilidges does not have the +power to cause untoward things to occur. To further curb the +actions of guest operators, LOCAL_KILL_ONLY can be defined +to only allow locally connected clients to be KILLed. + +<sect1>ZIP_LINKS, ZIP_LEVEL +<p> +As of the 2.9.3 version of the server, server-server +connections may be compressed using the zlib. In order to +compile the server with this feature, you MUST have the zlib +package (version 1.0 or higher) already compiled and define +ZIP_LINKS in the config.h file. Compression use for +server-server connections is separately configured in the +ircd.conf file for each server-server link. ZIP_LEVEL +allows you to control the compression level that will be +used. Values above 5 will noticeably increase the CPU used +by the server. +<p> +The zlib package may be found at <url +url="http://www.cdrom.com/pub/infozip/zlib/">. The data format used +by the zlib library is described by RFCs (Request for +Comments) 1950 to 1952 in the files <url +url="ftp://ds.internic.net/rfc/rfc1950.txt"> (zlib format), +rfc1951.txt (deflate format) and rfc1952.txt (gzip +format). These documents are also available in other formats +from <url url="ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html"> + +<sect1>SLOW_ACCEPT +<p> +This option is defined by default and is needed on some +OSes. It creates an artificial delay in processing incoming +connections. On a given port, no more than 1 connection per +2 seconds will be processed. +<p> +Undefining this will let the server process connections as +fast as it can which can cause problems on some OSes (such +as SunOS) and be abused (fast massive join of clonebots..), +for these reasons, if you decide to undefine SLOW_ACCEPT you +MUST define CLONE_CHECK. + +<sect1>CLONE_CHECK +<p> +This option acts as a wrapper, by checking incoming +connections early before starting ident query. By default, +the server will not accept more than 2 connections from the +same host within 10 seconds. + +<sect1>Other #define's +<p> +The rest of the user changable #define's should be +pretty much self explanatory in the config.h file. It is +*NOT* recommended that any of the file undef the line with +"STOP STOP" in it be changed. + +<sect>Editing the Makefile, and compiling +<p> +This package now uses GNU autoconf to probe your system and +generate the correct Makefile. However you need to edit it +to specify specific information, such as ``prefix'', +``irc_mode'', ``ircd_mode'' and ``ircd_dir''. +<p> +Now to build the package, type ``make all''. If everything +goes will, you can then install it by typing ``make install''. +<p> +If you have trouble compiling ircd, copy Makefile.in to +Makefile and edit Makefile as appropriate. + +<sect>The ircd.conf file +<p> +After installing the ircd and irc programs, edit the +ircd.conf file as per the instructions in this section and +install it in the location you specified in the config.h +file. There is a sample conf file called example.conf in +the doc/ directory. +<p> +Appendix A (See INSTALL.appendix) describes the differences +between IP addresses and host names. If you are unfamiliar +with this, you should probably scan through it before +proceeding. +<p> +The ircd.conf file contains various records that specify +configuration options. The record types are as follows: +<enum> +<item>Machine information (M) +<item>Administrative info (A) +<item>Port connections (P) +<item>Connection Classes (Y) +<item>Client connections (I,i) +<item>Operator privileges (O) +<item>Restrict lines (R) +<item>Excluded accounts (K,k) +<item>Server connections (C,c,N) +<item>Deny auto-connections (D) +<item>Hub connections (H) +<item>Leaf connections (L) +<item>Version limitations (V) +<item>Excluded machines (Q) +<item>Service connections (S) +<item>Bounce server (B) +<item>Default local server (U) +</enum> +<p> +Except for types ``M'' and ``A'', you are allowed to have +multiple records of the same type. In some cases, you can +have concurrent records. <bf>It is important to note that +the last matching record will be used</bf>. This is +especially useful when setting up I records (client +connections). + +<sect1>Machine information +<p> +<descrip> +<tag/Introduction/ +IRC needs to know a few things about your UNIX site, and the +``M'' command specifies this information for IRC. The fomat +of this command is: +<tag/Format/ +<verb>M:<Server NAME>:<YOUR Internet IP#>:<Geographic Location>:<Port></verb> +<tag/M/ +``M'' specifies a Machine description line +<tag/Server NAME/ +The name of YOUR server adding any Internet DOMAINNAME that +might also be present. If this hostname can be resolved, the +IP# found will be used to for outgoing connections. +Otherwise the default interface address of the host is used. +The server name may not be FQDN of another host. (This +means all outgoing connections will be done from the same +IP#, even if your host has several IP#). +<tag/YOUR Internet IP#/ +If the machine on which you run the server has several IP +addresses, you can define which IP# to use for outgoing +connections. This overrides overrides the ``Server NAME''. +<p>See Also the ``Port Connections'' section. +<tag/Geographic Location/ +Geographic Location is used to say WHERE YOUR SERVER is, and +gives people in other parts of the world a good idea of +where you are! If your server is in the USA, it is usually +best to say: <CITY> <STATE>, USA. Like for +Denver I say: ``Denver Colorado, USA''. Finnish sites (like +tolsun.oulu.fi generally say something like ``Oulu, +Finland''. +<tag/Port/ +Defines the port on which your server will listen for UDP +pings from other servers. This should be the port were +other servers are set to autoconnect. (Also see the port +field description in connect lines). +<tag/Example:/ +M:tolsun.oulu.fi::Oulu, Finland:6667: +<p> +This line reads: My Host's name is ``tolsun.oulu.fi'' and my +site is located in ``Oulu, Finland''. +<p> +M:orion.cair.du.edu::Denver Colorado, USA:6667: +<p> +This line reads: My Hosts name is ``orion.cair.du.edu'' and +my site is located in ``Denver Colorado, USA''. +</descrip> +<p> + +<sect1>Administrative info +<p> +<descrip> +<tag/Introduction/ The ``A'' line is used for administrative +information about a site. The e-mail address of the person +running the server should be included here in case problems +arise. +<tag/Format/<verb>A:<Your Name/Location>:<Your Electronic Mailing Addr>:<other>::</verb> +<tag/A/This specifies an Admin record. +<tag/Your Name & Location/ Use this field to say tell +your FULL NAME and where in the world your machine is. Be +sure to add your City, State/Province and Country. +<tag/Your Electronix Mailing Addr/ Use this field to specify +your Electronic Mailing Address preferably your Internet +Mailing Address. If you have a UUCP or ARAPnet address - +please add that as well. Be sure to add any extra DOMAIN +information that is needed, for example ``mail jtrim@orion'' +probably won't work as a mail address to me if you happen to +be in Alaska. But ``mail jtrim@orion.cair.du.edu'' would +work because you know that ``orion'' is part of the DOMAIN +``cair.du.edu''. So be sure to add your DOMAINNAMES to your +mailing addresses. +<tag/Other/ This is really an OTHER field - you can add what +you want here. +<tag/Example/ +(the line is just one line in the confuration file, here it +is cut into two lines to make it clearer to read): +<p> +A:Jeff Trim - Denver Colorado, USA:INET jtrim@orion.cair.du.edu UUCP {hao,isis}!udenva!jtrim:Terve! Heippa! Have you said hello in Finnish today?;):: +<p> +Would look like this when printed out with the /admin command: +<p> +Jeff Trim - Denver Colorado, USA +INET jtrim@orion.cair.du.edu UUCP {hao,isis}!udenva!jtrim +Terve! Hei! Heippa! Have you said hello in Finnish today? ;) +<p> +Note that the A record cannot be split across multiple +lines; it will typically be longer than 80 characters and +will therefore wrap around the screen. +</descrip> + +<Sect1>Port connections +<p> +<descrip> +<tag/Introduction/ The port line adds flexibility to the +server's ability to accept connections. By use of this line +in the ircd.conf file, it is easy to setup both Unix Domain +ports for the server to accept connections on as well as +extra internet ports. +<tag/Format/<verb>P:<Internet IP#>:<*>:<Internet IP Mask>:<Port>: +P:<Directory>:<*>:<*>:<Port>:</verb> +</descrip> +<itemize> +<item>Internet Ports +<descrip> +<tag/Internet IP#/ If the host on which the server runs has +several IP addresses, you can define for which IP address +connections will be accepted. If no is defined here, server +will bind to all interfaces (INADDR_ANY). See also MACHINE +CONFIGURATION section to properly configure outgoing +connections. +<p> +P:192.168.1.194:::6664: +<tag/Internet IP# Mask/ This defines where connections may +come from and be accepted. The IP mask uses either *'s or +0's as wildcards. The following two lines are the same: +<p> +<verb>P:::128.2.*:6664: +P:::128.2.0.0:6664: +</verb> +<p> +The incoming isn't matched against the mask, rather the ip# +string is decoded and compared segment by segment. Thus +<p> +P:::128.2*.1.2:6664: +<p> +will not match 128.20.1.2. +<tag/Port/ The port number field tells the server which port +number it should listen on for incoming connections. +</descrip> +<item> Unix Socket Ports. +<descrip> +<tag/Directory/ The path set in this field should be the +directory name in which to create the unix socket for later +listening to. The server will attempt to create the +directory before creating the unix socket. +<tag/Port/ The port field when used in combination with a +pathname in a P-line is the filename created in the +directory set in the first field. +<tag/Example/ P:/tmp/.ircd:::6667: +<p> +Creates a unix socket in the /tmp/.ircd directory called +``6667''. The unix socket (file) must be a numerical. +</descrip> +</itemize> +<descrip> +<tag/Note/ You need at least one P line. +</descrip> + +<sect1>Connection Classes +<p> +<descrip> +<tag/Introduction/ To enable more efficient use of +MAXIMUM_LINKS, connection classes were implemented. All +clients belong to a connection class. +<p>Each line for a server should have the same number as the +sixth field. If it is absent, the server deaults it to 0, +using the defaults from the config.h file. +<p>To define a connection class, you need to include a Y: +line in the ircd.conf file. This enables you to define the +ping frequency, connection frequency (for servers) and +maximum number of links that class should have. +<p>Currently, the Y: line <bf>MUST</bf> appear in the +ircd.conf file <bf>BEFORE</bf> it is used in any other way. +<tag/Format/<verb>Y:<Class>:<Ping Frequency>:<Connect freq>:<Max Links>:<SendQ>:<Local Limit>:<Global Limit></verb> +<tag/Y/ This specifies a Class record. +<tag/Class/ This is the class number which gains the following +attributes and should match that which is on the end of the +C/c/N/I/O/S line. +<tag/Ping Frequency/ This field defines how long the server will let +the connection remain ``silent'' before sending a PING message +to make sure it is still alive. Unless you are sure of what +you are doing, use the default value which is in your +config.h file. +<tag/Connect Frequency/ By changing this number, you change +how often your server checks to see if it can connect to +this server. If you want to check very occasionally, use a +large value, but if it is an important connection, you might +want a smaller value so that you connect to it as soon as +possible. +<tag/Max Links/ This field defines the maximum number of +links this class will allow from automatic connections (C +lines). Using /CONNECT overrides this feature. Also +defines the maximum number of users in this class for I/O +lines per I/O line. +<tag/SendQ/ This field defines the ``SendQ'' value for this +class. If this field is not present, the default (from +config.h) is assigned. +<tag/Local limit/ This field is used to limit the number +of local concurrent connections. The format is +<x>.<y> +<itemize> +<item> x: defines the maximum number of clients from the +same host (IP) will be allowed. +<item> y: defines the maximum number of clients from the +same user@host (IP) will be allowed. Read note below. +</itemize> +Only x or y may be set, any unset value defaults to zero. +<tag/Global limit/ This field has the same use as the +``Local limit'' field. But, the connection counts are done +for all clients present on the net instead of only counting +local clients. +<tag/Note/ leaving any of the fields (except SendQ) out +means their value is 0 (ZERO)!! The SendQ field default +value is dynamically determined. +<tag/Note/ If you plan to use the local user@host limit, +please read the following very carefully. The ``user'' +value is the ident reply for the connection. If no reply +was given then it defaults to ``unknown'' and thus the +effective limit will be per host, not per user@host. Also, +some ident servers return encrypted data which changes for +every connection making the limit void. +<tag/Note/ Only the local limitation is accurate. +<tag/Note/ If you define a gobal limit, you should also +define a local limit (same or lower) as it won't take more +CPU and will make the global limit more accurate. +<tag/Note/ The local and global limits only affect users (I +lines), not servers nor services. +<tag/Example/ Y:23:120:300:5:100000:0:0: (server class) +<p> +This defines class 23 to allow 5 auto-connections, which are +checked every 300 seconds. The connection is allowed to +remain silent for 120 seconds before a PING is sent. NOTE: +fields 3 & 4 are in seconds. The SendQ is set to 100000 +bytes. +<p> +Another feature of connection class is the ability to do +automatic routing by using the class as a ``priority''. If +you are connected to a server which has a class lower than +one of the servers that is ``behind'' it, the server will +disconnect the lower class one and schedule a ``new'' +connection for the higher class server. +<p> +Y:1:60:0:50:20000:2:5: (client class) +<p> +In case of a client class, the fields are interpreted a bit +differently. This class (number 1) can be used by up to 50 +users. The connections are allowed to remain silent for 60 +seconds before a PING is set. The SendQ is set to 20000 +bytes. A new connection in this class will only be allowed +if there aren't more than 2 other local connections from the +same IP address, or more than 5 other connections on the net +from the same hostname. +<p> +Y:2:60:0:50:20000:2.1:5: (client class) +<p> +In case of a client class, the fields are interpreted a bit +differently. This class (number 1) can be used by up to 50 +users. The connections are allowed to remain silent for 60 +seconds before a PING is set. The SendQ is set to 20000 +bytes. A new connection in this class will only be allowed +if there aren't more than 2 other local connections from the +same IP address, 1 other local connection from the same user +from the same IP address, or more than 5 other connections +on the net from the same hostname. +</descrip> + +<sect1>Client connections +<p> +How to let clients connect to your IRCD. +<descrip> +<tag/Introduction/ A client is a program that connects to +the ircd daemon (ircd). There are clients written in C, GNU +Emacs Lisp and many other languages. The ``irc'' program is +the C client. Each person that talks via IRC is running +their own client. +<p> +The ircd.conf files contains entries that specify which +clients are allowed to connect to your irc daemon. +Obviously you want to allow your own machine's clients to +connect. You may want to allow clients from other sites to +connect. These remote clients will use your server as a +connection point. All messages sent by these clients will +pass through your machine. +<tag/Format/ +<verb>I:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class> +i:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class></verb> +<tag/TARGET Host Addr/Specifies the IP address(es) of the +machine(s) that are allowed to connect. If ``user@'' +prefixes the actual IP address the server will require that +the remote username returned by the ident server be the same +as the one given before the ``@''. Wildcards are permitted +unless using a bitmask (e.g. 1.2.3.0/24). +<tag/Password/The password that must be given by the client +to be allowed on the server. +<tag/TARGET Host NAME/Specifies the host name(s) of the +machines allowed to connect to the server. If ``user@'' +prefixes the actual IP address the server will require that +the remote username returned by the ident server be the same +as the one given before the ``@''. Wildcards are permitted. +<p> +This field can be empty, it then has a special meaning. See +Below. +<tag/Port/Specifies the port number for which this +configuration line is valid. An empty field, or ``0'' +matches all ports. +<tag/Class/This field should refer to an existing class. +Connections classes are usefull to limit the number of users +allowed on the server. +<tag/Note/The server first checks if the client hostname (or +any aliases) matches the <bf>TARGET Host NAME</bf> field. +If a match is found, the client is accepted. If not, the +server checks if the IP address of the client matches the +<bf>TARGET Host Addr</bf> field. The matching field is used +to set the name of the client: for example, if the client +matches the <bf>TARGET Host Addr</bf> field, it will show on +IRC with a numerical address (even if this address is +resolvable). If the <bf>TARGET Host NAME</bf> field is +empty, then the host name is always used (when available). +<tag/Examples/ +For example, if you were installing IRC on tolsun.oulu.fi +and you wanted to allow examples sake let us assume you were +making this file for tolsun and you wanted to let your own +clients to connect to your server, you would add this entry +to the file: +<p> +I:x::tolsun.oulu.fi::1 +<p> +If you wanted to let remote clients connect, you could add +the following lines: +<p> +I:x::*.du.edu::1 +<p> +Allow any clients from machines whose names end in +``.du.edu'' to connect with no password. +<p> +I:128.214.6.100::nic.funet.fi::1 +<p> +Allow clients from a machine with that IP number to +connect. Numeric match is enough, name is not required +anymore. +<p> +I:x:secret:*.tut.fi::1 +<p> +Allow clients from machines matching ``*.tut.fi'' to connect +with the password ``secret''. +<p> +I:*::*::1 +<p> +Allow anyone from anywhere to connect your server. +<p> +This is the easiest way, but it also allows people to for +example dump files to your server, or connect 1000 (or how +many open sockets per process your OS allows) clients to +your machine and take your network ports. Of course the same +things can be done by simply telnetting to your machine's +SMTP port (for example). +<p> +I:x::*.fi:6667:1 +<p> +Allow clients from machines matching ``*.fi'' to connect on +the port 6667. +<p> +I:135.11.35.*::*.net::1 +<p> +Allows clients from machines which host name matches +``*.net'' or which IP address matches ``135.11.35.*'' to +connect to the server. If the host name does not match +``*.net'' then the IP address is used for these clients, +even if the host name is known. +<p> +I:135.11.35.*::::1 +<p> +Allows clients from machines which IP address matches +``135.11.35.*'' to connect to the server. If the host name +is known, is it used as address for these clients. +<tag/NEW!!!/ As of the 2.7.2d version of the server, the +server is able to accept connections on multiple +ports. I-lines are required for each P-line to allow +connections to be accepted. For unix sockets, this means +either adding I:/path/port::/path/port or some variation +(wildcards are recognised here). For internet ports, there +must be an I-line which allows the host access as normal, +but the port field of the I-line must match that of the port +of the socket accepting the connectiion. A port number of 0 +is a wildcard (matches all ports). +<tag/NEW!!!/ As of the 2.9.1 version of the server, i lines +are introduced. They work the same way as I lines, but the +clients matching an i line will have a restricted +connection. (no nick/mode change, no kick). Such users will +have their username prefixed by +, = or - depending on the +ident reply. +</descrip> + +<sect1>Operator priviliges +<p> +How to become the IRC administrator on your site +<descrip> +<tag/Introduction/ To become an IRC Administrator, IRC must +know who is authorized to become an operator and what their +``Nickname'' and ``Password'' is. +<tag/Format/<verb>O:<TARGET Host NAME>:<Password>:<Nickname>:<Port>:<Class></verb> +<tag/O/ Speficies Operator record. If you use capital letter +(``O'') in it, it specifies a global operator. Small letter +(``o'') specifies a local operator. Local operator has +basically the same rights except global operator with some +restrictions. +<tag/TARGET Host NAME/ Tells IRC which host you have the +privileges FROM. This means that you should be logged into +this host when you ask for the priviliges. If you specify +``tolsun.oulu.fi'' then IRC will expect your CLIENT to be +connected at ``tolsun.oulu.fi'' - when you ask for OPERATOR +privileges from ``tolsun.oulu.fi''. You cannot be logged in +at any other host and be able to use your OPERATOR +privileges at tolsun, only when you are connected at TOLSUN +will this work - this is a safeguard against unauthorized +sites. +<tag/Password/ If your AUTHORIZATION Password - this is the +password that let's IRC know you are who you say you are! +Never tell anyone your password and always keep the +``ircd.conf'' file protected from all of the other users. +<tag/Nickname/ The Nickname you usually go by - but you can +make this what you want. +<tag/Port/ Unused. +<tag/Class/ The class field should refer to an existing +class (preferably having a lower number than that for the +relevant I-line) and determines the maximum number of +simultaneous uses of the O-line allowable through the +max. links field in the Y-line. +<tag/Example/ O:orion.cair.du.edu:pyunxc:Jeff::1 +<p> +There is an OPERATOR at ``orion.cair.du.edu'' that can get +Operator priviliges if he specifies a password of ``pyunxc'' +and uses a NICKNAME of ``Jeff''. +</descrip> + +<sect1>Restrict connections +<p> +Let an external program decide if a client should be allowed +or not. +<descrip> +<tag/Introduction/ R lines provide a convenient way to +handle user access to the server with an external program. +The outside program given three parameters: the client's +username (set by the USER command), the client's hostname, +and the client's ident reply (``unknown'' if none). +<p>It is expected to return a reply line where the first +word is either ``Y'' or ``N'' meaning `Yes Let them in'' or +``No don't let them in''. If the first word begins with +neither ``Y'' or ``N'' the default is to let the person on. +<tag/Format/ +<verb>R:<Target Host Name>:<Program>:<User>:::</verb> +<tag/R/This specifies a restrict record. +<tag/Target Host Name/ In this field you specify the +Hostname that the user is connecting from. If you wanted to +restrict connects to IRC from ``orion.cair.du.edu'' then you +would want to enter ``orion.cair.du.edu''. +<tag/Program/ This is the external program to run to know if +the user is allowed on your server. +<tag/User/ The Username of the user you want removed from +IRC. For example ``root''. +</descrip> + +<sect1>Excluded accounts +<p> +Remove an errant user from IRC on your site. +<descrip> +<tag/Introduction/ +Obviously it is hoped that you wouldn't have to use this +command. Unfortunately sometimes a user can become +unmanageable and this is your only recourse - the KILL USER +command. THIS COMMAND ONLY AFFECTS YOUR SERVER - If this +user can connect to another SERVER somewhere else in the +IRC-Network then you would have to talk to the administrator +on that site to disable his access from that IRCD Server as +well. +<tag/Format/<verb>K:<Host Name>:<time interval(s)|comment>:<User>:<port>:</verb> +<tag/Format/<verb>k:<Host Name>:<time interval(s)|comment>:<Auth>:<port>:</verb> +<tag/K/``K'' tells the IRCD that you are making a KILL USER +command entry. +<tag/Host Name/ In this field you specify the Hostname or +the IP address (Single IP, Wildcard notation or bitmask +notation) that the user is connecting from. If you wanted +to REMOVE connects to IRC from ``orion.cair.du.edu'' then +you would want to enter ``orion.cair.du.edu''. If you want +to REMOVE ALL HOSTS access you can use ``*'' (Wild Card +notation) and no matter what host the USERNAME (specified in +Field 4) connects from s/he will be denied access. Removing +all hosts isn't very smart thing to do though, why would you +run an ircd if you allow nobody to connect to it anyways ? +<p> +If you specify an IP address, IP mask, or an IP bitmask, +it will match clients connecting from the matching +addresses, no matter if they resolve or not. +<p> +You can prefix an IP address, an IP mask, or IP bitmask by +``='' in which case only non resolving matching hosts will +be banned. +<tag/time interval(s)|comment/ Either leave this field empty +or put a comment, then the line active continuously for the +specified user/host machine. You may also specify intervals +during the line should be active, see examples below. +<tag/User/ The USERNAME of the user you want removed from +IRC. For example ``root''. +<tag/Auth/ If the user's ident server replies with the OTHER +type (as opposed to the UNIX type), the reply is not used to +set the user's username. (lowercase) k lines can be used in +these case to reject users based on their ident reply. +<p> +This field will be matched against the ident server reply. +It is important to note that OTHER replies are prefixed with +a ``-'' by the ircd, while UNIX replies are not. +<tag/Port/ The port on which the Kill line will be +effective. 0 means all ports. +<tag/Examples/ K:orion.cair.du.edu::jtrim:0: +<p> +If user ``jtrim'' connects to IRC from host +``orion.cair.du.edu'' then IMMEDIATELY REMOVE HIM from my +IRCD. +<p> +k:*.stealth.net::-43589:0: +<p> +If a user connects from any host that has the suffix +``stealth.net'' and if that host ident server returns +``-43589'' - then IMMEDIATELY REMOVE THEM from my IRCD. +<p> +K:*.cair.du.edu::root:0: +<p> +If user ``root'' connects to IRC from any host that has the +suffix ``cair.du.edu'' - then IMMEDIATELY REMOVE THEM from +my IRCD. +<p> +K:*::vijay:0: +<p> +This line reads ``I don't care WHAT HOST user ``vijay'' is +on, I will NEVER allow username ``vijay'' to login to my +IRCD.'' +<p> +K:*.oulu.fi:0800-1200,1400-1900:*:0: +<p> +This disallows all users from hosts with enddomain +``oulu.fi'' access to your server between 8 and 12am, 2 and +7pm. Users get kicked off if they're already signed on when +the line becomes active (they'll get a warning 5 minutes +before). +<p> +K:192.11.35.*::*:0: +<p> +This line disallows all hosts whose IP address matches +``192.11.35.*'' to login to the ircd. +<p> +K:=192.11.35.*::*:0: +<p> +This line disallows all hosts whose IP address matches +``192.11.35.*'' and which didn't resolve to login to the +ircd. +</descrip> + +<sect1>Server connections +<p> +How to connect to other servers, How other servers can connect to you +<p> +<bf>WARNING:</bf> +The hostnames used as examples are really only examples and +not meant to be used (simply because they don't work) in +real life. +<p> +Now you must decide WHICH hosts you want to connect to and +WHAT ORDER you want to connect to them in. For my example +let us assume I am on the machine "rieska.oulu.fi" and I +want to connect to irc daemons on 3 other machines: +<itemize> +<item>``garfield.mit.edu'' - Tertiary Connection +<item>``irc.nada.kth.se'' - Secondary Connection +<item>``nic.funet.fi'' - Primary Connection +</itemize> +<p> +And I prefer to connect to them in that order, meaning I +first want to try connecting to ``nic.funet.fi'', then to +``irc.nada.kth.edu'', and finally to ``garfield.mit.edu''. +So if ``nic.funet.fi'' is down or unreachable, the program +will try to connect to ``irc.nada.kth.se''. If +irc.nada.kth.se is down it will try to connect to garfield +and so forth. +<p> +PLEASE limit the number of hosts you will attempt to connect +to down to 3. This is because of two main reasons: +<enum> +<item> to save your server from causing extra load and +delays to users +<item> to save internet from extra network traffic (remember +the old rwho program with traffic problems when the number +of machines increased). +</enum> +<p> +<descrip> +<tag/Format/ <verb>C:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<TARGET PORT>:<Class></verb> +<p> +for example: +<p> +C:nic.funet.fi:passwd:nic.funet.fi:6667:1 +<p> + - or - +<p> +C:128.214.6.100:passwd:nic.funet.fi:6667:1 +<p> + - or - +<p> +C:root@nic.funet.fi:passwd:nic.funet.fi:6667:1 +<p> +Each field is separated with a ":" charcter: +<tag/C/ This field tells the IRC program which option is +being configured. "C" corresponds to a server Connect +option. +<tag/TARGET Host Addr/ Specifies the host name or IP address +of the machine to connect to. If ``user@'' prefixes the +actual hostname or IP address the server will require that +the remote username returned by the ident server be the same +as the one given before the ``@''. +<tag/Password/ The password of the other host. A password +must always be present for the line to be recognized. +<tag/TARGET Host NAME/ The full hostname of the target +machine. This is the name that the TARGET server will +identify itself with when you connect to it. If you were +connecting to nic.funet.fi you would receive +``nic.funet.fi'' and that is what you should place in this +field. +<tag/TARGET PORT/ The INTERNET Port that you want to connect +to on the TARGET machine. Most of the time this will be set +to ``6667''. If this field is left blank, then no +connections will be attempted to the TARGET host, and your +host will accept connections FROM the TARGET host instead. +The port field can contain 2 ports, separated by a . In this +case, the first port is used when auto-connecting, the +second port is used for the UDP pings to the targer server. +<tag/Class/ The class field should refer to an existing +class and determines the maximum number of simultaneous uses +of the C-line allowable through the max. links field in the +Y-line. +<tag/NEW!!!/ As of the 2.9.3 version of the server, server connections can be compressed with the zlib library. To define a compressed connection, you must have compiled the server with ZIP_LINKS defined (cf 2.h), and use a _lowercase_ C line. +</descrip> +<p> +Some examples: +<itemize> +<item>C:nic.funet.fi::nic.funet.fi:6667:1 +<p> +This reads: Connect to host ``nic.funet.fi'', with no +password and expect this server to identify itself to you as +``nic.funet.fi''. Your machine will connect to this host to +port 6667. +<item>C:18.72.0.252:Jeff:garfield.mit.edu:6667:1 +<p> +This reads: Connect to a host at address ``18.72.0.252'', +using a password of ``Jeff''. The TARGET server should +identify itself as ``garfield.mit.edu''. You will connect +to Internet Port 6667 on this host. +<item>C:irc.nada.kth.se::irc.nada.kth.se:1 +<p> +This reads: do not attempt to connect to +``irc.nada.kth.se'', if ``irc.nada.kth.se'' requests a +connection, allow it to connect. +</itemize> +<p> +Now back to our original problem, we wanted OUR server +CONNECT to 3 hosts, ``nic.funet.fi'', ``irc.nada.kth.se'' +and ``garfield.mit.edu'' in that order. So as we enter +these entries into the file they must be done in +<bf>reverse</bf> order of how we could want to connect to +them. +<p> +Here's how it would look if we connected ``nic.funet.fi'' first: +<p> +C:garfield.mit.edu::garfield.mit.edu:6667:1 +C:irc.nada.kth.se::irc.nada.kth.se:6667:1 +C:nic.funet.fi::nic.funet.fi:6667:1 +<p> +Ircd will attempt to connect to nic.funet.fi first, then to +irc.nada and finally to garfield. +<p> +<bf>Reciprocal entries:</bf> +Each ``C'' entry requires a corresponding ``N'' entry that +specifies connection priviliges to other hosts. The ``N'' +entry contains the password, if any, that you require other +hosts to have before they can connect to you. These entries +are of the same format as the ``C'' entries. +<p> +<descrip> +<tag/Format/ The format for the NOCONNECT entry in the ``ircd.conf'' is: +<verb>N:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<Domain Mask>:<Class></verb> +<p> +Let us assume that ``garfield.mit.edu'' connects to your +server and you want to place password authorization +authorization on garfield. The ``N'' entry would be: +<p> +N:garfield.mit.edu:golden:garfield.mit.edu:: +<p> +This line says: expect a connection from host +``garfield.mit.edu'', and expect a login password of +``golden'', and expect the host to identify itself as +``garfield.mit.edu''. +<p> +N:18.72.0.252::garfield.mit.edu:: +<p> +This line says: expect a Connection from host +``18.72.0.252'', and don't expect login password. The +connecting host should identify itself as +``garfield.mit.edu''. +<tag/N/ ``N'' corresponds to a server Noconnect option. +<tag/TARGET Host Addr/ Specifies the host name or IP address +of the machine to connect to. If ``user@'' prefixes the +actual hostname or IP address the server will require that +the remote username returned by the ident server be the same +as the one given before the ``@''. +<tag/Password/ The password of the other host. A password +must always be present for the line to be recognized. If +CRYPT_LINK_PASSWORD is defined in config.h, this password +must be crypted. +<tag/TARGET Host NAME/ The full hostname of the target +machine. This is the name that the TARGET server will +identify itself with when you connect to it. If you were +connecting to nic.funet.fi you would receive +``nic.funet.fi'' and that is what you should place in this +field. +<tag/Domain Mask/ Domain masking, see below. +<tag/Class/ The class field should refer to an existing class. +<tag/Wildcards domains/ To reduce the great amount of +servers in IRCnet wildcard DOMAINS were introduced in +2.6. To explain the usage of wildcard domains we take an +example of such: +<p> +*.de - a domain name matching all machines in Germany. +<p> +Wildcard domains are useful in that ALL SERVERS in Germany +(or any other domain area) can be shown as one to the rest +of the world. Imagine 100 servers in Germany, it would be +incredible waste of netwotk bandwidth to broadcast all of +them to all servers around the world. +<p> +So wildcard domains are a great help, but how to use them ? +<p> +They can be defined in the N-line for a given connection, in +place of ``Domain Mask'' you write a magic number called +wildcard count. +<p> +Wildcard count tells you HOW MANY PARTS of your server's +name should be replaced by a wildcard. For example, your +server's name is ``tolsun.oulu.fi'' and you want to +represent it as ``*.oulu.fi'' to ``nic.funet.fi''. In this +case the wildcard count is 1, because only one word (tolsun) +is replaced by a wildcard. +<p> +If the wildcard count would be 2, then the wildcard domain +would be ``*.fi''. Note that with wildcard name ``*.fi'' you +could NOT connect to ``nic.funet.fi'' because that would +result in a server name <bf>collision</bf> (*.fi matches +nic.funet.fi). +<p> +I advice you to not to use wildcard servers before you know +for sure how they are used, they are mostly beneficial for +backbones of countries and other large areas with common +domain. +</descrip> +<p> + +<sect1>Deny auto-connections +<p> +<descrip> +<tag/Introduction/ D lines were implemented to give server +administrators more control on how auto connections are +done. This will most likely only be useful for big networks +which have complex configurations. +<tag/Format/<verb>D:<Denied Server Mask>:Denied Class:<Server Name>:Server Class: +</verb> +<tag/Denied Server Mask/ This field is matched against all +servers currently present on the network. +<tag/Denied Class/ If this field contains a class number, +it will match if any server in that class is currently +present on the network. Note that this can be true for any +server, even the ones not directly connected. +<tag/Server Mask/ This field is matched against the server +name that the server wants to auto connect to. +<tag/Server Class/ This field is used to match against the +class to which belong the servers for which an autoconnect +is set. +<tag/Examples/D:*.edu::*.fi:: +<p> +Don't auto-connect to any ``*.fi'' server if any server +present on the network matches ``*.edu''. +<p> +D::2:eff.org:3: +<p> +Do now auto-connect to ``eff.org'', or any server in class +``3'' if a server defined to be in class ``2'' is currently +present on the network. +</descrip> + +<sect1>Hub connections +<p> +<descrip> +<tag/Introduction/ In direct contrast to L-lines, the server +also implements H-lines to determine which servers may act +as a hub and what they may ``hub for''. If a server is only +going to supply its own name (ie act as a solitary leaf) +then no H-line is required for, else a H-line must be added. +<tag/Format/<verb>H:<Server Mask>:*:<Server Name>:: +</verb> +<tag/Server Mask/ All servers that are allowed via this +H-line must match the mask given in this field. +<tag/Server Name/ This field is used to match exactly +against a server name, wildcards being treated as literal +characters. +<tag/Examples/H:*.edu::*.bu.edu:: +<p> +Allows a server named ``*.bu.edu'' to introduce only servers +that match the ``*.edu'' name mask. +<p> +H:*::eff.org:: +<p> +Allows ``eff.org'' to introduce (and act as a hub for) any +server. +<tag/Note/ It is possible to have and use multiple H-lines +(or L-lines) for the one server. eg: +<p> +<verb>H:*.edu:*:*.bu.edu:: +H:*.au:*:*.bu.edu:: +</verb> +<p> +is allowed as is +<p> +<verb>L:*.edu:*:*.au:: +L:*.com:*:*.au:: +</verb> +</descrip> + +<sect1>Leaf connections +<p> +<descrip> +<tag/Introduction/ To stop servers which should only act as +leaves from hubs becoming hubs accidently, the L line was +introduced so that hubs can be aware of which servers should +and shouldnt be treated as leaves. A leaf server is supposed +to remain a node for the entirity of its life whilst +connected to the IRC server network. It is quite easy, +however for a leaf server to be incorrectly setup and create +problems by becoming a node of 2 or more servers, ending its +life as a leaf. The L line enables the administrator of an +IRC ``Hub server'' to ``stop'' a server which is meant to +act as a leaf trying to make itself a hub. If, for example, +the leaf server connects to another server which doesnt have +an L-line for it, the one which does will drop the +connection, once again making the server a leaf. +<tag/Format/<verb>L:<Server Mask>:*:<Server Name>:<Max Depth>:</verb> +<tag/Server Mask/ Mask of which servers the leaf-like +attributes are used on when the server receives SERVER +messages. The wildcards * and ? may be used within this +field for matching purposes. If this field is empty, it +acts the same as if it were a single * (ie matches +everything). +<tag/Server Name/ The name of the server connected to you +that for which you want to enforce leaf-like attributes +upon. +<tag/Max Depth/ Maximum depth allowed on that leaf and if +not specified, a value of 1 is assumed. The depth is +checked each time a SERVER message is received by the +server, the hops to the server being the field checked +against this max depth and if greater, the connection to the +server that made its leaf too deep has its connection +dropped. For the L-line to come into effect, both fields, 2 +and 4, must match up with the new server being introduced +and the server which is responsible for introducing this new +server. +</descrip> + +<sect1>Version limitations +<p> +<descrip> +<tag/Introduction/ V-lines are used to restrict server +connecting to you based on their version and on compile time +options. +<tag/Format/<verb>V:<Version Mask>:<Flags>:<Server Mask>::</verb> +<tag/Version Mask/ The matching version number strings will be rejected. +<tag/Flags/ If any flag specified in this field is found in +the peer's flags string, it will be rejected. +<tag/Server Mask/ This field is used to match server names. +The V line will be used for servers matching the mask given +in this field. +<tag/Server Type/ Both the <bf>Version Mask</bf> and the +<bf>Flags</bf> should be prefixed with the server type +identification. This implementation uses the id +``<bf>IRC</bf>'' (starting with version 2.10). +<tag/Examples/V:IRC/021001*::*:: +<p> +Disallows any ``IRC'' server which version is 2.10.1* to connect. +<p> +V:IRC/021001*:IRC/D:*:: +<p> +Disallows any ``IRC'' server which version is 2.10.1* or +which has been compiled with DEBUGMODE defined to connect. +<p> +V:*/0209*:::: +<p> +Disallows any server using the 2.9 protocol to connect. +<tag/Note/ It is possible to have and use multiple V-lines +for the one server mask. +<p> +V:IRC/021001*::*:: +<p> +V:IRC/021002*::*:: +<p> +is allowed. +<tag/Protocol Version/ Only the 4 first digit of the +<bf>Version Number</bf> are standard: they define the +protocol version. The remaining of the string is +implementation dependant; matches on this part should be +used with particular identification. +<tag/Flags/ are not standard. Therefore, this field +<bf>should always</bf> contain a specific identification. +</descrip> + +<sect1>Excluded machines +<p> +Disallowing SERVERS in your irc net. +<descrip> +<tag/Introduction/ In some cases people run into +difficulties in net administration. For one reason or +another you do not want a certain server to be in your net +(for example because of the security holes it opens for +every server if it's not secured carefully). In that case +you should use Q-lines in your server. When you specify a +server name in Q-line, everytime some server link tries to +introduce you a server (remember, all server names are +broadcast around the net), that name is checked if it +matches the Q-lines in your server. If it matches, then +<bf>your server</bf> disconnects the link. Note that just +placing Q-lines to your server probably results in <bf>your +server</bf> being left alone, unless other servers have +agreed to have the same Q-line in their ircd configuration +files as well. +<tag/Example/Q::of the security holes:foo.bar.baz:: +<p> +This command excludes a server named ``foo.bar.baz'', the +reason is given to be security holes (you should give a +reason, it is polite). The first field is unused, so leave +it empty. +</descrip> + +<sect1>Service connections +<p> +<descrip> +<tag/Introduction/ The Service is a special kind of IRC +client. It does not have the full abilities of a normal user +but can behave in a more active manner than a normal +client. +<p> +Services are not intended for interactive usage, and are +better suited for automated clients. +<tag/Format/<verb>S:<TARGET Host Mask>:<Password>:<Service Name>:<Service Type>:<Class></verb> +<tag/TARGET Host Mask/ The host mask should be set to match +the host(s) from which the service will be connecting +from. This may be either an IP# or full name (prefered). +<tag/Password/ This is the password which must be passed in +the SERVICE command. +<tag/Service Name/ The name used by the service. Services +don't have nicknames, but a static name defined by the S +line. +<tag/Service Type/ The type of service. It defines the +priviledges given to the service. Be very careful in the +types you allow. The types can be found in +include/service.h +<tag/Class/ The class field should refer to an existing class. +<tag/Notes/ A service is not a very useful sort of client, +it cannot join channels or issue certain commands although +most are available to it. Services are rejected upon sending +an unknown or unallowed command. Services however, are not +affected by flood control and can be granted special +privileges. It is therefore <bf>wise to oversee the use of +S-lines with much care.</bf> +</descrip> + +<sect1>Bounce server +<p> +<descrip> +<tag/Introduction/ This provides you a way to bounce clients +to another server. This information is provided to clients +which are denied connection, either because their connection +class is full, or the server is full, or they are not +authorized to connect. +<tag/Format/<verb>B:<Class|Host Mask>::<Server Name>:<Port>:</verb> +<tag/B/ This specifies a Bounce record. +<tag/Class|Host Mask/ This field specifies to which client +this configuration line applies to. It can be either a +connection class number, a host mask to be matched against +the client's hostname, or an IP address/mask/bitmask to be +matched against the client's IP address. +<p> +When the server is completely full, it rejects clients with +the ``All connections in use'' message. In this case, the +server doesn't process the connections at all, and has no +knowledge of the client's host name, or class number. For +these cases, this field must be empty. +<tag/Server Name/ This specifies the IRC server hostname +that the client should use. +<tag/Port/ This specifies the IRC server port that the +client should connect to. +<tag/Example/B:2::irc.stealth.net:6660: +<p> +Rejected clients in class 2 are advised to use +``irc.stealth.net'' on port 6660. +<p> +B:*.fi::irc.funet.fi:6667: +<p> +Finnish client should use irc.funet.fi when they cannot be +taken anymore. +<p> +B:::irc2.stealth.net:6667: +<p> +When the server is completely full, clients should use the +secondary server. +</descrip> + +<sect1>Default local server (for local clients) <bf>*OBSOLETED*</bf> +<p> +<descrip> +<tag/Introduction/ This defines the default connection for +the irc client. If you are running an ircd server on the +same machine, you will want to define this command to +connect to your own host. If your site is not running a +server then this command should contain the TARGET host's +connection information and password (if any). +<tag/Format/<verb>U:<TARGET Host addr>:<Password>:<TARGET Host NAME>:<Internet Port></verb> +<tag/Examples/ +U:tolsun.oulu.fi::tolsun.oulu.fi:6667<p> +U:128.214.5.6::tolsun.oulu.fi:6667<p> +U:tolsun.oulu.fi::tolsun.oulu.fi +<p> +If the port number is omitted, irc will default to using 6667. +</descrip> + +<sect>Related resources +<p> +<descrip> +<tag/Mailing list/ A list is dedicated to the people using +ircd. If you have trouble running ircd, or wish to discuss +the future, you can subscribe by sending an email to +<htmlurl url="mailto:majordomo@irc.org" +name="majordomo@irc.org">, with ``<bf>subscribe +ircd-users</bf>'' in the body. +<p> +If you just have a question and don't want to subscribe to +the list, mail to <htmlurl url="mailto:ircd-users@irc.org" +name="ircd-users@irc.org">. Be sure to indicate which +version you are using. +<tag/Development/ Technical discussions and development are +carried on ircd-dev@irc.org. People interested in very +early testing, and/or working on the source code are +welcome. This is done by sending an email to <htmlurl +url="mailto:majordomo@irc.org" +name="majordomo@irc.org">, with ``<bf>subscribe +ircd-dev</bf>'' in the body. +<tag/FAQ/ It can be found on the WWW, at <url +url="http://www.stealth.net/~kalt/irc/faq.html">. +<tag/WWW 2.9/ Vesa Ruokonen has also put serveral pages +related to the 2.9 servers on the WWW: <url +url="http://www.irc.org/~irc/server/">. +</descrip> + +<sect>Reporting a bug +<p> +If you encounter a bug in the software, here is how and +where to report it. + +<sect1>How to report a bug +<p> +To save everyone time, make sure that your e-mail contains +all the information related to your problem. In particular, +we need to know: +<descrip> +<tag/Package version/ +The IRC software version you are using: please include the +output obtained by running ``irc -v'' for the client, and/or +``ircd -v'' for the server. +<p> +Also, let us know if you have applied any patch to the +package or if it is the vanilla version. +<tag/OS/ +Please, indicate which OS version you are running. +<tag/Configuration/ +If it is related to a configuration problem with the server, +include the relevant parts of the configuration file. +<tag/Backtrace/ +If the bug results in a crash, please include the +backtrace. (This can be done, for example, by running +``gdb'' on the core file, and typing ``where''). +<tag/Fix/ +If you have a fix, don't forget to include it. +</descrip> + +<sect1>Where to send a bug report +<p> +Reports should be sent to <htmlurl url="mailto:ircd-bugs@irc.org" +name="ircd-bugs@irc.org">. Your report will be reviewed +and forwarded to the appropriate mailing list. + +</article> diff --git a/doc/INSTALL.txt b/doc/INSTALL.txt new file mode 100644 index 0000000..b8dbc63 --- /dev/null +++ b/doc/INSTALL.txt @@ -0,0 +1,1716 @@ + Installing IRC - The Internet Relay Chat Program + SGML version by Christophe Kalt + $Id: INSTALL.txt,v 1.38 1999/08/13 17:22:12 kalt Exp $ + + This document describes how to install, and configure IRC 2.10.3. + + 11.. IInnssttaalllliinngg IIRRCC.. + + 11..11.. TThhee ccoonnffiigguurree ssccrriipptt + + This package uses a GNU configure script for its configuration. You + simply need to untar the distribution and run the ``configure'' + script. This will run configure which will probe your system for any + peculiarities it has and setup the Makefile and a file of default + #define's ($arch/setup.h). + + There are a few options to ``configure'' to help it out, or change the + default behaviour: + + ----pprreeffiixx==DDIIRR + changes the default directory into which ircd will install using + ``make install''. This defaults to /usr/local + + ----ssbbiinnddiirr==DDIIRR + changes the default directory where the system admin executable + files will go. It is important to set this properly. (default is + prefix/sbin) + + ----llooggddiirr==DDIIRR + changes the default directory where the irc log files will go. + (default is prefix/var/log/ircd) + + ----ssyyssccoonnffddiirr==DDIIRR + changes the default directory where the irc server configuration + files will go. (default is prefix/etc) + + ----llooccaallssttaatteeddiirr==DDIIRR + changes the default directory where the irc server state files + will go. (default is prefix/var/run) + + ----rreessccoonnff==FFIILLEE + defines the file to be used by ircd to initialize its resolver. + (default is /etc/resolv.conf) + + ----zzlliibb--iinncclluuddee==DDIIRR + specifies in which directory the include file from the zlib is + located. + + ----zzlliibb--lliibbrraarryy==DDIIRR + specifies in which directory the zlib library is located. + + ----zzlliibb--pprreeffiixx==DDIIRR + specifies the prefix for zlib location. It overrides the 2 + previous options. (The include directory is supposed to be in + prefix/include, and the library in prefix/lib). + + ----wwiitthh--zzlliibb + is the default. ``configure'' looks on your system to find the + zlib. If found, ircd will be linked using it. This does NOT + mean you can use server link compression, for this you also need + to define ZIP_LINKS (see section below). + + ----wwiitthhoouutt--zzlliibb + tells ``configure'' not to look for the zlib. Defining this + will keep you from using server link compression. + + ----eennaabbllee--iipp66 + Enable IPv6 support (See notes below) + + ----eennaabbllee--ddssmm + Enable Dynamically Shared Modules support for iauth + + + 11..22.. NNootteess ffoorr CCyyggwwiinn3322 uusseerrss + + The daemon of 2.10.3 release compiles properly on W32 systems which + have the GNU-Win32 environment ( <http://www.cygnus.com/misc/gnu- + win32/>) setup. At the time of the release, tests were made using the + version b20.1 of the Cygwin32 library. + + When compiling on such system, you want to make sure that you have + carefully followed the Cygwin32 installation notes. In particular, + you will need to make sure that the following files exist: + //bbiinn//ccpp..eexxee, //bbiinn//mmvv..eexxee, //bbiinn//rrmm..eexxee and //bbiinn//sshh..eexxee. + + Also, the IRC server needs a rreessoollvv..ccoonnff file in order to initialize + the resolver. This file can be anywhere (see configure options), and + is typically in //eettcc on UNIX systems. + + Finally, iauth is automatically disabled. Even though the iauth + program compiles properly, extra work is required to have a working + communication channel between the IRC server and the iauth program. + + + 11..33.. NNootteess ccoonncceerrnniinngg IIPPvv66 ssuuppppoorrtt + + The only part of the software that doesn't use IPv6 is the server + internal resolver. It relies on the name servers defined in + ``/etc/resolv.conf'' to be IPv4 addresses. + + This version was tested on the following IPv6 systems: BSD/OS+KAME, + Digital Unix, FreeBSD+KAME, Linux, NetBSD+INRIA. + + Because IPv6 numeric addresses contain ``:'' characters, tthhee sseeppaarraattoorr + ffoorr tthhee sseerrvveerr ccoonnffiigguurraattiioonn ffiillee wwaass cchhaannggeedd ttoo ````%%''''. + + + 22.. TThhee ccoonnffiigg..hh ffiillee + + The second step consists of defining options before the compilation. + This is done by editing the ``config.h'' file and changing the various + #DEFINE's. + + + 22..11.. DDeeffiinnee wwhhaatt ttyyppee ooff UUNNIIXX yyoouurr mmaacchhiinnee uusseess.. + + Pick the machine type which best describes your machine and change the + #undef to #define (if needed).Some flavours of Unix require no #define + and in such cases all others should be #undef'd. + + + 22..22.. DDEEBBUUGGMMOODDEE + + Define DEBUGMODE if you want to see the ircd debugging information as + the daemon is running. Normally this function will be undefined as + ircd produces a considerable amount of output. DEBUGMODE must be + defined for either of -t or -x command line options to work. Defining + this induces a large overhead for the server as it does a large amount + of self diagnostics whilst running. + + TThhiiss sshhoouulldd oonnllyy bbee ddeeffiinneedd ffoorr tteesstt ppuurrppoosseess,, aanndd nneevveerr uusseedd oonn aa + pprroodduuccttiioonn sseerrvveerr.. + 22..33.. CCPPAATTHH,, MMPPAATTHH,, LLPPAATTHH,, PPPPAATTHH,, TTPPAATTHH,, QQPPAATTHH,, OOPPAATTHH + + Define CPATH to be the directory path to the ``ircd.conf'' file. This + path is usually /usr/local/lib/ircd/ircd.conf. The format of this file + will be discussed later. + + The LPATH #define should be set to ``/dev/null'' unless you plan to + debug the ircd program. Note that the logfile grows very quickly. + + Define MPATH to be the path to the ``motd'' (message of the day) file + for the server. Keep in mind this is automatically displayed whenever + anyone signs on to your server. + + The PPATH is optional, but if defined, should point to a file which + either doesn't exist (but is creatable) or a previously used PPATH + file. It is used for storing the server's PID so a ps(1) isn't + necessary. + + Define QPATH to be the directory path to the ``iauth.conf'' file. This + path is usually /usr/local/lib/ircd/iauth.conf. The format of this + file is described by a manual page. + + The OPATH #define should be set to ``/dev/null'' unless you plan to + debug the iauth program. Note that the logfile grows very quickly. + + + 22..44.. CCAACCHHEEDD__MMOOTTDD + + The server sends the ``motd'' to every client connecting. Every time, + it reads it from the disk. This is quite intensive and can be + undesirable for busy servers. + + Defining CACHED_MOTD will make the server store the ``motd'' in + memory, and only read it again from the disk when rehashing if the + file has changed. + + + 22..55.. CCHHRROOOOTTDDIIRR + + To use the CHROOTDIR feature, make sure it is #define'd and that the + server is being run as root. The server will chroot to the directory + name provded by ``IRCDDIR'' (in Makefile). + + + 22..66.. EENNAABBLLEE__SSUUMMMMOONN,, EENNAABBLLEE__UUSSEERRSS + + For security conscious server admins, they may wish to leave + ENABLE_USERS undefined, disabling the USERS command which can be used + to glean information the same as finger can. ENABLE_SUMMON toggles + whether the server will attempt to summon local users to irc by + writing a message similar to that from talk(1) to a user's tty. + + + 22..77.. SSHHOOWW__IINNVVIISSIIBBLLEE__LLUUSSEERRSS,, NNOO__DDEEFFAAUULLTT__IINNVVIISSIIBBLLEE + + On large IRC networks, the number of invisible users is likely to be + large and reporting that number cause no pain. To aid and effect + this, SHOW_INVISIBLE_LUSERS is provided to cause the LUSERS command to + report the number of invisible users to all people and not just + operators. The NO_DEFAULT_INVISIBLE define is used to toggle whether + clients are automatically made invisible when they register. + + + + + + 22..88.. OOPPEERR__KKIILLLL,, OOPPEERR__RREEHHAASSHH,, OOPPEERR__RREESSTTAARRTT,, LLOOCCAALL__KKIILLLL__OONNLLYY + + The three operator only commands, KILL, REHASH and RESTART, may all be + disabled to ensure that an operator who does not have the correct + privilidges does not have the power to cause untoward things to occur. + To further curb the actions of guest operators, LOCAL_KILL_ONLY can be + defined to only allow locally connected clients to be KILLed. + + + 22..99.. ZZIIPP__LLIINNKKSS,, ZZIIPP__LLEEVVEELL + + As of the 2.9.3 version of the server, server-server connections may + be compressed using the zlib. In order to compile the server with + this feature, you MUST have the zlib package (version 1.0 or higher) + already compiled and define ZIP_LINKS in the config.h file. + Compression use for server-server connections is separately configured + in the ircd.conf file for each server-server link. ZIP_LEVEL allows + you to control the compression level that will be used. Values above + 5 will noticeably increase the CPU used by the server. + + The zlib package may be found at + <http://www.cdrom.com/pub/infozip/zlib/>. The data format used by the + zlib library is described by RFCs (Request for Comments) 1950 to 1952 + in the files <ftp://ds.internic.net/rfc/rfc1950.txt> (zlib format), + rfc1951.txt (deflate format) and rfc1952.txt (gzip format). These + documents are also available in other formats from + <ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html> + + + 22..1100.. SSLLOOWW__AACCCCEEPPTT + + This option is defined by default and is needed on some OSes. It + creates an artificial delay in processing incoming connections. On a + given port, no more than 1 connection per 2 seconds will be processed. + + Undefining this will let the server process connections as fast as it + can which can cause problems on some OSes (such as SunOS) and be + abused (fast massive join of clonebots..), for these reasons, if you + decide to undefine SLOW_ACCEPT you MUST define CLONE_CHECK. + + + 22..1111.. CCLLOONNEE__CCHHEECCKK + + This option acts as a wrapper, by checking incoming connections early + before starting ident query. By default, the server will not accept + more than 2 connections from the same host within 10 seconds. + + + 22..1122.. OOtthheerr ##ddeeffiinnee''ss + + The rest of the user changable #define's should be pretty much self + explanatory in the config.h file. It is *NOT* recommended that any of + the file undef the line with "STOP STOP" in it be changed. + + + 33.. EEddiittiinngg tthhee MMaakkeeffiillee,, aanndd ccoommppiilliinngg + + This package now uses GNU autoconf to probe your system and generate + the correct Makefile. However you need to edit it to specify specific + information, such as ``prefix'', ``irc_mode'', ``ircd_mode'' and + ``ircd_dir''. + + Now to build the package, type ``make all''. If everything goes will, + you can then install it by typing ``make install''. + + + If you have trouble compiling ircd, copy Makefile.in to Makefile and + edit Makefile as appropriate. + + + 44.. TThhee iirrccdd..ccoonnff ffiillee + + After installing the ircd and irc programs, edit the ircd.conf file as + per the instructions in this section and install it in the location + you specified in the config.h file. There is a sample conf file + called example.conf in the doc/ directory. + + Appendix A (See INSTALL.appendix) describes the differences between IP + addresses and host names. If you are unfamiliar with this, you should + probably scan through it before proceeding. + + The ircd.conf file contains various records that specify configuration + options. The record types are as follows: + + 1. Machine information (M) + + 2. Administrative info (A) + + 3. Port connections (P) + + 4. Connection Classes (Y) + + 5. Client connections (I,i) + + 6. Operator privileges (O) + + 7. Restrict lines (R) + + 8. Excluded accounts (K,k) + + 9. Server connections (C,c,N) + + 10. + Deny auto-connections (D) + + 11. + Hub connections (H) + + 12. + Leaf connections (L) + + 13. + Version limitations (V) + + 14. + Excluded machines (Q) + + 15. + Service connections (S) + + 16. + Bounce server (B) + + 17. + Default local server (U) + + Except for types ``M'' and ``A'', you are allowed to have multiple + records of the same type. In some cases, you can have concurrent + records. IItt iiss iimmppoorrttaanntt ttoo nnoottee tthhaatt tthhee llaasstt mmaattcchhiinngg rreeccoorrdd wwiillll + bbee uusseedd. This is especially useful when setting up I records (client + connections). + + 44..11.. MMaacchhiinnee iinnffoorrmmaattiioonn + + + IInnttrroodduuccttiioonn + IRC needs to know a few things about your UNIX site, and the + ``M'' command specifies this information for IRC. The fomat of + this command is: + + FFoorrmmaatt + + M:<Server NAME>:<YOUR Internet IP#>:<Geographic Location>:<Port> + + + + MM ``M'' specifies a Machine description line + + SSeerrvveerr NNAAMMEE + The name of YOUR server adding any Internet DOMAINNAME that + might also be present. If this hostname can be resolved, the IP# + found will be used to for outgoing connections. Otherwise the + default interface address of the host is used. The server name + may not be FQDN of another host. (This means all outgoing + connections will be done from the same IP#, even if your host + has several IP#). + + YYOOUURR IInntteerrnneett IIPP## + If the machine on which you run the server has several IP + addresses, you can define which IP# to use for outgoing + connections. This overrides overrides the ``Server NAME''. + + See Also the ``Port Connections'' section. + + GGeeooggrraapphhiicc LLooccaattiioonn + Geographic Location is used to say WHERE YOUR SERVER is, and + gives people in other parts of the world a good idea of where + you are! If your server is in the USA, it is usually best to + say: <CITY> <STATE>, USA. Like for Denver I say: ``Denver + Colorado, USA''. Finnish sites (like tolsun.oulu.fi generally + say something like ``Oulu, Finland''. + + PPoorrtt + Defines the port on which your server will listen for UDP pings + from other servers. This should be the port were other servers + are set to autoconnect. (Also see the port field description in + connect lines). + + EExxaammppllee:: + M:tolsun.oulu.fi::Oulu, Finland:6667: + + This line reads: My Host's name is ``tolsun.oulu.fi'' and my + site is located in ``Oulu, Finland''. + + M:orion.cair.du.edu::Denver Colorado, USA:6667: + + This line reads: My Hosts name is ``orion.cair.du.edu'' and my + site is located in ``Denver Colorado, USA''. + + + + 44..22.. AAddmmiinniissttrraattiivvee iinnffoo + + + IInnttrroodduuccttiioonn + The ``A'' line is used for administrative information about a + site. The e-mail address of the person running the server should + be included here in case problems arise. + FFoorrmmaatt + + A:<Your Name/Location>:<Your Electronic Mailing Addr>:<other>:: + + + + AA This specifies an Admin record. + + YYoouurr NNaammee && LLooccaattiioonn + Use this field to say tell your FULL NAME and where in the world + your machine is. Be sure to add your City, State/Province and + Country. + + YYoouurr EElleeccttrroonniixx MMaaiilliinngg AAddddrr + Use this field to specify your Electronic Mailing Address + preferably your Internet Mailing Address. If you have a UUCP or + ARAPnet address - please add that as well. Be sure to add any + extra DOMAIN information that is needed, for example ``mail + jtrim@orion'' probably won't work as a mail address to me if you + happen to be in Alaska. But ``mail jtrim@orion.cair.du.edu'' + would work because you know that ``orion'' is part of the DOMAIN + ``cair.du.edu''. So be sure to add your DOMAINNAMES to your + mailing addresses. + + OOtthheerr + This is really an OTHER field - you can add what you want here. + + EExxaammppllee + (the line is just one line in the confuration file, here it is + cut into two lines to make it clearer to read): + + A:Jeff Trim - Denver Colorado, USA:INET jtrim@orion.cair.du.edu + UUCP {hao,isis}!udenva!jtrim:Terve! Heippa! Have you said hello + in Finnish today?;):: + + Would look like this when printed out with the /admin command: + + Jeff Trim - Denver Colorado, USA INET jtrim@orion.cair.du.edu + UUCP {hao,isis}!udenva!jtrim Terve! Hei! Heippa! Have you said + hello in Finnish today? ;) + + + Note that the A record cannot be split across multiple lines; it + will typically be longer than 80 characters and will therefore + wrap around the screen. + + + 44..33.. PPoorrtt ccoonnnneeccttiioonnss + + + IInnttrroodduuccttiioonn + The port line adds flexibility to the server's ability to accept + connections. By use of this line in the ircd.conf file, it is + easy to setup both Unix Domain ports for the server to accept + connections on as well as extra internet ports. + + FFoorrmmaatt + + P:<Internet IP#>:<*>:<Internet IP Mask>:<Port>: + P:<Directory>:<*>:<*>:<Port>: + + + + + +o Internet Ports + + IInntteerrnneett IIPP## + If the host on which the server runs has several IP addresses, + you can define for which IP address connections will be + accepted. If no is defined here, server will bind to all + interfaces (INADDR_ANY). See also MACHINE CONFIGURATION section + to properly configure outgoing connections. + + P:192.168.1.194:::6664: + + IInntteerrnneett IIPP## MMaasskk + This defines where connections may come from and be accepted. + The IP mask uses either *'s or 0's as wildcards. The following + two lines are the same: + + + P:::128.2.*:6664: + P:::128.2.0.0:6664: + + + + The incoming isn't matched against the mask, rather the ip# string + is decoded and compared segment by segment. Thus + + P:::128.2*.1.2:6664: + + will not match 128.20.1.2. + + PPoorrtt + The port number field tells the server which port number it + should listen on for incoming connections. + + +o Unix Socket Ports. + + DDiirreeccttoorryy + The path set in this field should be the directory name in which + to create the unix socket for later listening to. The server + will attempt to create the directory before creating the unix + socket. + + PPoorrtt + The port field when used in combination with a pathname in a P- + line is the filename created in the directory set in the first + field. + + EExxaammppllee + P:/tmp/.ircd:::6667: + + Creates a unix socket in the /tmp/.ircd directory called + ``6667''. The unix socket (file) must be a numerical. + + + NNoottee + You need at least one P line. + + + 44..44.. CCoonnnneeccttiioonn CCllaasssseess + + + IInnttrroodduuccttiioonn + To enable more efficient use of MAXIMUM_LINKS, connection + classes were implemented. All clients belong to a connection + class. + + Each line for a server should have the same number as the sixth + field. If it is absent, the server deaults it to 0, using the + defaults from the config.h file. + To define a connection class, you need to include a Y: line in + the ircd.conf file. This enables you to define the ping + frequency, connection frequency (for servers) and maximum number + of links that class should have. + + Currently, the Y: line MMUUSSTT appear in the ircd.conf file BBEEFFOORREE + it is used in any other way. + + FFoorrmmaatt + + Y:<Class>:<Ping Frequency>:<Connect freq>:<Max Links>:<SendQ>:<Local Limit>:<Global Limit> + + + + YY This specifies a Class record. + + CCllaassss + This is the class number which gains the following attributes + and should match that which is on the end of the C/c/N/I/O/S + line. + + PPiinngg FFrreeqquueennccyy + This field defines how long the server will let the connection + remain ``silent'' before sending a PING message to make sure it + is still alive. Unless you are sure of what you are doing, use + the default value which is in your config.h file. + + CCoonnnneecctt FFrreeqquueennccyy + By changing this number, you change how often your server checks + to see if it can connect to this server. If you want to check + very occasionally, use a large value, but if it is an important + connection, you might want a smaller value so that you connect + to it as soon as possible. + + MMaaxx LLiinnkkss + This field defines the maximum number of links this class will + allow from automatic connections (C lines). Using /CONNECT + overrides this feature. Also defines the maximum number of + users in this class for I/O lines per I/O line. + + SSeennddQQ + This field defines the ``SendQ'' value for this class. If this + field is not present, the default (from config.h) is assigned. + + LLooccaall lliimmiitt + This field is used to limit the number of local concurrent + connections. The format is <x>.<y> + + +o x: defines the maximum number of clients from the same host (IP) + will be allowed. + + +o y: defines the maximum number of clients from the same user@host + (IP) will be allowed. Read note below. + + Only x or y may be set, any unset value defaults to zero. + + GGlloobbaall lliimmiitt + This field has the same use as the ``Local limit'' field. But, + the connection counts are done for all clients present on the + net instead of only counting local clients. + + NNoottee + leaving any of the fields (except SendQ) out means their value + is 0 (ZERO)!! The SendQ field default value is dynamically + determined. + + NNoottee + If you plan to use the local user@host limit, please read the + following very carefully. The ``user'' value is the ident reply + for the connection. If no reply was given then it defaults to + ``unknown'' and thus the effective limit will be per host, not + per user@host. Also, some ident servers return encrypted data + which changes for every connection making the limit void. + + NNoottee + Only the local limitation is accurate. + + NNoottee + If you define a gobal limit, you should also define a local + limit (same or lower) as it won't take more CPU and will make + the global limit more accurate. + + NNoottee + The local and global limits only affect users (I lines), not + servers nor services. + + EExxaammppllee + Y:23:120:300:5:100000:0:0: (server class) + + This defines class 23 to allow 5 auto-connections, which are + checked every 300 seconds. The connection is allowed to remain + silent for 120 seconds before a PING is sent. NOTE: fields 3 & + 4 are in seconds. The SendQ is set to 100000 bytes. + + Another feature of connection class is the ability to do + automatic routing by using the class as a ``priority''. If you + are connected to a server which has a class lower than one of + the servers that is ``behind'' it, the server will disconnect + the lower class one and schedule a ``new'' connection for the + higher class server. + + Y:1:60:0:50:20000:2:5: (client class) + + In case of a client class, the fields are interpreted a bit + differently. This class (number 1) can be used by up to 50 + users. The connections are allowed to remain silent for 60 + seconds before a PING is set. The SendQ is set to 20000 bytes. + A new connection in this class will only be allowed if there + aren't more than 2 other local connections from the same IP + address, or more than 5 other connections on the net from the + same hostname. + + Y:2:60:0:50:20000:2.1:5: (client class) + + In case of a client class, the fields are interpreted a bit + differently. This class (number 1) can be used by up to 50 + users. The connections are allowed to remain silent for 60 + seconds before a PING is set. The SendQ is set to 20000 bytes. + A new connection in this class will only be allowed if there + aren't more than 2 other local connections from the same IP + address, 1 other local connection from the same user from the + same IP address, or more than 5 other connections on the net + from the same hostname. + + + 44..55.. CClliieenntt ccoonnnneeccttiioonnss + + How to let clients connect to your IRCD. + + IInnttrroodduuccttiioonn + A client is a program that connects to the ircd daemon (ircd). + There are clients written in C, GNU Emacs Lisp and many other + languages. The ``irc'' program is the C client. Each person + that talks via IRC is running their own client. + + The ircd.conf files contains entries that specify which clients + are allowed to connect to your irc daemon. Obviously you want + to allow your own machine's clients to connect. You may want to + allow clients from other sites to connect. These remote clients + will use your server as a connection point. All messages sent + by these clients will pass through your machine. + + FFoorrmmaatt + + I:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class> + i:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class> + + + + TTAARRGGEETT HHoosstt AAddddrr + Specifies the IP address(es) of the machine(s) that are allowed + to connect. If ``user@'' prefixes the actual IP address the + server will require that the remote username returned by the + ident server be the same as the one given before the ``@''. + Wildcards are permitted unless using a bitmask (e.g. + 1.2.3.0/24). + + PPaasssswwoorrdd + The password that must be given by the client to be allowed on + the server. + + TTAARRGGEETT HHoosstt NNAAMMEE + Specifies the host name(s) of the machines allowed to connect to + the server. If ``user@'' prefixes the actual IP address the + server will require that the remote username returned by the + ident server be the same as the one given before the ``@''. + Wildcards are permitted. + + This field can be empty, it then has a special meaning. See + Below. + + PPoorrtt + Specifies the port number for which this configuration line is + valid. An empty field, or ``0'' matches all ports. + + CCllaassss + This field should refer to an existing class. Connections + classes are usefull to limit the number of users allowed on the + server. + + NNoottee + The server first checks if the client hostname (or any aliases) + matches the TTAARRGGEETT HHoosstt NNAAMMEE field. If a match is found, the + client is accepted. If not, the server checks if the IP address + of the client matches the TTAARRGGEETT HHoosstt AAddddrr field. The matching + field is used to set the name of the client: for example, if the + client matches the TTAARRGGEETT HHoosstt AAddddrr field, it will show on IRC + with a numerical address (even if this address is resolvable). + If the TTAARRGGEETT HHoosstt NNAAMMEE field is empty, then the host name is + always used (when available). + + EExxaammpplleess + For example, if you were installing IRC on tolsun.oulu.fi and + you wanted to allow examples sake let us assume you were making + this file for tolsun and you wanted to let your own clients to + connect to your server, you would add this entry to the file: + + I:x::tolsun.oulu.fi::1 + If you wanted to let remote clients connect, you could add the + following lines: + + I:x::*.du.edu::1 + + Allow any clients from machines whose names end in ``.du.edu'' + to connect with no password. + + I:128.214.6.100::nic.funet.fi::1 + + Allow clients from a machine with that IP number to connect. + Numeric match is enough, name is not required anymore. + + I:x:secret:*.tut.fi::1 + + Allow clients from machines matching ``*.tut.fi'' to connect + with the password ``secret''. + + I:*::*::1 + + Allow anyone from anywhere to connect your server. + + This is the easiest way, but it also allows people to for + example dump files to your server, or connect 1000 (or how many + open sockets per process your OS allows) clients to your machine + and take your network ports. Of course the same things can be + done by simply telnetting to your machine's SMTP port (for + example). + + I:x::*.fi:6667:1 + + Allow clients from machines matching ``*.fi'' to connect on the + port 6667. + + I:135.11.35.*::*.net::1 + + Allows clients from machines which host name matches ``*.net'' + or which IP address matches ``135.11.35.*'' to connect to the + server. If the host name does not match ``*.net'' then the IP + address is used for these clients, even if the host name is + known. + + I:135.11.35.*::::1 + + Allows clients from machines which IP address matches + ``135.11.35.*'' to connect to the server. If the host name is + known, is it used as address for these clients. + + NNEEWW!!!!!! + As of the 2.7.2d version of the server, the server is able to + accept connections on multiple ports. I-lines are required for + each P-line to allow connections to be accepted. For unix + sockets, this means either adding I:/path/port::/path/port or + some variation (wildcards are recognised here). For internet + ports, there must be an I-line which allows the host access as + normal, but the port field of the I-line must match that of the + port of the socket accepting the connectiion. A port number of 0 + is a wildcard (matches all ports). + + NNEEWW!!!!!! + As of the 2.9.1 version of the server, i lines are introduced. + They work the same way as I lines, but the clients matching an i + line will have a restricted connection. (no nick/mode change, no + kick). Such users will have their username prefixed by +, = or - + depending on the ident reply. + + 44..66.. OOppeerraattoorr pprriivviilliiggeess + + How to become the IRC administrator on your site + + IInnttrroodduuccttiioonn + To become an IRC Administrator, IRC must know who is authorized + to become an operator and what their ``Nickname'' and + ``Password'' is. + + FFoorrmmaatt + + O:<TARGET Host NAME>:<Password>:<Nickname>:<Port>:<Class> + + + + OO Speficies Operator record. If you use capital letter (``O'') in + it, it specifies a global operator. Small letter (``o'') + specifies a local operator. Local operator has basically the + same rights except global operator with some restrictions. + + TTAARRGGEETT HHoosstt NNAAMMEE + Tells IRC which host you have the privileges FROM. This means + that you should be logged into this host when you ask for the + priviliges. If you specify ``tolsun.oulu.fi'' then IRC will + expect your CLIENT to be connected at ``tolsun.oulu.fi'' - when + you ask for OPERATOR privileges from ``tolsun.oulu.fi''. You + cannot be logged in at any other host and be able to use your + OPERATOR privileges at tolsun, only when you are connected at + TOLSUN will this work - this is a safeguard against unauthorized + sites. + + PPaasssswwoorrdd + If your AUTHORIZATION Password - this is the password that let's + IRC know you are who you say you are! Never tell anyone your + password and always keep the ``ircd.conf'' file protected from + all of the other users. + + NNiicckknnaammee + The Nickname you usually go by - but you can make this what you + want. + + PPoorrtt + Unused. + + CCllaassss + The class field should refer to an existing class (preferably + having a lower number than that for the relevant I-line) and + determines the maximum number of simultaneous uses of the O-line + allowable through the max. links field in the Y-line. + + EExxaammppllee + O:orion.cair.du.edu:pyunxc:Jeff::1 + + There is an OPERATOR at ``orion.cair.du.edu'' that can get + Operator priviliges if he specifies a password of ``pyunxc'' and + uses a NICKNAME of ``Jeff''. + + + 44..77.. RReessttrriicctt ccoonnnneeccttiioonnss + + Let an external program decide if a client should be allowed or not. + + IInnttrroodduuccttiioonn + R lines provide a convenient way to handle user access to the + server with an external program. The outside program given + three parameters: the client's username (set by the USER + command), the client's hostname, and the client's ident reply + (``unknown'' if none). + + It is expected to return a reply line where the first word is + either ``Y'' or ``N'' meaning `Yes Let them in'' or ``No don't + let them in''. If the first word begins with neither ``Y'' or + ``N'' the default is to let the person on. + + FFoorrmmaatt + + R:<Target Host Name>:<Program>:<User>::: + + + + RR This specifies a restrict record. + + TTaarrggeett HHoosstt NNaammee + In this field you specify the Hostname that the user is + connecting from. If you wanted to restrict connects to IRC from + ``orion.cair.du.edu'' then you would want to enter + ``orion.cair.du.edu''. + + PPrrooggrraamm + This is the external program to run to know if the user is + allowed on your server. + + UUsseerr + The Username of the user you want removed from IRC. For example + ``root''. + + + 44..88.. EExxcclluuddeedd aaccccoouunnttss + + Remove an errant user from IRC on your site. + + IInnttrroodduuccttiioonn + Obviously it is hoped that you wouldn't have to use this + command. Unfortunately sometimes a user can become unmanageable + and this is your only recourse - the KILL USER command. THIS + COMMAND ONLY AFFECTS YOUR SERVER - If this user can connect to + another SERVER somewhere else in the IRC-Network then you would + have to talk to the administrator on that site to disable his + access from that IRCD Server as well. + + FFoorrmmaatt + + K:<Host Name>:<time interval(s)|comment>:<User>:<port>: + + + + FFoorrmmaatt + + k:<Host Name>:<time interval(s)|comment>:<Auth>:<port>: + + + + KK ``K'' tells the IRCD that you are making a KILL USER command + entry. + + HHoosstt NNaammee + In this field you specify the Hostname or the IP address (Single + IP, Wildcard notation or bitmask notation) that the user is + connecting from. If you wanted to REMOVE connects to IRC from + ``orion.cair.du.edu'' then you would want to enter + ``orion.cair.du.edu''. If you want to REMOVE ALL HOSTS access + you can use ``*'' (Wild Card notation) and no matter what host + the USERNAME (specified in Field 4) connects from s/he will be + denied access. Removing all hosts isn't very smart thing to do + though, why would you run an ircd if you allow nobody to connect + to it anyways ? + + If you specify an IP address, IP mask, or an IP bitmask, it will + match clients connecting from the matching addresses, no matter + if they resolve or not. + + You can prefix an IP address, an IP mask, or IP bitmask by ``='' + in which case only non resolving matching hosts will be banned. + + ttiimmee iinntteerrvvaall((ss))||ccoommmmeenntt + Either leave this field empty or put a comment, then the line + active continuously for the specified user/host machine. You + may also specify intervals during the line should be active, see + examples below. + + UUsseerr + The USERNAME of the user you want removed from IRC. For example + ``root''. + + AAuutthh + If the user's ident server replies with the OTHER type (as + opposed to the UNIX type), the reply is not used to set the + user's username. (lowercase) k lines can be used in these case + to reject users based on their ident reply. + + This field will be matched against the ident server reply. It + is important to note that OTHER replies are prefixed with a + ``-'' by the ircd, while UNIX replies are not. + + PPoorrtt + The port on which the Kill line will be effective. 0 means all + ports. + + EExxaammpplleess + K:orion.cair.du.edu::jtrim:0: + + + If user ``jtrim'' connects to IRC from host + ``orion.cair.du.edu'' then IMMEDIATELY REMOVE HIM from my IRCD. + + k:*.stealth.net::-43589:0: + + If a user connects from any host that has the suffix + ``stealth.net'' and if that host ident server returns ``-43589'' + - then IMMEDIATELY REMOVE THEM from my IRCD. + + K:*.cair.du.edu::root:0: + + If user ``root'' connects to IRC from any host that has the + suffix ``cair.du.edu'' - then IMMEDIATELY REMOVE THEM from my + IRCD. + + K:*::vijay:0: + + This line reads ``I don't care WHAT HOST user ``vijay'' is on, I + will NEVER allow username ``vijay'' to login to my IRCD.'' + + K:*.oulu.fi:0800-1200,1400-1900:*:0: + + This disallows all users from hosts with enddomain ``oulu.fi'' + access to your server between 8 and 12am, 2 and 7pm. Users get + kicked off if they're already signed on when the line becomes + active (they'll get a warning 5 minutes before). + K:192.11.35.*::*:0: + + This line disallows all hosts whose IP address matches + ``192.11.35.*'' to login to the ircd. + + K:=192.11.35.*::*:0: + + This line disallows all hosts whose IP address matches + ``192.11.35.*'' and which didn't resolve to login to the ircd. + + + 44..99.. SSeerrvveerr ccoonnnneeccttiioonnss + + How to connect to other servers, How other servers can connect to you + + WWAARRNNIINNGG:: The hostnames used as examples are really only examples and + not meant to be used (simply because they don't work) in real life. + + + Now you must decide WHICH hosts you want to connect to and WHAT ORDER + you want to connect to them in. For my example let us assume I am on + the machine "rieska.oulu.fi" and I want to connect to irc daemons on 3 + other machines: + + +o ``garfield.mit.edu'' - Tertiary Connection + + +o ``irc.nada.kth.se'' - Secondary Connection + + +o ``nic.funet.fi'' - Primary Connection + + + And I prefer to connect to them in that order, meaning I first want to + try connecting to ``nic.funet.fi'', then to ``irc.nada.kth.edu'', and + finally to ``garfield.mit.edu''. So if ``nic.funet.fi'' is down or + unreachable, the program will try to connect to ``irc.nada.kth.se''. + If irc.nada.kth.se is down it will try to connect to garfield and so + forth. + + PLEASE limit the number of hosts you will attempt to connect to down + to 3. This is because of two main reasons: + + 1. to save your server from causing extra load and delays to users + + 2. to save internet from extra network traffic (remember the old rwho + program with traffic problems when the number of machines + increased). + + + FFoorrmmaatt + + C:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<TARGET PORT>:<Class> + + + + for example: + + C:nic.funet.fi:passwd:nic.funet.fi:6667:1 + + - or - + + C:128.214.6.100:passwd:nic.funet.fi:6667:1 + + - or - + + C:root@nic.funet.fi:passwd:nic.funet.fi:6667:1 + + Each field is separated with a ":" charcter: + + CC This field tells the IRC program which option is being + configured. "C" corresponds to a server Connect option. + + TTAARRGGEETT HHoosstt AAddddrr + Specifies the host name or IP address of the machine to connect + to. If ``user@'' prefixes the actual hostname or IP address the + server will require that the remote username returned by the + ident server be the same as the one given before the ``@''. + + PPaasssswwoorrdd + The password of the other host. A password must always be + present for the line to be recognized. + + TTAARRGGEETT HHoosstt NNAAMMEE + The full hostname of the target machine. This is the name that + the TARGET server will identify itself with when you connect to + it. If you were connecting to nic.funet.fi you would receive + ``nic.funet.fi'' and that is what you should place in this + field. + + TTAARRGGEETT PPOORRTT + The INTERNET Port that you want to connect to on the TARGET + machine. Most of the time this will be set to ``6667''. If this + field is left blank, then no connections will be attempted to + the TARGET host, and your host will accept connections FROM the + TARGET host instead. The port field can contain 2 ports, + separated by a . In this case, the first port is used when auto- + connecting, the second port is used for the UDP pings to the + targer server. + + CCllaassss + The class field should refer to an existing class and determines + the maximum number of simultaneous uses of the C-line allowable + through the max. links field in the Y-line. + + NNEEWW!!!!!! + As of the 2.9.3 version of the server, server connections can be + compressed with the zlib library. To define a compressed + connection, you must have compiled the server with ZIP_LINKS + defined (cf 2.h), and use a _lowercase_ C line. + + Some examples: + + +o C:nic.funet.fi::nic.funet.fi:6667:1 + + This reads: Connect to host ``nic.funet.fi'', with no password and + expect this server to identify itself to you as ``nic.funet.fi''. + Your machine will connect to this host to port 6667. + + +o C:18.72.0.252:Jeff:garfield.mit.edu:6667:1 + + This reads: Connect to a host at address ``18.72.0.252'', using a + password of ``Jeff''. The TARGET server should identify itself as + ``garfield.mit.edu''. You will connect to Internet Port 6667 on + this host. + + +o C:irc.nada.kth.se::irc.nada.kth.se:1 + + This reads: do not attempt to connect to ``irc.nada.kth.se'', if + ``irc.nada.kth.se'' requests a connection, allow it to connect. + + Now back to our original problem, we wanted OUR server CONNECT to 3 + hosts, ``nic.funet.fi'', ``irc.nada.kth.se'' and ``garfield.mit.edu'' + in that order. So as we enter these entries into the file they must + be done in rreevveerrssee order of how we could want to connect to them. + + Here's how it would look if we connected ``nic.funet.fi'' first: + + C:garfield.mit.edu::garfield.mit.edu:6667:1 + C:irc.nada.kth.se::irc.nada.kth.se:6667:1 + C:nic.funet.fi::nic.funet.fi:6667:1 + + Ircd will attempt to connect to nic.funet.fi first, then to irc.nada + and finally to garfield. + + RReecciipprrooccaall eennttrriieess:: Each ``C'' entry requires a corresponding ``N'' + entry that specifies connection priviliges to other hosts. The ``N'' + entry contains the password, if any, that you require other hosts to + have before they can connect to you. These entries are of the same + format as the ``C'' entries. + + + + FFoorrmmaatt + The format for the NOCONNECT entry in the ``ircd.conf'' is: + + N:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<Domain Mask>:<Class> + + + + Let us assume that ``garfield.mit.edu'' connects to your server and + you want to place password authorization authorization on garfield. + The ``N'' entry would be: + + N:garfield.mit.edu:golden:garfield.mit.edu:: + + This line says: expect a connection from host ``garfield.mit.edu'', + and expect a login password of ``golden'', and expect the host to + identify itself as ``garfield.mit.edu''. + + N:18.72.0.252::garfield.mit.edu:: + + This line says: expect a Connection from host ``18.72.0.252'', and + don't expect login password. The connecting host should identify + itself as ``garfield.mit.edu''. + + NN ``N'' corresponds to a server Noconnect option. + + TTAARRGGEETT HHoosstt AAddddrr + Specifies the host name or IP address of the machine to connect + to. If ``user@'' prefixes the actual hostname or IP address the + server will require that the remote username returned by the + ident server be the same as the one given before the ``@''. + + PPaasssswwoorrdd + The password of the other host. A password must always be + present for the line to be recognized. If CRYPT_LINK_PASSWORD is + defined in config.h, this password must be crypted. + + TTAARRGGEETT HHoosstt NNAAMMEE + The full hostname of the target machine. This is the name that + the TARGET server will identify itself with when you connect to + it. If you were connecting to nic.funet.fi you would receive + ``nic.funet.fi'' and that is what you should place in this + field. + + DDoommaaiinn MMaasskk + Domain masking, see below. + + + CCllaassss + The class field should refer to an existing class. + + WWiillddccaarrddss ddoommaaiinnss + To reduce the great amount of servers in IRCnet wildcard DOMAINS + were introduced in 2.6. To explain the usage of wildcard domains + we take an example of such: + + *.de - a domain name matching all machines in Germany. + + Wildcard domains are useful in that ALL SERVERS in Germany (or + any other domain area) can be shown as one to the rest of the + world. Imagine 100 servers in Germany, it would be incredible + waste of netwotk bandwidth to broadcast all of them to all + servers around the world. + + So wildcard domains are a great help, but how to use them ? + + They can be defined in the N-line for a given connection, in + place of ``Domain Mask'' you write a magic number called + wildcard count. + + Wildcard count tells you HOW MANY PARTS of your server's name + should be replaced by a wildcard. For example, your server's + name is ``tolsun.oulu.fi'' and you want to represent it as + ``*.oulu.fi'' to ``nic.funet.fi''. In this case the wildcard + count is 1, because only one word (tolsun) is replaced by a + wildcard. + + If the wildcard count would be 2, then the wildcard domain would + be ``*.fi''. Note that with wildcard name ``*.fi'' you could NOT + connect to ``nic.funet.fi'' because that would result in a + server name ccoolllliissiioonn (*.fi matches nic.funet.fi). + + I advice you to not to use wildcard servers before you know for + sure how they are used, they are mostly beneficial for backbones + of countries and other large areas with common domain. + + + + 44..1100.. DDeennyy aauuttoo--ccoonnnneeccttiioonnss + + + IInnttrroodduuccttiioonn + D lines were implemented to give server administrators more + control on how auto connections are done. This will most likely + only be useful for big networks which have complex + configurations. + + FFoorrmmaatt + + D:<Denied Server Mask>:Denied Class:<Server Name>:Server Class: + + + + DDeenniieedd SSeerrvveerr MMaasskk + This field is matched against all servers currently present on + the network. + + DDeenniieedd CCllaassss + If this field contains a class number, it will match if any + server in that class is currently present on the network. Note + that this can be true for any server, even the ones not directly + connected. + + + SSeerrvveerr MMaasskk + This field is matched against the server name that the server + wants to auto connect to. + + SSeerrvveerr CCllaassss + This field is used to match against the class to which belong + the servers for which an autoconnect is set. + + EExxaammpplleess + D:*.edu::*.fi:: + + Don't auto-connect to any ``*.fi'' server if any server present + on the network matches ``*.edu''. + + D::2:eff.org:3: + + Do now auto-connect to ``eff.org'', or any server in class ``3'' + if a server defined to be in class ``2'' is currently present on + the network. + + + 44..1111.. HHuubb ccoonnnneeccttiioonnss + + + IInnttrroodduuccttiioonn + In direct contrast to L-lines, the server also implements H- + lines to determine which servers may act as a hub and what they + may ``hub for''. If a server is only going to supply its own + name (ie act as a solitary leaf) then no H-line is required for, + else a H-line must be added. + + FFoorrmmaatt + + H:<Server Mask>:*:<Server Name>:: + + + + SSeerrvveerr MMaasskk + All servers that are allowed via this H-line must match the mask + given in this field. + + SSeerrvveerr NNaammee + This field is used to match exactly against a server name, + wildcards being treated as literal characters. + + EExxaammpplleess + H:*.edu::*.bu.edu:: + + Allows a server named ``*.bu.edu'' to introduce only servers + that match the ``*.edu'' name mask. + + H:*::eff.org:: + + Allows ``eff.org'' to introduce (and act as a hub for) any + server. + + NNoottee + It is possible to have and use multiple H-lines (or L-lines) for + the one server. eg: + + + H:*.edu:*:*.bu.edu:: + H:*.au:*:*.bu.edu:: + + + + is allowed as is + + + L:*.edu:*:*.au:: + L:*.com:*:*.au:: + + + + + 44..1122.. LLeeaaff ccoonnnneeccttiioonnss + + + IInnttrroodduuccttiioonn + To stop servers which should only act as leaves from hubs + becoming hubs accidently, the L line was introduced so that hubs + can be aware of which servers should and shouldnt be treated as + leaves. A leaf server is supposed to remain a node for the + entirity of its life whilst connected to the IRC server network. + It is quite easy, however for a leaf server to be incorrectly + setup and create problems by becoming a node of 2 or more + servers, ending its life as a leaf. The L line enables the + administrator of an IRC ``Hub server'' to ``stop'' a server + which is meant to act as a leaf trying to make itself a hub. + If, for example, the leaf server connects to another server + which doesnt have an L-line for it, the one which does will drop + the connection, once again making the server a leaf. + + FFoorrmmaatt + + L:<Server Mask>:*:<Server Name>:<Max Depth>: + + + + SSeerrvveerr MMaasskk + Mask of which servers the leaf-like attributes are used on when + the server receives SERVER messages. The wildcards * and ? may + be used within this field for matching purposes. If this field + is empty, it acts the same as if it were a single * (ie matches + everything). + + SSeerrvveerr NNaammee + The name of the server connected to you that for which you want + to enforce leaf-like attributes upon. + + MMaaxx DDeepptthh + Maximum depth allowed on that leaf and if not specified, a value + of 1 is assumed. The depth is checked each time a SERVER + message is received by the server, the hops to the server being + the field checked against this max depth and if greater, the + connection to the server that made its leaf too deep has its + connection dropped. For the L-line to come into effect, both + fields, 2 and 4, must match up with the new server being + introduced and the server which is responsible for introducing + this new server. + + + 44..1133.. VVeerrssiioonn lliimmiittaattiioonnss + + + IInnttrroodduuccttiioonn + V-lines are used to restrict server connecting to you based on + their version and on compile time options. + + FFoorrmmaatt + + + V:<Version Mask>:<Flags>:<Server Mask>:: + + + + VVeerrssiioonn MMaasskk + The matching version number strings will be rejected. + + FFllaaggss + If any flag specified in this field is found in the peer's flags + string, it will be rejected. + + SSeerrvveerr MMaasskk + This field is used to match server names. The V line will be + used for servers matching the mask given in this field. + + SSeerrvveerr TTyyppee + Both the VVeerrssiioonn MMaasskk and the FFllaaggss should be prefixed with the + server type identification. This implementation uses the id + ``IIRRCC'' (starting with version 2.10). + + EExxaammpplleess + V:IRC/021001*::*:: + + Disallows any ``IRC'' server which version is 2.10.1* to + connect. + + V:IRC/021001*:IRC/D:*:: + + Disallows any ``IRC'' server which version is 2.10.1* or which + has been compiled with DEBUGMODE defined to connect. + + V:*/0209*:::: + + Disallows any server using the 2.9 protocol to connect. + + NNoottee + It is possible to have and use multiple V-lines for the one + server mask. + + V:IRC/021001*::*:: + + V:IRC/021002*::*:: + + is allowed. + + PPrroottooccooll VVeerrssiioonn + Only the 4 first digit of the VVeerrssiioonn NNuummbbeerr are standard: they + define the protocol version. The remaining of the string is + implementation dependant; matches on this part should be used + with particular identification. + + FFllaaggss + are not standard. Therefore, this field sshhoouulldd aallwwaayyss contain a + specific identification. + + + 44..1144.. EExxcclluuddeedd mmaacchhiinneess + + Disallowing SERVERS in your irc net. + + IInnttrroodduuccttiioonn + In some cases people run into difficulties in net + administration. For one reason or another you do not want a + certain server to be in your net (for example because of the + security holes it opens for every server if it's not secured + carefully). In that case you should use Q-lines in your server. + When you specify a server name in Q-line, everytime some server + link tries to introduce you a server (remember, all server names + are broadcast around the net), that name is checked if it + matches the Q-lines in your server. If it matches, then yyoouurr + sseerrvveerr disconnects the link. Note that just placing Q-lines to + your server probably results in yyoouurr sseerrvveerr being left alone, + unless other servers have agreed to have the same Q-line in + their ircd configuration files as well. + + EExxaammppllee + Q::of the security holes:foo.bar.baz:: + + This command excludes a server named ``foo.bar.baz'', the reason + is given to be security holes (you should give a reason, it is + polite). The first field is unused, so leave it empty. + + + 44..1155.. SSeerrvviiccee ccoonnnneeccttiioonnss + + + IInnttrroodduuccttiioonn + The Service is a special kind of IRC client. It does not have + the full abilities of a normal user but can behave in a more + active manner than a normal client. + + Services are not intended for interactive usage, and are better + suited for automated clients. + + FFoorrmmaatt + + S:<TARGET Host Mask>:<Password>:<Service Name>:<Service Type>:<Class> + + + + TTAARRGGEETT HHoosstt MMaasskk + The host mask should be set to match the host(s) from which the + service will be connecting from. This may be either an IP# or + full name (prefered). + + PPaasssswwoorrdd + This is the password which must be passed in the SERVICE + command. + + SSeerrvviiccee NNaammee + The name used by the service. Services don't have nicknames, but + a static name defined by the S line. + + SSeerrvviiccee TTyyppee + The type of service. It defines the priviledges given to the + service. Be very careful in the types you allow. The types can + be found in include/service.h + + CCllaassss + The class field should refer to an existing class. + + NNootteess + A service is not a very useful sort of client, it cannot join + channels or issue certain commands although most are available + to it. Services are rejected upon sending an unknown or + unallowed command. Services however, are not affected by flood + control and can be granted special privileges. It is therefore + wwiissee ttoo oovveerrsseeee tthhee uussee ooff SS--lliinneess wwiitthh mmuucchh ccaarree.. + + + + + 44..1166.. BBoouunnccee sseerrvveerr + + + IInnttrroodduuccttiioonn + This provides you a way to bounce clients to another server. + This information is provided to clients which are denied + connection, either because their connection class is full, or + the server is full, or they are not authorized to connect. + + FFoorrmmaatt + + B:<Class|Host Mask>::<Server Name>:<Port>: + + + + BB This specifies a Bounce record. + + CCllaassss||HHoosstt MMaasskk + This field specifies to which client this configuration line + applies to. It can be either a connection class number, a host + mask to be matched against the client's hostname, or an IP + address/mask/bitmask to be matched against the client's IP + address. + + When the server is completely full, it rejects clients with the + ``All connections in use'' message. In this case, the server + doesn't process the connections at all, and has no knowledge of + the client's host name, or class number. For these cases, this + field must be empty. + + SSeerrvveerr NNaammee + This specifies the IRC server hostname that the client should + use. + + PPoorrtt + This specifies the IRC server port that the client should + connect to. + + EExxaammppllee + B:2::irc.stealth.net:6660: + + Rejected clients in class 2 are advised to use + ``irc.stealth.net'' on port 6660. + + B:*.fi::irc.funet.fi:6667: + + Finnish client should use irc.funet.fi when they cannot be taken + anymore. + + B:::irc2.stealth.net:6667: + + When the server is completely full, clients should use the + secondary server. + + + 44..1177.. DDeeffaauulltt llooccaall sseerrvveerr ((ffoorr llooccaall cclliieennttss)) **OOBBSSOOLLEETTEEDD** + + + IInnttrroodduuccttiioonn + This defines the default connection for the irc client. If you + are running an ircd server on the same machine, you will want to + define this command to connect to your own host. If your site + is not running a server then this command should contain the + TARGET host's connection information and password (if any). + + + FFoorrmmaatt + + U:<TARGET Host addr>:<Password>:<TARGET Host NAME>:<Internet Port> + + + + EExxaammpplleess + U:tolsun.oulu.fi::tolsun.oulu.fi:6667 + + U:128.214.5.6::tolsun.oulu.fi:6667 + + U:tolsun.oulu.fi::tolsun.oulu.fi + + If the port number is omitted, irc will default to using 6667. + + + 55.. RReellaatteedd rreessoouurrcceess + + + MMaaiilliinngg lliisstt + A list is dedicated to the people using ircd. If you have + trouble running ircd, or wish to discuss the future, you can + subscribe by sending an email to majordomo@irc.org, with + ``ssuubbssccrriibbee iirrccdd--uusseerrss'' in the body. + + If you just have a question and don't want to subscribe to the + list, mail to ircd-users@irc.org. Be sure to indicate which + version you are using. + + DDeevveellooppmmeenntt + Technical discussions and development are carried on ircd- + dev@irc.org. People interested in very early testing, and/or + working on the source code are welcome. This is done by sending + an email to majordomo@irc.org, with ``ssuubbssccrriibbee iirrccdd--ddeevv'' in + the body. + + FFAAQQ + It can be found on the WWW, at + <http://www.stealth.net/~kalt/irc/faq.html>. + + WWWWWW 22..99 + Vesa Ruokonen has also put serveral pages related to the 2.9 + servers on the WWW: <http://www.irc.org/~irc/server/>. + + + 66.. RReeppoorrttiinngg aa bbuugg + + If you encounter a bug in the software, here is how and where to + report it. + + + 66..11.. HHooww ttoo rreeppoorrtt aa bbuugg + + To save everyone time, make sure that your e-mail contains all the + information related to your problem. In particular, we need to know: + + PPaacckkaaggee vveerrssiioonn + The IRC software version you are using: please include the + output obtained by running ``irc -v'' for the client, and/or + ``ircd -v'' for the server. + + Also, let us know if you have applied any patch to the package + or if it is the vanilla version. + + OOSS Please, indicate which OS version you are running. + + CCoonnffiigguurraattiioonn + If it is related to a configuration problem with the server, + include the relevant parts of the configuration file. + + BBaacckkttrraaccee + If the bug results in a crash, please include the backtrace. + (This can be done, for example, by running ``gdb'' on the core + file, and typing ``where''). + + FFiixx + If you have a fix, don't forget to include it. + + + 66..22.. WWhheerree ttoo sseenndd aa bbuugg rreeppoorrtt + + Reports should be sent to ircd-bugs@irc.org. Your report will be + reviewed and forwarded to the appropriate mailing list. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/Juped/Advertisement b/doc/Juped/Advertisement new file mode 100644 index 0000000..585c467 --- /dev/null +++ b/doc/Juped/Advertisement @@ -0,0 +1,39 @@ + The Internet Relay Chat Program - IRC + + Author: Jeff Trim, April '89 + Revised: Greg Lindahl, Oct '90 (gl8f@virginia.edu) + Re-Revised: Helen Rose, March '94 (hrose@kei.com) + +Have you ever wanted to talk with computer users in other parts of the +world? Well guess what? You can! The network is called IRC and it is +networked much over North America, Europe, and Asia, Oceania, and parts of +Africa. This program is a substitution for talk(1), ytalk(1) and many +other multiple talk programs you might have read about. When you are +talking in IRC, everything you type will instantly be transmitted around +the world to other users that might be watching their terminals at the +time - they can then type something and RESPOND to your messages - and +vise versa. I should warn you that the program can be very addictive once +you begin to make friends and contacts on IRC ;-) especially when you +learn how to cuss in 14 languages. + +Topics of discussion on IRC are varied, just like the topics of Usenet +newsgroups are varied. Technical and political discussions are popular, +especially when world events are in progress. IRC is also a way to expand +your horizons, as people from many countries and cultures are on, 24 hours +a day. Most conversations are in English, but there are always places to +chat in German, Japanese, and Finnish, and occasionally other languages. + + How To Get IRC (technical) + +IRC is a fully-distributed client-server system, much like +NNTP-Usenet, with several clients availble in C and elisp. You may ftp +documentation and clients from any of the following sites: + +many kinds of clients (C, elisp, X11, VMS, REXX for VM, MSDOS, Macintosh): +cs.bu.edu:/irc/clients +ftp.acsu.buffalo.edu:/pub/irc +ftp.funet.fi:/pub/unix/irc +coombs.anu.edu.au:/pub/irc + +If you have any questions about IRC installation, write to hrose@kei.com. + diff --git a/doc/Juped/ChangeLog.common b/doc/Juped/ChangeLog.common new file mode 100644 index 0000000..f6b10ae --- /dev/null +++ b/doc/Juped/ChangeLog.common @@ -0,0 +1,91 @@ +/************************************************************************ + * IRC - Internet Relay Chat, lib/ircd/ChangeLog + * Copyright (C) 1990 Mike Bolotski + * + * 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. + */ + +Mon Sep 02 17:08:43 1991 Darren Reed <avalon@coombs.anu.edu.au> + + * general comments: + + various files now have dependencies depending on whether it is the + client or server the files are being compiled for. + + * parse.c + + find_*() routines changed to use hash table lookup. + + * send.c + + changed to maximize presence of the local client array. + sendto_ops_butone() fixed back to not broadcast wallops. + +Sun Jun 30 23:21:50 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * parse.c + Changed from->name to sender; Maybe double search can be removed + + * send.c + LOOP detected!! + Fixed sendto_channel_butone() as suggested by msa. + send.c needs TOTAL cleanup. + + * bsd.c + Final fixes of inet_netof() and inet_nota() + + * send.c + Changed some SendMessage() into sendto_one() (code duplication ;)) + +Wed Jun 20 11:25:54 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + Added gruner's patches. + Patches to make string channels work done as well to some files. + +Sun Jun 17 21:29:04 1990 Armin Gruner (gruner@informatik.tu-muenchen.de) + + * parse.c + In case that a server sends an unknown command to a client (!!), + debug() is called, as client handles debug outputs now. + +Thu May 10 17:15:12 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + * dbuf.c + Fixed memcpy and bcopy problems in different machines + +Sat Jan 6 15:14:14 1990 Mike Bolotski (mikeb at coho.ee.ubc.ca) + + * config.h + Added Poohbear's cleanup changes. + Added #undef SYSV if mips is defined (as per jlp@hamblin.byu.edu) + + +Sat Dec 16 16:06:17 1989 Mike Bolotski (mikeb at coho.ee.ubc.ca) + + * config.h + + Changed NOTTY to TTYON, and reversed the logic everywhere. + Now TTYON has to be explicitly defined in order to produce + tty output. + + +Thu Dec 14 12:50:36 1989 Mike Bolotski (mikeb at coho.ee.ubc.ca) + + * version.c + Added a version.c file to contain the version numbers and + prompt strings. Removed the old #ifdef MAIN style definition + + + diff --git a/doc/Juped/ChangeLog.doc b/doc/Juped/ChangeLog.doc new file mode 100644 index 0000000..538d791 --- /dev/null +++ b/doc/Juped/ChangeLog.doc @@ -0,0 +1,90 @@ +/************************************************************************ + * IRC - Internet Relay Chat, doc/ChangeLog + * Copyright (C) 1990, Mike Bolotski + * + * 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. + */ + + +Tue Mar 22 17:32:33 1994 Helen T. Rose Davis (hrose@rocza.kei.com) + + * Re-rewrite of documentation to coincide with 2.8.17 release. + +Mon Mar 29 01:26:16 1993 + + * INTSALL updated. + * m4macros added. + +Fri Jan 22 22:49:20 1993 + + * INTSALL updated. + +Thu Dec 17 19:41:19 1992 Darren Reed <avalon@coombs.anu.edu.au> + + * general Well, these docs were updated for 2.7, nobody + documented it - must be a general distaste for + documentation I'd say :) + + Work on 2.8 documentation slowly creaping along. + +Mon Sep 02 17:12:41 1991 Darren Reed <avalon@coombs.anu.edu.au> + + * Documentation brought upto date with new features to 2.6.2 + + +Mon Aug 26 16:51:01 1991 Helen Trillian Rose (hrose@eff.org) + + * Rewrite of documentation (again) to coincide with the 2.6.2 + release. + +Wed Oct 31 18:05:12 1990 Jarkko Oikarinen + + * Added hrose@cs.bu.edu's patches to irc2.6 + - Documentation rewrites... + - patches + +Fri Jun 29 18:54:40 1990 Armin Gruner (gruner@informatik.tu-muenchen.de) + + * NETWORKING + + Added some sites in Germany + +Sat Dec 16 15:56:41 1989 Mike Bolotski (mikeb at coho.ee.ubc.ca) + + * INSTALL + + Modified the installation document as per Valdis's nitpicking. + Improved the grammer and speling of a lot of dokumentation. + Removed lots and lots of informal wording, eh? and especially + the long run on sentences that try to say a lot but really don't + and are present only to show the author's superiority, especially + when quoting from a prestigious work like Webster's New Collegiate + Dictionary, gosh, specifically the 1979 version (ISBN + 0-87779-3580-1), which I guess I should run out and purchase + immediately, for otherwise I might be considered ignorant by + wise men who have written a great deal of code in VS/Pascal and + even IBM Assembler and still can't manage not to avoid including + .QUIT in every goddam mail message. + + + * HISTORY + + Added a recent history of the version numbers and the new + patchlevel mechanism. + + + * BugList + + Added a BugList file including the notation of bug numbers. diff --git a/doc/Juped/ChangeLog.include b/doc/Juped/ChangeLog.include new file mode 100644 index 0000000..481b39b --- /dev/null +++ b/doc/Juped/ChangeLog.include @@ -0,0 +1,85 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/ChangeLog + * 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. + */ + +Sat Jul 25 05:52:43 1992 + * common.h Dynix (sequent) doesnt have malloc.h but it appears + Dynix/PTX does. Blah. + +Fri Jul 24 18:43:35 1992 + * config.h, sys.h, common.h + Applied patches from Adrian Hall for compiling on + Dynix/PTX (email: csc260@central1.lancaster.ac.uk). + +Mon Sep 02 17:06:59 1991 Darren Reed <avalon@coombs.anu.edu.au> + + * config.h + added MAXCONNECTIONS (see config.h for details) + added NICKNAMEHISTORYLENGTH + + * hash.h + Added to support for ../ircd/hash.c + + * msg.h + Commands reordered in (hopefully) order of useage. + All commands now marked for flood protection. + +Tue Jul 02 11:10:26 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * config.h + changed MSG_MAIL to MSG_NOTE as requested by the author. + +Mon Jul 01 20:37:38 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * config.h + #define WALL a priori. WALL should be go away in future version. + + * numeric.h + ERR_TOOMANYTARGETS added. + +Mon Dec 03 13:56:36 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * config.h + Switches for NEED_* added. + +Mon Nov 26 10:33:43 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * sys.h[.SH] + declaration of dummy() and restart() depending on configuration + process. + +Sat Nov 10 18:00:44 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * New header file: common.h, should be included into all source + files. Created sys.h.SH, Makefile.SH, config.h.SH; these files + are extracted by running Configure. + + * Added some function declarations + Removed Makefile (do we need one here ?). + +Wed Jun 20 11:44:00 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + * config.h + MAIL changes to config.h + * struct.h + Numerous changes to file to make string channels work + +Thu May 10 22:37:23 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + * config.h + Added UPHOST into config.h (Who removed it ?) diff --git a/doc/Juped/ChangeLog.irc b/doc/Juped/ChangeLog.irc new file mode 100644 index 0000000..18a86b7 --- /dev/null +++ b/doc/Juped/ChangeLog.irc @@ -0,0 +1,77 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/ChangeLog + * Copyright (C) 1990 Mike Bolotski + * + * 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. + */ + +Mon Dec 9 06:38:57 1991 Darren Reed <avalon@coombs.anu.edu.au> + * All files + Updated to work properly with 2.7. Its early and I'm cold. + +Sun Jun 30 14:45:59 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * irc.c + Removed MSG protocol command. Kludge to get channel msgs working. + * msg.c + Reformatted WHOERPLY output :) + +Wed Nov 28 20:45:42 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * c_msg.c + Fixed abuf[123] overflow. (by using mybuf and removing the buffers) + +Sat Nov 10 17:59:29 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * Added #include "common.h" into all source files, moved "common" + and regularly used declarations to include/common.h + +Wed Jun 20 11:45:30 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + String channel fixes to files, added some numerics. + +Sun Jun 17 17:12:14 1990 Armin Gruner (gruner@informatik.tu-muenchen.de) + + * c_debug.c + New created file, for the benefit of wrong server stuff output + if client does not recognize it. common/debug.c has been removed. + + * c_numeric.c + Changed output of YOUWILLBEBANNED and YOUREBANNEDCREEP, now only + the first digits (== minutes) of the msg will be inserted. + + * irc.c + Defined debuglevel to DEBUG_ERROR, now more error + conditions are displayed. + + +Sat Jan 6 14:48:34 1990 Mike Bolotski (mikeb at coho.ee.ubc.ca) + + * screen.c + + Changed insert = ~insert to be insert = !insert. + Gotta be careful about those bitwise operators, WiZ. + + * swear.c + + Changed scroll to scroll_ok. Changed extern/static definitions + of tgoto, getenv to work with ANSI C compilers. + + * edit.c + + Changed #if HPUX to #if HPUX || defined(mips) + + + diff --git a/doc/Juped/ChangeLog.ircd b/doc/Juped/ChangeLog.ircd new file mode 100644 index 0000000..228ce0d --- /dev/null +++ b/doc/Juped/ChangeLog.ircd @@ -0,0 +1,458 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/ChangeLog + * Copyright (C) 1990 Mike Bolotski + * + * 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. + */ + +Tue Sep 1 20:16:42 1992 + * s_bsd.c, s_bsd.c, s_serv.c + * TRACE/STATS now show logfiles if logging is enabled. + +Tue Sep 1 03:56:21 1992 + * channel.c * bug found in set_mode() - length of strings when + setting/clearing chanop was possibly incorrect. + * a few optimizations have hopefully been added as + well. + + * s_bsd.c, s_auth.c + * RFC913 (authd) / TAP code separated from s_bsd,c to + s_auth.c + + * s_misc.c, s_debug.c + * various code/routines removed from s_misc.c and put + in s_debug.c where it truely belongs. + +Tue Aug 25 16:07:01 1992 + * ircd.c * chroot(2) option from Seth added to work along + with SET_UID & SET_GID for servers running as + root. (seth@ctr.columbia.edu) + +Thu Aug 13 18:46:53 1992 + * channel.c * Bug in send_channel_modes() fixed which causes + trashed +b's to be sent on server rejoins. + +Thu Aug 13 17:40:47 1992 + * channel.c * Added channel passwords (keys). + +Tue Aug 11 14:05:12 1992 + * channel.c * JOIN bug giving chanop on wrong channels fixed. + Reported by Rogue_F. + +Tue Aug 4 04:38:23 1992 + * s_bsd.c, s_serv.c, s_conf.c + * Username authentication for servers completed. + Username now required in host portion of the + C/N lines for a connection to be completed. + +Tue Aug 4 03:45:54 1992 + * IDENT changes finally debugged. + +Tue Aug 4 02:16:42 1992 + * s_bsd.c, s_user.c, s_serv.c, ircd.c + * IDENT code now written such that it works in a + similar manner to the DNS async code and thus should + stop the server hanging (if at all). + + * authuser.c * Removed. (redundant). + +Fri Jul 31 01:05:57 1992 + * s_user.c * m_whois() changes to stop people abusing /whois * + and kiling other links to/from that server. + +Sat Jul 25 07:33:20 1992 + * s_user.c * m_oper() fixed so it doesnt core dump when it + calls send_umode(). send_umode_toservs() added. + +Sat Jul 25 05:51:01 1992 + * s_bsd.c * Patches for little endian systems (ie sequents :) + completed. (Fixing of RPL_MYPORTIS) + +Fri Jul 24 18:43:35 1992 + * s_bsd.c, s_conf.c, ircd.c, s_misc.c + * Applied patches from Adrian Hall for compiling on + Dynix/PTX (email: csc260@central1.lancaster.ac.uk). + +Fri Jul 24 00:07:41 1992 + Its been busy with other things so these comments + apply over a few days. + + * general Compiles cleanly under ultrix 4.2 and AIX 3.1 + + * s_user.c O-lines host field changed to user@host. + This change could sweep across to other lines yet. + + * s_serv.c L-lines host field made functional. + + * s_bsd.c I-lines also take user@host as the host now :) + +Tue Jul 14 03:51:04 1992 + * s_msg.c, s_serv.c, s_user.c + - THE BIG SPLIT occured! s_msg.c split into two files: + s_serv.c and s_user.c + +Mon Jul 13 03:08:03 1992 Darren Reed <avalon@coombs.anu.edu.au> + * s_conf.c, class.c + - added MAXSENDQ. field for classes. + +Sun Jul 12 10:41:48 1992 Darren Reed <avalon@coombs.anu.edu.au> + * s_msg.c - added m_close + +Sat Jul 11 01:01:09 1992 Darren Reed <avalon@coombs.anu.edu.au> + * s_err.c - Created, debuged and Added. + * general - Generic creation of ERR and RPL numerics from routines + in s_err.c. The use of these is optional. + * channel.c - Changed NAMES, LIST to be able to query remote + servers. + - NAMES, LIST, TOPIC all understand channel name lists + using a comma (,) as a name separator. + +Sat Jul 4 22:40:35 1992 Darren Reed <avalon@coombs.anu.edu.au> + * s_bsd.c, ircd.c, s_conf.c, s_msg.c + - Changed DIE/RESTART/REHASH to be signal activated or + optionally allow operators to issue REHASH/RESTART. + +Sat Jul 4 04:12:43 1992 Darren Reed <avalon@coombs.anu.edu.au> + * s_bsd.c, res.c + - fixed automatic lookup of hostnames returned by a + lookup of the IP#. + +Fri Jul 3 16:15:39 1992 Darren Reed <avalon@coombs.anu.edu.au> + * channel.c - added comments to the KICK command. + * s_msg.c - rewrote WHOIS, optimized sending of JOIN channels at + net splits. + * general - checked to make sure all replies had a ':' in the + reply to mark the last parameter being sent. + +Thu Jul 2 07:56:46 1992 Darren Reed <avalon@coombs.anu.edu.au> + * channel.c - imposed 256 character limit on channel names for + clients local to the server. + +Thu Jul 2 03:41:15 1992 Darren Reed <avalon@coombs.anu.edu.au> + * s_msg.c - changed numeric reply 200 from TRACE. Now shows next + server in the reply line (extra arg). + +Tue Jun 30 04:53:11 1992 Darren Reed <avalon@coombs.anu.edu.au> + * s_bsd.c - split up check_server() to accomodate the name lookup + in the middle of it for access checking. + * s_msg.c - split up m_server to work with the splitup of + check_server(). + +Mon Jun 29 23:46:32 1992 Darren Reed <avalon@coombs.anu.edu.au> + * whowas.c - added RPL_ENDOFWHOWAS to the whowas reply chain. + +Sun Jun 28 21:31:20 1992 Darren Reed <avalon@coombs.anu.edu.au> + * channel.c, send.c + - channel name masks using ":mask" completed along with + removal of # significance. '%' channel prefix is + local to server. + + + The removal of the # significance was temporary due to + too many problems with the nickname/channelname space + problems. + + * s_bsd.c, res.c, s_conf.c + - hostname and ip number lookup working asynchronously. + * s_bsd.c - udp port created. echo's any data sent to it. + +Sun Dec 1 Greg Lindahl <gl8f@virginia.edu> + * general - gee, avalon, you could at least try. as of pre16 + numerics restored to old values. MSG_NOTE code + removed, because it does not pass Saber C. + * support.c - ctype macros now give values for EOF. + * dbuf.c - test for bozo compilers + * example.conf- more documentation + * s_msg.c - pjg's patch to fix m_server + * ircd.c - print message when debugging off and debugtty set + * config.h - remove many dead crufty options. + +Sun Dec 1 13:41:11 1991 Darren Reed <avalon@coombs.anu.edu.au> + * all files - There have been so many changes and bug fixes going + into 2.7 that it would be impossible to list them all. + +Mon Nov 4 14:35:07 1991 Darren Reed <avalon@coombs.anu.edu.au> + * s_msg.c - installed msa's patch to m_nick + +Mon Nov 4 01:03:45 1991 Darren Reed <avalon@coombs.anu.edu.au> + * all files - changed all functions to have "function_name" style + names. All macros now MacroName. + * general - lots of various different work in preparation for 2.7 + +Thu Sep 19 14:55:24 1991 Darren Reed <avalon@coombs.anu.edu.au> + * s_msg.c, channel.c + - moved m_topic() and m_invite() from s_msg.c to + channel.c + - changed m_topic() to now process # channel topics + +Mon Sep 02 16:27:53 1991 Darren Reed <avalon@coombs.anu.edu.au> + (lost previous ChangeLog which had accurate dates of additions + for 2.6.2. Following is changes from 2.6.1 to 2.6.2). + + * s_conf.c - added L-line handling for Leaf Enforcement. + (Courtesy Wumpus (Greg Lindhal)) + - added det_I_lines_butfirst to make sure each client + connection only ever has (at most) 1 I-line attached + to it. + + * channel.c - fixed ghost ChanOp problem from earlier versions. + - painful ^G mode bug fixed for 2.6.1 + + * ircd.c - some problems with TryConnections fixed. + + * s_bsd.c, ircd.c, s_msg.c + - local clients are now stored and referenced with an + array of pointers. This has a fixed size :/ + + * s_msg.c, list.c + - client list is now a double linked list. + - moved some code to list.c to create addition/deletion + routines to add/delete client records from the list. + + * list.c - added NICKNAMEHISTORYLENGTH to replace the 'magic' 200. + + * s_msg.c - Added following commands: + USERHOST <nickname> [n.[n.[n.[n.]]]] + ISON <nickname> [nickname...] + + * hash.c, s_msg.c, channel.c + - (finally) added hash tables for nickname, server and + channel name lookup. Nicknames and servers share the + same table. + +Thu Jul 04 20:31:10 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * s_numeric.c + Changed sptr->name to parv[0]; use strtoken() for loop. + +Tue Jul 02 11:11:15 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * ircd.c, channel.c, s_msg.c + changed MSG_MAIL to MSG_NOTE as requested by the author + Fixed m_links(); remote LINKS should work now. + * mail.c + Removed mail.c, replaced by new version 1.3pre8, now note.c + +Mon Jul 01 20:35:40 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * s_msg.c + m_notice(), m_text(), m_privmsg() merged to one function. + m_wall() changed. Default is WALL. Should be eliminated + anyways in next version. + + * channel.c + Changed error msgs when parameters from 'l' are missing. + +Sun Jun 30 14:53:42 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * s_msg.c + Major cleanups; Server/host mask msgs moved to NOTICEs. + m_whois changed. For nonexistent nickname an error is created now. + +Sat Jun 29 15:46:35 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * s_msg.c + Fixed m_summon error bug + Applied msa'a patches. Fixes ExitOneClient(). + + * channel.c + Fixed join ctrl-g bug + +Sat Apr 6 19:47:00 1991 Jarkko Oikarinen <jto@tolsun.oulu.fi> + + * Added destination parameter to /links (a'la /whois) + +Thu Apr 4 16:01:16 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * ircd.c, s_bsd.c + Fix SIGHUP - SIGHUP to ircd causes a rehash() finally. + + * c_msg.c + Fix KILL from an OPER - pre19 with wildcard match didn't pro- + pagate the correct sender. Server kills behind *-domains are + still unsolved. + +Sun Mar 31 08:57:12 1991 Jarkko Oikarinen <jto@tolsun.oulu.fi> + + * WALL placed under #ifdef. Default is no WALL + * Fixed JOIN mode option to accept more parameters + like userlimit. + +Sun Mar 24 07:43:00 1991 Jarkko Oikarinen <jto@tolsun.oulu.fi> + + * A couple minor bug fixes. + * Channel name to ERR_CHANOPRIVSNEEDED and ERR_NOTONCHANNEL. + +Sun Mar 17 09:50:12 1991 Jarkko Oikarinen <jto@tolsun.oulu.fi> + + * m_who() numeric RPL_ENDOFWHO (315) for all queries + * RPL_ENDOFWHOIS (316) reply added + * RPL_ENDOFWHO (315) and RPL_ENDOFWHOIS (316) return + the query parameter now as well. + * RPL_WHOISIDLE (317) returns the idle time of a particular user. + * RPL_NOTOPIC (331), RPL_TOPIC (332) return channel name as a + paramater (this has been already added to RPL_CHANNELMODEIS (324)) + * Limited trace (won't show users on a server) available now for + all users + * Fix to HuntServer() to make sure loops do not happen. + * Added new numeric, ERR_CHANOPRIVSNEEDED (482) which replaces + *all* ERR_NOPRIVILEGES (481) messages where the missing privileges + were channel operator privileges. + * KICK to user not existant on irc now generates + ERR_NOTONCHANNEL (442) error reply. + * ERR_NOSUCHSERVER (402) returns the server name as a parameter. + * ERR_CANNOTSENDTOCHAN (404) now returns the channel name you couldn't + send to. + +Mon Feb 25 16:08:51 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * s_msg.c + 'Fixed' K:-line behaviour of m_user(). Now, the connection + is not closed; USER-msg is distributed with K:-line remark, and + user isn't introduced locally, so user gets 'You have not registered + as a user'. + + * ircd.c + SIGHUP generates rehash() now. + +Mon Feb 11 18:57:56 1991 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * s_msg.c + Fixed m_server(). The domain matching was done against the + return value of GetClientName(), but this never matches + if the servername differs from the host name, because + [real socketname] is added to 'inpath'. + +Fri Jan 12 12:34:21 1991 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + * more ircd options at startup... + +Mon Dec 03 13:54:25 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * class.c, s_msg.c, s_bsd.c + Fixes from Avalon. Sigh. + +Wed Nov 28 14:07:11 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * class.c, s_bsd.c (CloseConnection) + Fixes from avalon (DEBUG stuff) + +Tue Nov 27 11:24:56 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * s_msg.c, s_bsd.c, ircd.c, class.c + Isolated the implementation of 'classes' to class.c (by using + macros for accessing the structure members) -- we should start + using this everywhere -- especially with this linear list of + clients!! + + * channel.h (new file) + prototyping, 'channel'-misc, try to isolate channel implemen- + tation to channel.h and channel.c + +Sun Nov 25 16:13:42 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * class.c, class.h + New files for class-handling. Applied Avalon's patches. + Change some code into more readable one (MIN). + +Tue Nov 13 11:44:28 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * s_msg.c + Fixed Invite bug. + + * s_bsd.c + Fixed overhead of check_access. + New function to get qualified (local) domain name: AddLocalDomain() + +Mon Nov 12 20:42:44 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * channel.c + Fixed 2.6 MODE_NOPRIVMSG bug + + * Added mkversion.sh into self configuration extraction, + now version.c.SH + +Sat Nov 10 19:10:33 1990 Armin Gruner <gruner@informatik.tu-muenchen.de> + + * Removed getlongtime() everywhere. + + * s_bsd.c + Removed some ULTRIX sidesteps. + + * s_conf.c + Changed the return values of find_kill(). + + * ircd.c + Avalon's cleanup's. + Change close() to shutdown() (restart()). + +Wed Oct 31 18:20:00 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + * 2.6: + - multichannels + - wildcard servers + - more fun stuff I don't remember anymore but which should + be in documentation... + +Sun Oct 21 18:53:02 1990 Christopher Davis (ckd at bucsd) + + * Makefile + - Added IRCDLIBS and IRCDMODE variables + +Wed Jun 20 11:53:00 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + numerous files changed and functions moved around to make + string channels work... + +Sun Jun 17 16:52:39 1990 Armin Gruner (gruner@informatik.tu-muenchen.de) + + * s_debug.c + New created file, common/debug.c has been moved to it because + now we handle also debug outputs in client code + + * s_conf.c + Added the prefix character into all reply-strings. + MSGs never appeared on client site because parse() didn't + recognize it as a prefix (numeric) message + Changed the test of time-interval, now a specified interval + that begins before midnight and ends after should also work + + * s_bsd.c + Added setdtablesize() for sequents OS Dynix, + default was 20; allows more socket connections. + +Sat May 12 22:50:13 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + * s_msg.c + Added newline removal from the end of string ctime() + returns (m_info() and m_stats()) + * s_whowas.c + Added newline removal from the end of string ctime() + returns (m_whowas()) + * s_conf.f + Added close() into init_conf() + Was obviously forgotten from there + +Thu May 10 17:17:13 1990 Jarkko Oikarinen (jto@tolsun.oulu.fi) + + * whowas.c + Fixed memcpy and bcopy problems + +Sat Jan 6 17:36:28 1990 Mike Bolotski (mikeb at coho.ee.ubc.ca) + + * date.c + + Added HPUX-specific code since it lacks the timezone() function. + + diff --git a/doc/Juped/INSTALL b/doc/Juped/INSTALL new file mode 100644 index 0000000..8ec35ff --- /dev/null +++ b/doc/Juped/INSTALL @@ -0,0 +1,1167 @@ +/************************************************************************ + * IRC - Internet Relay Chat, doc/INSTALL + * Copyright (C) 1990,1991,1992, Jeff Trim, Mike Bolotski, + * Jarkko Oikarinen and 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. + */ + + Installing IRC - The Internet Relay Chat Program + + +Overview of this document: + + 1) Installing IRC + 2) The config.h file + 3) Editing the Makefile, and compiling + 4) The ircd.conf file + 5) Mailing list + +1) So that ircd/irc will compile and work correctly with your version of + Unix, it is necessary that you run "make" first. This will run + configure which will probe your system for any peculiarities it has + and setup the Makefile and a file of default #define's ($arch/setup.h). + To change the default directory into which ircd will install using + "make install", invoke "make" using the "CONFIGARGS=--prefix=/dir" + command line option. + +2) Edit the "config.h" file and make changes to the various #DEFINE's: + + a) Define what type of UNIX your machine uses. + + Pick the machine type which best describes your machine and change + the #undef to #define (if needed). Some flavours of Unix require no + #define and in such cases all others should be #undef'd. + + b) DEBUGMODE + + Define DEBUGMODE if you want to see the ircd debugging information + as the daemon is running. Normally this function will be undefined + as ircd produces a considerable amount of output. DEBUGMODE must be + defined for either of -t or -x command line options to work. Defining + this induces a large overhead for the server as it does a large amount + of self diagnostics whilst running. + + c) SPATH, CPATH, MPATH, LPATH, PPATH, TPATH + + Define SPATH to be the directory path to ircd. This is usually + /usr/local/bin/ircd, unless you don't have installation permission + there. + + Define CPATH to be the directory path to the "ircd.conf" file. + This path is usually /usr/local/lib/ircd.conf. The format of this file + will be discussed later. + + The LPATH #define should be set to "/dev/null" unless you plan to + debug the program. Note that the logfile grows very quickly. + + Define MPATH to be the path to the 'motd' (message of the day) file + for the server. Keep in mind this is displayed whenever anyone + signs on to your server. + + The PPATH is optional, but if defined, should point to a file which + either doesn't exist (but is creatable) or a previously used PPATH + file. It is used for storing the server's PID so a ps(1) isn't + necessary. + + Define TPATH to be the directory path to the "ircd.tune" file. + This path is usually /usr/local/lib/ircd.tune. This file is used + by the server to optimize memory use. + + d) CHROOTDIR + + To use the CHROOTDIR feature, make sure it is #define'd and that + the server is being run as root. The server will chroot to the + directory name provded by IRCDDIR (in Makefile). + + e) ENABLE_SUMMON, ENABLE_USERS + + For security conscious server admins, they may wish to leave + ENABLE_USERS undefined, disabling the USERS command which can be used + to glean information the same as finger can. ENABLE_SUMMON toggles + whether the server will attempt to summon local users to irc by + writing a message similar to that from talk(1) to a user's tty. + + f) SHOW_INVISIBLE_LUSERS, NO_DEFAULT_INVISIBLE + + On large IRC networks, the number of invisible users is likely to + be large and reporting that number cause no pain. To aid and effect + this, SHOW_INVISIBLE_LUSERS is provided to cause the LUSERS command + to report the number of invisible users to all people and not just + operators. The NO_DEFAULT_INVISIBLE define is used to toggle whether + clients are automatically made invisible when they register. + + g) OPER_KILL, OPER_REHASH, OPER_RESTART, LOCAL_KILL_ONLY + + The three operator only commands, KILL, REHASH and RESTART, may all + be disabled to ensure that an operator who does not have the correct + privilidges does not have the power to cause untoward things to occur. + To further curb the actions of guest operators, LOCAL_KILL_ONLY can + be defined to only allow locally connected clients to be KILLed. + + h) ZIP_LINKS, ZIP_LEVEL + + As of the 2.9.3 version of the server, server-server connections + may be compressed using the zlib. In order to compile the server + with this feature, you MUST have the zlib package (version 1.0 or higher) + already compiled and define ZIP_LINKS in the config.h file. Compression + use for server-server connections is separately configured in the + ircd.conf file for each server-server link. ZIP_LEVEL allows you to + control the compression level that will be used. Values above 5 will + noticeably increase the CPU used by the server. + + The zlib package may be found at http://quest.jpl.nasa.gov/zlib/ + The data format used by the zlib library is described by RFCs (Request + for Comments) 1950 to 1952 in the files + ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate + format) and rfc1952.txt (gzip format). These documents are also + available in other formats from + ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + + i) SLOW_ACCEPT + + This option is defined by default and is needed on some OSes. It + creates an artificial delay in processing incoming connections. On a + given port, no more than 1 connection per 2 seconds will be processed. + + Undefining this will let the server process connections as fast as + it can which can cause problems on some OSes (such as SunOS) and be + abused (fast massive join of clonebots..), for these reasons, if you + decide to undefine SLOW_ACCEPT you MUST define CLONE_CHECK. + + j) CLONE_CHECK + + This option acts as a wrapper, by checking incoming connections + early before starting ident query. By default, the server will not + accept more than 2 connections from the same host within 10 seconds. + + k) The rest of the user changable #define's should be pretty much self + explanatory in the config.h file. It is *NOT* recommended that any + of the file undef the line with "STOP STOP" in it be changed. + +3) Editting Makefile and compilation. + + Once configure has been run, it is safe to edit the Makefile. You + will most likely need to uncomment the correct IRCDLIBS, IRCLIBS and + IRCDDIR lines. + + To now build and install the server, type "make && make install". + + If you have trouble compiling ircd, copy Makefile.in to Makefile and + edit Makefile as appropriate. + +4) The ircd.conf file. + + After installing the ircd and irc programs, edit the ircd.conf file + as per the instructions in this section and install it in the + location you specified in the config.h file. There is a sample + conf file called example.conf in the /doc directory. + + Appendix A describes the differences between IP addresses and host + names. If you are unfamiliar with this, you should probably scan + through it before proceeding. + + The ircd.conf file contains various records that specify configuration + options. The record types are as follows: + + 1. Server connections (C,c,N) + 2. Machine information (M) + 3. Client connections (I,i) + 4. Default local server (U) + 5. Operator priviliges (O) + 6. Administrative info (A) + 7. Excluded accounts (K) + 8. Excluded machines (Q) + 9. Connection Classes (Y) + 10. Leaf connections (L) + 11. Service connections (S) + 12. Port connections (P) + 13. Hub connections (H) + 14. Version limitations (V) + + + 1. SERVER CONNECTIONS: How to connect to other servers + How other servers can connect to you + + WARNING: + The hostnames used as examples are really only examples and + not meant to be used (simply because they don't work) in real life. + + Now you must decide WHICH hosts you want to connect to and WHAT ORDER you + want to connect to them in. For my example let us assume I am on the + machine "rieska.oulu.fi" and I want to connect to irc daemons on 3 other + machines: + + "garfield.mit.edu" - Tertiary Connection + "irc.nada.kth.se" - Secondary Connection + "nic.funet.fi" - Primary Connection + + And I prefer to connect to them in that order, meaning I first want to + try connecting to "nic.funet.fi", then to "irc.nada.kth.edu", and + finally to "garfield.mit.edu". So if "nic.funet.fi" is down or + unreachable, the program will try to connect to "irc.nada.kth.se". + If irc.nada.kth.se is down it will try to connect to garfield and so forth. + PLEASE limit the number of hosts you will attempt to connect to down to 3. + This is because of two main reasons: + a) to save your server from causing extra load and delays + to users + b) to save internet from extra network traffic + (remember the old rwho program with traffic problems when + the number of machines increased). + + The format for the CONNECT entry in the "ircd.conf" is: + + C:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<TARGET PORT>:<Class> +Field: 1 2 3 4 5 6 + + for example: + + C:nic.funet.fi:passwd:nic.funet.fi:6667:1 + + - or - + + C:128.214.6.100:passwd:nic.funet.fi:6667:1 + + - or - + + C:root@nic.funet.fi:passwd:nic.funet.fi:6667:1 + + + Explanation: + + Each field is separated with a ":" charcter: + + Field 1: Field 1 tells the IRC program which option is being configured. + "C" corresponds to a server Connect option. + + Field 2: Specifies the host name or IP address of the machine to connect + to. If "user@" prefixes the actual hostname or IP address + the server will require that the remote username returned by + the ident server be the same as the one given before the "@". + + Field 3: The password of the other host. A password must always be + present for the line to be recognized. + + Field 4: The full hostname of the target machine. This is the name that + the TARGET server will identify itself with when you connect + to it. If you were connecting to nic.funet.fi you would receive + "nic.funet.fi" and that is what you should place in + this field. + + Field 5: The INTERNET Port that you want to connect to on the TARGET + machine. Most of the time this will be set to "6667". + If this field is left blank, then no connections will + be attempted to the TARGET host, and your host will accept + connections FROM the TARGET host instead. + The port field can contain 2 ports, separated by a . + In this case, the first port is used when auto-connecting, + the second port is used for the UDP pings to the targer + server. + + Field 6: The class field should refer to an existing class and + determines the maximum number of simultaneous uses of the + C-line allowable through the max. links field in the Y-line. + + NEW!!! + As of the 2.9.3 version of the server, server connections can be + compressed with the zlib library. To define a compressed connection, + you must have compiled the server with ZIP_LINKS defined (cf 2.h), and + use a _lowercase_ C line. + + Some examples: + + C:nic.funet.fi::nic.funet.fi:6667:1 + + This reads: Connect to host "nic.funet.fi", with no password + and expect this server to identify itself to you as + "nic.funet.fi". Your machine will connect to this host to + PORT 6667. + + C:18.72.0.252:Jeff:garfield.mit.edu:6667:1 + + This reads: Connect to a host at address "18.72.0.252", using a + password of "Jeff". The TARGET server should identify + itself as "garfield.mit.edu". You will connect to Internet + Port 6667 on this host. + + C:irc.nada.kth.se::irc.nada.kth.se:1 + + This reads: do not attempt to connect to "irc.nada.kth.se", + but if "irc.nada.kth.se" requests a connection, + allow it to connect. + + Now back to our original problem, we wanted OUR server CONNECT to 3 + hosts, "nic.funet.fi", "irc.nada.kth.se" and "garfield.mit.edu" in + that order. So as we enter these entries into the file they must be + done in REVERSE order of how we could want to connect to them. + + Here's how it would look if we connected "nic.funet.fi" first: + + C:garfield.mit.edu::garfield.mit.edu:6667:1 + C:irc.nada.kth.se::irc.nada.kth.se:6667:1 + C:nic.funet.fi::nic.funet.fi:6667:1 + + Ircd will attempt to connect to nic.funet.fi first, then to irc.nada + and finally to garfield. + + Reciprocal entries: + + Each "C" entry requires a corresponding 'N' entry that specifies + connection priviliges to other hosts. The 'N' entry contains + the password, if any, that you require other hosts to have before + they can connect to you. These entries are of the same format as + the "C" entries. + + The format for the NOCONNECT entry in the "ircd.conf" is: + + N:<TARGET Host Addr>:<Password>:<TARGET Host NAME>:<Domain Mask>:<Class> +Field: 1 2 3 4 5 6 + + Let us assume that "garfield.mit.edu" connects to your server + and you want to place password authorization authorization on garfield. + The "N" entry would be: + + N:garfield.mit.edu:golden:garfield.mit.edu:: + + This line says: expect a connection from host "garfield.mit.edu", + and expect a login password of "golden" + and expect the host to identify itself as "garfield.mit.edu". + + N:18.72.0.252::garfield.mit.edu:: + + This line says: expect a Connection from host "18.72.0.252", and + don't expect login password. The connecting host should identify itself + as "garfield.mit.edu". + + Explanation: + + Each field is separated with a ":" charcter: + + Field 1: "N" corresponds to a server Noconnect option. + + Field 2: Specifies the host name or IP address of the machine to connect + to. If "user@" prefixes the actual hostname or IP address + the server will require that the remote username returned by + the ident server be the same as the one given before the "@". + + Field 3: The password of the other host. A password must always be + present for the line to be recognized. If CRYPT_LINK_PASSWORD + is defined in config.h, this password must be crypted. + + Field 4: The full hostname of the target machine. This is the name that + the TARGET server will identify itself with when you connect + to it. If you were connecting to nic.funet.fi you would receive + "nic.funet.fi" and that is what you should place in + this field. + + Field 5: Domain masking, see below. + + Field 6: The class field should refer to an existing class. + + Wildcards domains: + To reduce the great amount of servers in IRCnet wildcard + DOMAINS were introduced in 2.6. To explain the usage of + wildcard domains we take an example of such: + *.de - a domain name matching all machines + in Germany. + Wildcard domains are useful in that ALL SERVERS in Germany + (or any other domain area) can be shown as one to the + rest of the world. Imagine 100 servers in Germany, it + would be incredible waste of netwotk bandwidth to broadcast + all of them to all servers around the world. + + So wildcard domains are a great help, but how to use them ? + They can be defined in the N-line for a given connection, + in place of port number you write a magic number called + wildcard count. + + Wildcard count tells you HOW MANY PARTS of your server's name + should be replaced by a wildcard. For example, your server's + name is "tolsun.oulu.fi" and you want to represent it as + "*.oulu.fi" to "nic.funet.fi". In this case the wildcard count + is 1, because only one word (tolsun) is replaced by a wildcard. + If the wildcard count would be 2, then the wildcard domain would + be "*.fi". Note that with wildcard name "*.fi" you could NOT + connect to "nic.funet.fi", because that would result in a server + name COLLISION (*.fi matches nic.funet.fi). + + I advice you to not to use wildcard servers before you know + for sure how they are used, they are mostly beneficial for + backbones of countries and other large areas with common domain. + + + 2. MACHINE INFORMATION + + Introduction. + IRC needs to know a few things about your UNIX site, and the "M" command + specifies this information for IRC. The fomat of this command is: + + M:<Server NAME>:<YOUR Internet IP#>:<Geographic Location>:<Port> + Field: 1 2 3 4 5 + + Explanation: + + Field 1: "M" specifies a Machine description line + + Field 2: The name of YOUR server adding any Internet DOMAINNAME that + might also be present. If this hostname can be resolved, + the IP# found will be used to for outgoing connections. + Otherwise the default interface address of the host is used. + The server name may not be FQDN of another host. + (This means all outgoing connections will be done from the + same IP#, even if your host has several IP#). + + Field 3: If the machine on which you run the server has several IP + addresses, you can define which IP# to use for outgoing + connections. This overrides field 2. + See Also the "Port Connections" section. + + Field 4: Geographic Location is used to say WHERE YOUR SERVER is, + and gives people in other parts of the world a good + idea of where you are! If your server is in the USA, it is + usually best to say: <CITY> <STATE>, USA. Like for Denver + I say: "Denver Colorado, USA". Finnish sites (like + tolsun.oulu.fi generally say something like "Oulu, Finland". + + Field 5: Defines the port on which your server will listen for udp + pings from other servers. This should be the port were other + servers are set to autoconnect. (Also see the port field + description in connect lines). + + Example: + M:tolsun.oulu.fi::Oulu, Finland:6667: + + This line reads: My Host's name is "tolsun.oulu.fi" and + my site is located in "Oulu, Finland". + + M:orion.cair.du.edu::Denver Colorado, USA:6667: + + This line reads: My Hosts name is "orion.cair.du.edu" + and my site is located in "Denver Colorado, USA". + + 3. CLIENT CONNECTIONS - How to let clients connect to your IRCD. + + Introduction. + A client is a program that connects to the ircd daemon (ircd). + There are clients written in C, GNU Emacs Lisp and many other languages. + The "irc" program is the C client. Each person that talks via IRC is + running their own client. + + The ircd.conf files contains entries that specify which clients are + allowed to connect to your irc daemon. Obviously you want to allow your + own machine's clients to connect. You may want to allow clients from + other sites to connect. These remote clients will use your server + as a connection point. All messages sent by these clients will pass + through your machine. + + The format of this entry in the conf file is: + + I:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class> + Field:1 2 3 4 5 6 + i:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class> + + + For example, if you were installing IRC on tolsun.oulu.fi and you wanted + to allow examples sake let us assume you were making this file for + tolsun and you wanted to let your own clients to connect to your + server, you would add this entry to the file: + + I:x::tolsun.oulu.fi::1 + + If you wanted to let remote clients connect, you could add the + following lines: + + I:x::*.du.edu::1 + + Allow any clients from machines whose names end in "du.edu" to connect + with no password. + + I:128.214.6.100::nic.funet.fi::1 + + Allow clients from a machine with that IP number to connect. + Numeric match is enough, name is not required anymore. + + I:x:secret:*.tut.fi::1 + + Allow clients from machines matching *.tut.fi to connect + with the password 'secret'. + + I:*::*::1 + + Allow anyone from anywhere to connect your server. + This is the easiest way, but it also allows people to for example + dump files to your server, or connect 1000 (or how many open + sockets per process your OS allows) clients to your machine + and take your network ports. Of course the same things can be + done by simply telnetting to your machine's SMTP port (for example). + + I:x::*.fi:6667:1 + + Allow clients from machines matching *.fi to connect on the port + 6667. + + I:*@*::*@*::1 + + Allow clients from anywhere to connect your server. + If the client machine does not reply to your server ident query, + the client's username will be prefixed by ~ + + NEW!!! + As of the 2.7.2d version of the server, the server is able to accept + connections on multiple ports. I-lines are required for each P-line + to allow connections to be accepted. For unix sockets, this means + either adding I:/path/port::/path/port or some variation (wildcards + are recognised here). For internet ports, there must be an I-line + which allows the host access as normal, but the port field of the + I-line must match that of the port of the socket accepting the + connectiion. A port number of 0 is a wildcard (matches all ports). + + NEW!!! + As of the 2.9.1 version of the server, i lines are introduced. They + work the same way as I lines, but the clients matching an i line + will have a restricted connection. (no nick/mode change, no kick) + Such users will have their username prefixed by +, = or - depending + on the ident reply. + + 4. DEFAULT HOSTS (for local clients) *obsoleted* + + Introduction. + This defines the default connection for the irc client. If you are + running an ircd server on the same machine, you will want to define + this command to connect to your own host. If your site is not running + a server then this command should contain the TARGET host's connection + information and password (if any). The format for this command is: + + U:<TARGET Host addr>:<Password>:<TARGET Host NAME>:<Internet Port> + Field: 1 2 3 4 5 + + + For example: + + U:tolsun.oulu.fi::tolsun.oulu.fi:6667 + U:128.214.5.6::tolsun.oulu.fi:6667 + U:tolsun.oulu.fi::tolsun.oulu.fi + + If the port number is omitted, irc will default to using 6667. + + 5. OPERATOR Privileges: How to become the IRC administrator on your site + + Introduction. + To become an IRC Administrator, IRC must know who is authorized to + become an operator and what their "Nickname" and "Password" is. To add + this information, EDIT your "ircd.conf" file and add the following command + line to it: + + O:<TARGET Host NAME>:<password>:<nickname>:<port>:<class> + Field: 1 2 3 4 5 6 + + Explanation: + + Field 1: Speficies Operator record. If you use capital letter ('O') + in it, it specifies a global operator. Small letter ('o') + specifies a local operator. Local operator has basically the + same rights except global operator with some restrictions. + + Field 2: Tells IRC which host you have the privileges FROM. This + means that you should be logged into this host when you + ask for the priviliges. If you specify "tolsun.oulu.fi" + then IRC will expect your CLIENT to be connected at + "tolsun.oulu.fi" - when you ask for OPERATOR privileges + from "tolsun.oulu.fi". You cannot be logged in at any + other host and be able to use your OPERATOR privileges + at tolsun, only when you are connected at TOLSUN will this + work - this is a safeguard against unauthorized sites. + + + Field 3: If your AUTHORIZATION Password - this is the password that + let's IRC know you are who you say you are! Never tell anyone + your password and always keep the "ircd.conf" file protected + from all of the other users. + + Field 4: The Nickname you usually go by - but you can make this what + you want. It is better to make this a NICKNAME that no one + else knows, but anything will do. I usually use my own + loginname. + + Field 5: Unused. + + Field 6: The class field should refer to an existing class (preferably + having a lower number than that for the relevant I-line) and + determines the maximum number of simultaneous uses of the + O-line allowable through the max. links field in the Y-line. + + Example: + O:orion.cair.du.edu:pyunxc:Jeff::1 + + There is an OPERATOR at "orion.cair.du.edu" that can get + Operator priviliges if he specifies a password of "pyunxc" + and uses a NICKNAME of "Jeff". + + + + 6. ADMINISTRATIVE INFORMATION + + Introduction. + The "A" command is used for administrative information about a site. + The e-mail address of the person running the server should be included + here in case problems arise. + + + A:<Your Name/Location>:<Your Electronic Mailing Addr>:<other>:: + Field: 1 2 3 4 + + Explanation: + + Field 1: "A" specifies an Admin record. + + + Field 2: Use this field to say tell your FULL NAME and where in the + world your machine is. Be sure to add your City, + State/Province and Country. + + + Field 3: Use this field to specify your Electronic Mailing Address + preferably your Internet Mailing Address. If you have + a UUCP or ARAPnet address - please add that as well. Be + sure to add any extra DOMAIN information that is needed, + for example "mail jtrim@orion" probably won't work as a + mail address to me if you happen to be in Alaska. But + "mail jtrim@orion.cair.du.edu" would work because you + know that "orion" is part of the DOMAIN "cair.du.edu". + So be sure to add your DOMAINNAMES to your mailing addresses. + + Field 4: Is really an OTHER field - you can add what you want here, + + + Examples (the line is just one line in the confuration file, here it + is cut into two lines to make it clearer to read): + +A:Jeff Trim - Denver Colorado, USA:INET jtrim@orion.cair.du.edu UUCP {hao, +isis}!udenva!jtrim:Terve! Heippa! Have you said hello in Finnish today?;):: + + Would look like this when printed out with the /admin command: + + Jeff Trim - Denver Colorado, USA + INET jtrim@orion.cair.du.edu UUCP {hao,isis}!udenva!jtrim + Terve! Hei! Heippa! Have you said hello in Finnish today? ;) + + + Note that the A record cannot be split across multiple lines; it will + typically be longer than 80 characters and will therefore wrap around + the screen. + + + 7. REMOVING A USER FROM IRC Remove an errant user from IRC on your site. + + Introduction. + Obviously it is hoped that you wouldn't have to use this command. + Unfortunately sometimes a user can become unmanageable and this is your + only recourse - the KILL USER command. THIS COMMAND ONLY AFFECTS YOUR + SERVER - If this user can connect to another SERVER somewhere else in + the IRC-Network then you would have to talk to the administrator on that + site to disable his access from that IRCD Server as well. + + The format of this command is: + + K:<Host Name>:<time interval(s)|comment>:<User>:<port>: + Field: 1 2 3 4 5 + + Explanation: + + Field 1: "K" tells the IRCD that you are making a KILL USER command + entry. + + Field 2: In this field you specify the Hostname that the user is + connecting from. If you wanted to REMOVE connects + to IRC from "orion.cair.du.edu" then you would want to enter + "orion.cair.du.edu". If you want to REMOVE ALL HOSTS + access you can use '*' (Wild Card notation) and no matter + what host the USERNAME (specified in Field 4) connects from + s/he will be denied access. Removing all hosts isn't + very smart thing to do though, why would you run an ircd + if you allow nobody to connect to it anyways ? + + Field 3: Either leave this field empty or put a comment, then the line + is active continuously for the specified user/host machine. + You may also specify intervals during the line should be + active, see examples above. + + Field 4: The USERNAME of the user you want removed from IRC. For + example 'root'. + + Field 5: The port on which the Kill line will be effective. + 0 means all ports. + + + Some Examples: + K:orion.cair.du.edu::jtrim:0: + + If user 'jtrim' connects to IRC from host "orion.cair.du.edu" + then IMMEDIATELY REMOVE HIM from my IRCD. + + K:*.cair.du.edu::root:0: + + If user 'root' connects to IRC from any host that has the + suffix "cair.du.edu" - then IMMEDIATELY REMOVE THEM from + my IRCD. + + K:*::vijay:0: + + This line reads "I don't care WHAT HOST user 'vijay' is on, + I will NEVER allow username 'vijay' to login to my IRCD. + + K:*.oulu.fi:0800-1200,1400-1900:*:0: + + This disallows all users from hosts with enddomain 'oulu.fi' + access to your server between 8 and 12am, 2 and 7pm. + Users get kicked off if they're already signed on when the + line becomes active (they'll get a warning 5 minutes ago). + + 8. Disallowing SERVERS in your irc net. + + Introduction. + In some cases people run into difficulties in net administration. + For one reason or another you do not want a certain server to be + in your net (for example because of the security holes it opens + for every server if it's not secured carefully). In that case + you should use Q-lines in your server. When you specify a server + name in Q-line, everytime some server link tries to introduce you + a server (remember, all server names are broadcast around the net), + that name is checked if it matches the Q-lines in your server. + If it matches, then your server disconnects the link. Note that + just placing Q-lines to your server probably results in your server + being left alone, unless other servers have agreed to have the + same Q-line in their ircd configuration files as well. + + Example: + Q::of the security holes:foo.bar.baz:: + + This command excludes a server named "foo.bar.baz", the reason + is given to be security holes (you should give a reason, it is + polite). The first field is unused, so leave it empty. + + 9. Connection Classes. + + Introduction. + To enable more efficient use of MAXIMUM_LINKS, connection classes + were implemented. To give a connection a class, add another field + (a sixth) to the C/N lines for a particular server. + Each line for a server should have the same number as the sixth + field. If it is absent, the server deaults it to 0, using the + defaults from the config.h file. To define a connection class, + you need to include a Y: line in the ircd.conf file. This enables + you to define the ping frequency, connection frequency and maximum + number of links that class should have. Currently, the Y: line MUST + appear in the ircd.conf file BEFORE it is used in any other way. + + The format for the line is: + + Y:<CLASS>:<PING FREQUENCY>:<CONNECT FREQ|MAX IP>:<MAX LINKS>:<SENDQ> +Field: 1 2 3 4 5 6 + + Field 2: This is the class number which gains the following attributes + and should match that which is on the end of the C/N/I/O line. + + Field 3: This field defines how long the server will let the connection + remain "silent" before sending a PING message to make sure it + is still alive. Unless you are sure of what you are doing, + use the default value which is in your config.h file. + + Field 4: This field has a different meaning depending on the use of the + Y line: + For servers: By changing this number, you change how often your + server checks to see if it can connect to this + server. If you want to check very occasionally, use + a large value, but if it is an important connection, + you might want a smaller value so that you connect + to it as soon as possible. + For clients: Positive value: defines the maximum number of + clients from the same host (IP) + will be allowed. + Negative value: defines the maximum number of + clients from the same user@host (IP) + will be allowed. Read note below. + + Field 5: This field defines the maximum number of links this class + will allow from automatic connections (C lines). Using /CONNECT + overrides this feature. Also defines the maximum number of + users in this class (I/O lines). + + Field 6: This field defines the 'sendq' value for this class. If this + field is not present, the default (from config.h) is assigned. + + NOTE: leaving any of the fields out means their value is 0 (ZERO)!! + + NOTE: If you plan to use the user@host limit, please read the following + very carefully. The `user' value is the ident reply for the + connection. If no reply was given then it defaults to "unknown" + and thus the effective limit will be per host, not per user@host. + Also, some ident servers return encrypted data which changes for + every connection making the limit void. + + Example: + + Y:23:120:300:5: + + define class 23 to allow 5 auto-connections, which are checked every + 300 seconds. The connection is allowed to remain silent for 120 + seconds before a PING is sent. NOTE: fields 3 & 4 are in seconds. + + You may also give I lines a class (again the sixth field to define + which class). This is only usefull (currently) for redefining the + ping frequency. It can also be useful as a diagnostic to see how + much each I line is used when combined with the TRACE output. + + Another feature of connection class is the ability to do automatic + routing by using the class as a 'priority'. If you are connected + to a server which has a class lower than one of the servers that is + 'behind' it, the server will disconnect the lower class one and + schedule a 'new' connection for the higher class server. + + 10. Leaf Connections. + + Introduction. + To stop servers which should only act as leaves from hubs becoming + hubs accidently, the L line was introduced so that hubs can be aware + of which servers should and shouldnt be treated as leaves. A leaf + server is supposed to remain a node for the entirity of its life + whilst connected to the IRC server network. It is quite easy, however + for a leaf server to be incorrectly setup and create problems by + becoming a node of 2 or more servers, ending its life as a leaf. The + L line enables the administrator of an IRC 'Hub server' to 'stop' a + server which is meant to act as a leaf trying to make itself a hub. + If, for example, the leaf server connects to another server which doesnt + have an L-line for it, the one which does will drop the connection, once + again making the server a leaf. + + L:<SERVER MASK>:*:<SERVER NAME>:<MAX DEPTH>: +Field: 1 2 3 4 5 + + Field 2: mask of which servers the leaf-like attributes are used on + when the server receives SERVER messages. The wildcards * + and ? may be used within this field for matching purposes. + If this field is empty, it acts the same as if it were a + single * (ie matches everything). + + Field 4: the name of the server connected to you that for which you + want to enforce leaf-like attributes upon. + + Field 5: maximum depth allowed on that leaf and if not specified, + a value of 1 is assumed. The depth is checked each time a + SERVER message is received by the server, the hops to the + server being the field checked against this max depth and + if greater, the connection to the server that made its leaf + too deep has its connection dropped. For the L-line to come + into effect, both fields, 2 and 4, must match up with the new + server being introduced and the server which is responsible + for introducing this new server. + + 11. Service Connections (Not Fully Implemented Yet) + + Introduction. + The Service is a special kind of IRC client. It does not have the full + abilities of a normal user but can behave in a more active manner than + a normal client. The following line can be added to your ircd.conf file + to enable a service: + + S:<TARGET Host Mask>:<password>:<service_name>:<service type>:<class> + Field: 1 2 3 4 5 6 + + Explanation: + + Field 2: The host mask should be set to match the hosts(s) from which + the service will be connecting from. This may be either an + IP# or full name (prefered). + + Field 3: This is the password which must be passed in the SERVICE command. + + Field 4: The name used by the service. Services don't have nicknames, but + a static name defined by the S line. + + Field 5: The type of service. It defines the priviledges given to the + service. Be very careful in the types you allow. + The types can be found in include/service.h + + Field 6: The class field should refer to an existing class. + + To connect a service to your server, you must first create an S-line + entry in your ircd.conf file and get your server to read this in (ie + rehash or reboot). Once your server has updated itself, you can then + attempt to register your connection as a service. + Registering as a service is done by sending a SERVICE command to the + server: + + SERVICE servicename servername distribution servicetype 0 :Information + + A successfull registering of a service at the server will result in + a RPL_YOURESERVICE (383) being sent back to you. Any other reply as + a result of sending service indicates an error has occured. + + A service is not a very useful sort of client, it cannot join channels + or issue certain commands although most are available to it. Services + are rejected upon sending an unknown or unallowed command. Services + however, are not affected by flood control and can be granted special + priviledges. It is therefore wise to oversee the use of S-lines with + much care. + + Services can be listed using the SERVLIST command, and can be sent + messages using the SQUERY command. + + 12. Port Connections + + Introduction. + The port line adds flexibility to the server's ability to accept + connections. By use of this line in the ircd.conf file, it is easy + to setup both Unix Domain ports for the server to accept connections + on as well as extra internet ports. + + P:<Internet IP#>:<*>:<Internet IP Mask>:<PORT>: +Field: 1 2 3 4 5 + +or + + P:<Directory>:<*>:<*>:<PORT>: +Field: 1 2 3 4 5 + + Explanation: + Internet Ports + Field 2 + If the host on which the server runs has several IP addresses, you can + define for which IP address connections will be accepted. If no + is defined here, server will bind to all interfaces (INADDR_ANY). + See also MACHINE CONFIGURATION section to properly configure outgoing + connections. + + P:192.168.1.194:::6664: + + Field 4 + The internet IP# mask defines where connections may come from and + be accepted. The IP mask uses either *'s or 0's as wildcards. The + following two lines are the same: + + P:::128.2.*:6664: + P:::128.2.0.0:6664: + + The incoming isn't matched against the mask, rather the ip# string + is decoded and compared segment by segment. Thus + P:128.2*.1.2:::6664: + will not match 128.20.1.2. + + Field 5 + The port number field tells the server which port number it should + listen on for incoming connections. + + Unix Socket Ports. + Field 1 + The path set in field 1 should be the directory name in which to + create the unix socket for later listening to. The server will + attempt to create the directory before creating the unix socket. + + Field 5 + The port field when used in combination with a pathname in a P-line + is the filename created in the directory set in Field 1. + + Example: + P:/tmp/.ircd:::6667: + + Creates a unix socket in the /tmp/.ircd directory called "6667". + The unix socket (file) must be a numerical. + + NOTE: You need at least one P line. + + 13. Hub Connections + + Introduction. + In direct contrast to L-lines, the server also implements H-lines to + determine which servers may act as a hub and what they may 'hub for'. + If a server is only going to supply its own name (ie act as a solitary + leaf) then no H-line is required for, else a H-line must be added as + follows: + + H:<SERVER MASK>:*:<SERVER NAME>:: +Field: 1 2 3 4 + + Explanation: + Field 2 + All servers that are allowed via this H-line must match the mask + given in this field. + + Field 4 + This field is used to match exactly against a server name, wildcards + being treated as literal characters. + + Examples: + + H:*.edu::*.bu.edu:: + + Allows a server named "*.bu.edu" to introduce only servers that + match the "*.edu" name mask. + + H:*::eff.org:: + + Allow "eff.org" to introduce (and act as a hub for) any server. + + Note: It is possible to have and use multiple H-lines (or L-lines) for + the one server. eg: + + H:*.edu:*:*.bu.edu:: + H:*.au:*:*.bu.edu:: + + is allowed as is + + L:*.edu:*:*.au:: + L:*.com:*:*.au:: + + 14. Version limitations + + Introduction. + In direct contrast to L-lines, the server also implements H-lines to + determine which servers may act as a hub and what they may 'hub for'. + If a server is only going to supply its own name (ie act as a solitary + leaf) then no H-line is required for, else a H-line must be added as + follows: + + V:<VERSION MASK>:<FLAGS>:<SERVER NAME>:: +Field: 1 2 3 4 + + Explanation: + Field 2 + Server is not allowed to connect if its version string matches the mask + given in this field. + + Field 3 + This field should contained flags as defined in ircd/s_debug.c + This flags show up in RPL_VERSION. + If any of the flags present in this field are found in the RPL_VERSION + of a server, this server will be denied connection. + This must be used with care. + + Field 4: + This field is used to match server names. The V line will be used + for servers matching the mask given in this field. + + Examples: + + V:020901*::*:: + + Disallows any server which version is 2.9.1* to connect. + + V:020901*:D:*:: + + Disallows any server which version is 2.9.1* or which has been + compiled with DEBUGMODE defined to connect. + + Note: It is possible to have and use multiple V-lines for the one server + mask. + + H:020901:*:*:: + V:020902:*:*:: + + is allowed. + + +Appendix A: Difference between IP addresses and hostnames + + + There are 2 different types of INTERNET addresses, NAME addresses and + NUMERIC addresses. NAME addresses look like ENGLISH words (and indeed + they are ENGLISH words that refer to a given host). A NAME address looks + like "tolsun.oulu.fi" - and that particular address refers to the machine + named TOLSUN in Finland. It is a UNIQUE address because no other machine + in the world has its NAME address the same as "tolsun.oulu.fi". Anytime + you say "telnet tolsun.oulu.fi" - you would always connect to TOLSUN in + Finland. NUMERIC addresses refer to those addresses that are made up of + NUMBERS for example "128.214.5.6" is the NUMERIC address for TOLSUN. This + address is also UNIQUE in that no other machine in the world will be use + those NUMERIC numbers. The NUMERIC address is usually more reliable than + the NAME address because not all sites can recognize and translate the + NAME address into it's numeric counterpart. NUMERIC always seems to work + best, but use a NAME address when you can because it is easier to tell + what host you are connected to. + + + Every Unix machine has a file called "/etc/hosts" on it. This file + contains NAME and NUMERIC addresses. When you supply IRC with a NAME + address it will at first try to find it in /etc/hosts, and then (if it's + really smart), use the local Domain Name Server (DNS) to find the NUMERIC + address for the host you want to connect to. Thus if you plan to use NAME + addresses keep in mind that on SOME sites the entry for the TARGET machine + must be found in /etc/hosts or the NAME address will fail. A typical + entry in /etc/hosts looks like this: + + 130.253.1.15 orion.cair.du.edu orion.du.edu orion # BSD 4.3 + + This particular example is the Host ORION at the University of Denver. + Notice that on the far left is the NUMERIC Address for orion. The + next few ENGLISH words are the NAME addresses that can be used for orion, + "orion.cair.du.edu", "orion.du.edu", "orion". ALL of these NAME addresses + will return the NUMERIC address "130.253.1.15" which IRC will use to + connect to the TARGET UNIX. (when I say TARGET UNIX I am refering to the + UNIX you want to connect to for IRC). Any futher questions about + /etc/hosts should be directed to "man hosts". + + +Appendix B: Enabling Summon Messages + + +-----------------------------------------------------------------------+ + | E N A B L I N G / S U M M O N M E S S A G E S | + +-----------------------------------------------------------------------+ + + *NOTE* You must have ROOT or special access to the GROUP tty ('/dev') + to do this. If you want to allow users around the world to summon + users at your site to irc, then you should make sure that summon works. + + The "IRCD" program needs access to the GROUP of '/dev'. This + directory is where user TTY's are stored (as UNIX treats each Terminal + as a FILE!) IRCD needs GROUP ACCESS to /dev so that users can be + SUMMONED to the program by others users that are *in* the program. + This allows people from other Universities around the world to SUMMON + your users to IRC so that they can chat with them. Berkeley, SUN, HP-UX + and most of the newer versions of UNIX check to see if a USER is + accepting MESSAGES via the GROUP access rights on their TTY listing + in the /dev directory. For example an entry in '/dev' looks like this: + + (Unix Path on BSD 4.3 UNIX is: /dev/ttyp0) + + crw------- 1 jtrim 20, 0 Apr 29 10:35 ttyp0 + + You will note that 'jtrim' OWNS this terminal and can READ/WRITE to this + terminal as well (which makes sense because I am ENTERING DATA and + RECEIVEING DATA back from the UNIX). I logged into this particular + UNIX on "April 29th" at "10:35am" and my TTY is "ttyp0". But further + of *note* is that I do not have my MESSAGES ON! (mesg n) -- This is + how my terminal would look with MESSAGES ON (mesg y): + + crw--w---- 1 jtrim 20, 0 Apr 29 10:35 ttyp0 + + With my MESSAGES ON (mesg y) I can receive TALK(1) requests, use the + UNIX WRITE(1) command and other commands that allow users to talk + to one another. In IRC this would also allow me to get IRC /SUMMON + messages. To set up the "IRCD" program to work with /SUMMON type + the following: (using ROOT or an account that has access to '/dev'). + + % chgrp tty ircd + % chmod 6111 ircd + + The above commands read: "Give IRCD access to GROUP tty (which is /dev) + and then when ANYONE runs the IRCD allow SETUID and SETGID priviliges + so that they can use the /SUMMON command. + + +6) ircd-users + +A mailing list is dedicated to the people using ircd. If you have trouble +running ircd, or wish to discuss the future, you can subscribe by sending +an email to majordomo@stealth.net, with "subscribe ircd-users" in the body. diff --git a/doc/Juped/US-Admin/Networking b/doc/Juped/US-Admin/Networking new file mode 100644 index 0000000..e8dc186 --- /dev/null +++ b/doc/Juped/US-Admin/Networking @@ -0,0 +1,156 @@ +/************************************************************************ + * IRC - Internet Relay Chat, doc/NETWORKING + * Copyright (C) 1994, Helen Rose <hrose@kei.com> + * + * 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. + */ + + Author: Helen Rose + hrose@kei.com + Date: 3 March, 1994 + +*** Please read this before doing any connecting or writing to ask for +connections. The information contained in this section is crucial to the +way IRC is run. + +Note that any old documentation referring to ANet vs EFnet is out of date +and no longer applies. ANet died so long ago that nobody can remember +*when* it died. + + +To qualify for a link on the irc network, several criteria must be +met. These criteria include (but are not limited to): + +* A well established local irc userbase. A total of 100-150 local irc + users. An average of 15-20 irc users over a 24 hour period is also + acceptable. Note, these user counts are *unique, local* users. So + one person running fifteen clients doesn't count, and one local + person plus fifteen offsite people doesn't count. These are not + arbitrary numbers, it takes at least this many users to equate the + traffic of adding another server to the irc network. + +* A userbase that uses irc *all the time* (15 users on at once but + just for a 3 hour period per day is not sufficient). + +* A good, fast, internet link. Absolutely *NO* SLIP lines. 56k lines + are marginal, they usually cause more trouble than they are worth, + so we recommend a T1 or better. + +It is well established that having a local irc server does not attract +local irc users. Often, your best bet is to set up a local client that is +accessible by everyone at your site, connect it to a nearby offsite +server, and then see if the usage level goes up. (See appendix for list of +open-client servers). + +To see how many users you have, on irc do /m x@monitor.us show site.name +where site.name is your two-part domain name (eg "kei.com" or "bu.edu" or +"mit.edu"). monitor will tell you how many users you have. Once this +number gets over 125 or so, put the level it has reached in your note to +operlist-request@kei.com. + +If you are in the United States and need a link, please mail to +"operlist-request@kei.com" supplying the information listed below. + +(1) Find out if your system has /etc/ping (sometimes /usr/etc/ping) and + ping the following hosts: + + server/machine name IP address Geographical Location + csa.bu.edu 129.197.10.3 Boston, MA + irc-2.mit.edu 18.180.0.2 Cambridge, MA + polaris.ctr.columbia.edu 128.59.68.10 New York, NY + poe.acc.virginia.edu 128.143.83.132 Charlottesville, VA + irc.iastate.edu 129.186.150.1 Ames, IA + dewey.cc.utexas.edu 128.83.135.3 Austin, TX + irc.netsys.com 198.175.9.8 Palo Alto, CA + w6yx.stanford.edu 36.55.0.50 Stanford, CA + goren.u.washington.edu 140.142.63.1 Seattle, WA + +These are results of the typical /etc/ping command: + +(note that the machine I am running this from runs SunOS so I have to use +ping -s ): + +3:59pm hrose@csa : ~ % ping -s polaris.ctr.columbia.edu +PING polaris.ctr.columbia.edu: 56 data bytes +64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=0. time=137. ms +64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=1. time=163. ms +64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=2. time=110. ms +64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=3. time=111. ms +64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=4. time=78. ms +64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=5. time=82. ms +64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=7. time=83. ms +64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=8. time=91. ms +64 bytes from polaris.ctr.columbia.edu (128.59.68.10): icmp_seq=9. time=159. ms +[...] +^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^ ^^ ^^^^^^^ +Size of packet hostname IP address packet number trip time + + +----polaris.ctr.columbia.edu PING Statistics---- +25 packets transmitted, 25 packets received, 0% packet loss +round-trip (ms) min/avg/max = 78/136/327 + + +When you send pings to operlist-request, please only send the results +(the above three lines)--we *don't* need each packet's time. + + +Guidelines: + +Avg Time Connection is +======== ============= +0-20ms Optimal +20-40ms Excellent +40-70ms Very Good +70-90ms Average +90-110ms Acceptable +110ms-150ms Below Average +150ms-200ms Bad +200ms-300ms You're on a very slow link and it is unlikely you will be + able to support a server successfully. + + +** *** WHERE TO FIND HELP!!! *** +** +** If you have any other questions about connecting to an irc server, please +** mail to operlist-request@kei.com. If you have problems mailing there, +** try mailing hrose@kei.com. +** +** *** WHERE TO FIND HELP!!! *** + +Appendix +======== + +Open client servers. + +USA: + csa.bu.edu + irc.colorado.edu + irc.uiuc.edu + +Canada: + ug.cs.dal.ca + +Europe: + irc.funet.fi + cismhp.univ-lyon1.fr + disuns2.epfl.ch + irc.nada.kth.se + sokrates.informatik.uni-kl.de + bim.itc.univie.ac.at + +Australia: + jello.qabc.uq.oz.au + diff --git a/doc/LICENSE b/doc/LICENSE new file mode 100644 index 0000000..9a17037 --- /dev/null +++ b/doc/LICENSE @@ -0,0 +1,249 @@ + + GNU GENERAL PUBLIC LICENSE + Version 1, February 1989 + + Copyright (C) 1989 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The license agreements of most software companies try to keep users +at the mercy of those companies. By contrast, our General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. The +General Public License applies to the Free Software Foundation's +software and to any other program whose authors commit to using it. +You can use it for your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Specifically, the General Public License is designed to make +sure that you have the freedom to give away or sell copies of free +software, that you receive source code or can get it if you want it, +that you can change the software or use pieces of it in new free +programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of a such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must tell them their rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any program or other work which +contains a notice placed by the copyright holder saying it may be +distributed under the terms of this General Public License. The +"Program", below, refers to any such program or work, and a "work based +on the Program" means either the Program or any work containing the +Program or a portion of it, either verbatim or with modifications. Each +licensee is addressed as "you". + + 1. You may copy and distribute verbatim copies of the Program's source +code as you receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice and +disclaimer of warranty; keep intact all the notices that refer to this +General Public License and to the absence of any warranty; and give any +other recipients of the Program a copy of this General Public License +along with the Program. You may charge a fee for the physical act of +transferring a copy. + + 2. You may modify your copy or copies of the Program or any portion of +it, and copy and distribute such modifications under the terms of Paragraph +1 above, provided that you also do the following: + + a) cause the modified files to carry prominent notices stating that + you changed the files and the date of any change; and + + b) cause the whole of any work that you distribute or publish, that + in whole or in part contains the Program or any part thereof, either + with or without modifications, to be licensed at no charge to all + third parties under the terms of this General Public License (except + that you may choose to grant warranty protection to some or all + third parties, at your option). + + c) If the modified program normally reads commands interactively when + run, you must cause it, when started running for such interactive use + in the simplest and most usual way, to print or display an + announcement including an appropriate copyright notice and a notice + that there is no warranty (or else, saying that you provide a + warranty) and that users may redistribute the program under these + conditions, and telling the user how to view a copy of this General + Public License. + + d) You may charge a fee for the physical act of transferring a + copy, and you may at your option offer warranty protection in + exchange for a fee. + +Mere aggregation of another independent work with the Program (or its +derivative) on a volume of a storage or distribution medium does not bring +the other work under the scope of these terms. + + 3. You may copy and distribute the Program (or a portion or derivative of +it, under Paragraph 2) in object code or executable form under the terms of +Paragraphs 1 and 2 above provided that you also do one of the following: + + a) accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of + Paragraphs 1 and 2 above; or, + + b) accompany it with a written offer, valid for at least three + years, to give any third party free (except for a nominal charge + for the cost of distribution) a complete machine-readable copy of the + corresponding source code, to be distributed under the terms of + Paragraphs 1 and 2 above; or, + + c) accompany it with the information you received as to where the + corresponding source code may be obtained. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form alone.) + +Source code for a work means the preferred form of the work for making +modifications to it. For an executable file, complete source code means +all the source code for all modules it contains; but, as a special +exception, it need not include source code for modules which are standard +libraries that accompany the operating system on which the executable +file runs, or for standard header files or definitions files that +accompany that operating system. + + 4. You may not copy, modify, sublicense, distribute or transfer the +Program except as expressly provided under this General Public License. +Any attempt otherwise to copy, modify, sublicense, distribute or transfer +the Program is void, and will automatically terminate your rights to use +the Program under this License. However, parties who have received +copies, or rights to use copies, from you under this General Public +License will not have their licenses terminated so long as such parties +remain in full compliance. + + 5. By copying, distributing or modifying the Program (or any work based +on the Program) you indicate your acceptance of this license to do so, +and all its terms and conditions. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the original +licensor to copy, distribute or modify the Program subject to these +terms and conditions. You may not impose any further restrictions on the +recipients' exercise of the rights granted herein. + + 7. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of the license which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +the license, you may choose any version ever published by the Free Software +Foundation. + + 8. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to humanity, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + + To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively convey +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + 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. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19xx name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the +appropriate parts of the General Public License. Of course, the +commands you use may be called something other than `show w' and `show +c'; they could even be mouse-clicks or menu items--whatever suits your +program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + program `Gnomovision' (a program to direct compilers to make passes + at assemblers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 0000000..20b82e4 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,39 @@ +#************************************************************************ +#* IRC - Internet Relay Chat, 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. +#* +#* $Id: Makefile,v 1.3 1997/08/08 14:44:13 kalt Exp $ +#* +#*/ + +MANDIR=/usr/local/man + +all: + +sgml: service doc + +doc: INSTALL.sgml + sgml2txt INSTALL.sgml + sgml2info INSTALL.sgml + +service: SERVICE.sgml + sgml2txt SERVICE.sgml + +install: all + -${INSTALL} -c -m 644 ircd.8 ${MANDIR}/man8 + -${INSTALL} -c -m 644 irc.1 ${MANDIR}/man1 + diff --git a/doc/Nets/Europe/CoordEBIC b/doc/Nets/Europe/CoordEBIC new file mode 100644 index 0000000..80ee042 --- /dev/null +++ b/doc/Nets/Europe/CoordEBIC @@ -0,0 +1,86 @@ +############################################################################ +list updated the 8.11.1996 +############################################################################ + + If you like in future to establish a link inside the EBIC area, + please contact the coordinator of the affected toplevel domain. + This coordinator will discuss the link with affected local server + admins and inform other EBIC members about new links. Also a good + idea is to join #EU-Opers and discuss the new link there. + +############################################################################ + These toplevel domains are currently participating EBIC: +############################################################################ + + at be ch zc de dk fi fr hr hu is it nl no pl ru(/su) se si sk uk + +############################################################################ + The following national coordinators have been choosen for '95: +############################################################################ + +*.at EASINET, ACONET + 1. Fingwe, Bernhard Lorenz <Bernhard.Lorenz@wu-wien.ac.at> + +*.be BELNET + 1. Frans Francis Vanhemmens <vanhemme@ulb.ac.be> + 2. mro Marc Roger <Marc.Roger@belnet.be> + +*.ch SWITCH, EUNET/CH + 1. ksa Karim Saouli <Karim.Saouli@span.ch> + +*.cz CESNET, PASNET + 1. Kratz Tomas Kraus <xkraus@sun.felk.cvut.cz> + +*.de WIN, BelWue <irc-oper@leo.org> + 1. YeggMan Volker Paulsen <Volker.Paulsen@gmd.de> + 2. Haegar Thomas Thissen <tici@uni-paderborn.de> + +*.dk DENET, DKNET + 1. karthy Karsten Thygesen <karthy@sunsite.auc.dk> + +*.fi FUNET + 1. Vesa Vesa Ruokonen <Vesa.Ruokonen@lut.fi> + +*.fr EASINET/ROCAD, RENATER <irc-fr@ifens01.insa-lyon.fr> + 1. Nono Arnaud Girsch <Arnaud.Girsch@insa-lyon.fr> + 2. Dumpty Marie-Laure Bruneton <brunetom@poly.polytechnique.fr> + +*.hr CARNET + 1. Mozz Mario Mikocevic <mozgy@smile.srce.hr> + +*.hu HUNGARNET + 1. keksz Revoly Andras <cakes@sch.bme.hu> + +*.is ISnet + 1. ra Richard Allen <ra@rhi.hi.is> + +*.it CILEA <ebic-it@ccii.unipi.it> + 1. Francesco Francesco Messineo <frank@nowhere.ccii.unipi.it> + 2. Coccy Cosimo Riglietti <pez0004@cdc715_3.cdc.polimi.it> + +*.nl SURFNET/NLNET + 1. cor Cor Bosman <cor@xs4all.nl> + 2. Steven Steven Hessing <steven@nijenrode.nl> + +*.no UNINETT + 1. Veggen Vegard Engen <Vegard.Engen@uninett.no> + +*.pl POLIP + 1. Krzysio Krzysztof Mlynarski <krzysio@hydra.mimuw.edu.pl> + +*.ru (*.su) DEMOS + 1. mishania Mikhail Alekseevitch Sokolov <mishania@demos.net> + +*.se SUNET + 1. Ace95 Adam Rappner <ace@LoneStar.rsn.hk-r.se> + +*.sk UAKOM + 1. Koleso Tibor Weis <tibor@uvt.tuzvo.sk> + +*.si + 1. Iztok Iztok Umek <Iztok.Umek@uni-lj.si> + +*.uk JANET, JIPS + 1. jim_bob James R. Grinter <jrg@doc.ic.ac.uk> + + diff --git a/doc/Nets/Europe/IRCNO b/doc/Nets/Europe/IRCNO new file mode 100644 index 0000000..6fafd8d --- /dev/null +++ b/doc/Nets/Europe/IRCNO @@ -0,0 +1,171 @@ + European Board of IRC Coordinators - Norway + +Email: op-no@nvg.unit.no +Versjon: 1.01-001 +Dokument: IRCNO-ORRO 06.07.93 - 03:51 +File: flode.nvg.unit.no:/pub/irc/ircno/english + +-------------------------------------------------------------------------------- + + IRCNO in English. + +IRCNO is the Norwegian name for EBIC - Norway. + +Introduction +~~~~~~~~~~~ +The purpose of IRCNO is to make IRC in Norway as effective as +possible. To achieve this, it has to seperate components, an +administrative and a techincal. + +The administrative component enforces compliance with the IRC rules in +Norway. The purpose of the rules is not to make operators net-police, +but action must nonetheless be taken when rules are not complied with. +Furthermore, we create national statistics on servers and users +connection time. (This info is however only available to the operators). +We also document IRC in Norway, and keep information files updated. +Finally, we give heavy user-support. All documentation, information +files, and user-support files are in the Norwegian language. +The technical component consist mainly of ensuring the proper and +reliable functioning of Norwegian servers and links, so that IRC in +Norway is compatible with the rest of the EBIC IRC Net. + +IRCNO also has its own email adress for any inquiries: op-no@nvg.unit.no + +IRCNO has official support from the Norwegian academic network provider +- UNINETT. + + +IRCNO tasks +~~~~~~~~~~ +Here is a list that defines IRCNO's tasks. + +1) Take care of the Norwegian IRC servers. +2) Enforce the rules for IRC use in Norway. +3) Be responsible toward UNINETT. +4) Make statistics. +5) Document IRC in Norway. +6) User support. + + +Rules of IRC use in Norway +~~~~~~~~~~~~~~~~~~~~~~~~~ +We have 3 kinds of rules, user-bot, operator and server-admin. +Here is a short translation of the rules + +USER-RULES - The following is not allowed: + 1) Fake userids, or trying to hide the real user-id. + 2) Being intentionally offensive to another user. + 3) Dumping a lot of text to a public channel. + 4) Constant beeping on a channel. + 5) Anything that will reduce the techincal functionality of IRC. + 6) Harrasement defined by Norwegian Civil Law. + 7) Using offencive words in channel topics on public channels. + 8) Destroys the integrity of information. + 9) Compromise private communication. + + +BOT-RULES - The following guidelines must be followed: + 1) Bots must not have fake userid unless given permission. + 2) Bots must not send a message to a user not activating it. + 3) Bots must be invisible unless they perform a good "irc-deed". + 4) Bots must only answer to PRIVMSG by using NOTICE. + +Dispensation from some of the bot-rules may be given under certain +circumstances. + + +OPERATOR RULES + This guide gives guidelines on what is not good and what is good. + + Stuff that is not allowed: + - Using SQUIT / CONNECT to gain channel-operator-status. + - Mindless use of KILL. + - Using TRACE to find invisible users. + + Stuff that is allowed: + - Using SQUIT / CONNECT to "fix" the net. This is normally not + allowed and should be used with care. The IRCNO tries to make + efficient use of automatic routing. + - KILL should only be used when a user ask to be killed. KILL can + also be used if it's based in a certain paragraph of the USER + rule file. + + +SERVER RULES + Following is the EBIC-Rules conserning linking. For domestic + linking we have our own rules. + + 1) To get a server connect to the Norwegian IRC-net: + a. New servers must only be leafs. + b. New servers must have one primary- and one secondary link. + c. New servers should only have one active link at a time. + d. The new server must have enough users. + 2) New server connections should be discussed among the existing oper/admins. + 3) Any link should follow the physical net-topology. + 4) A server that is not close to a regional UNINETT net center should not + perform as a HUB server. + 5) Every server in Norway takes part in the national user-staistic. + 6) If hostmasking is to be used, every server behind a mask must be able + to connect to the up-host. + + +ADMIN RULES + 1) An irc-admin must be available by email, unless he/she notifies IRCNO + about any longer planned absence. + 2) A server-admin's duty is to have his/her server perform well for + the end-users and other servers on the irc-net. + 3) An irc-admin must upgrade his/her server and tune it according to + something suitable as soon as a server-release is known to be + relatively stable. + 4) An irc-admin that is not following these rules can loose his/her links + if 100% of IRCNO agrees. + + + +Persons in IRCNO +~~~~~~~~~~~~~~~ +We do not have any leader or jobs, but we do preform certain tasks. +Every decision is taken by discussion and voting. We do not have any +problem with this, and no nasty disagreements occur. This we belive +is because of our Norwegian Nature :-) +Who is Who is documentet in the file called irc-no. Norwegian titles +in paranthesis. + +IRCNO secretary (IRCNO sekret{r) + Keeps track and system of all docs that are produced within IRCNO. + The updating of the various documents is left to the one who has + the administrative job with the document. + +Filearchive (Filarkiv) + Keeps the anonymous FTP archie at flode.nvg.unit.no up-to date. + The archive is also accessible by FSP. The archive consist of + IRCNO docs, IRC docs in general, and IRC software. + This person also administrate the two mailinglists that exist (IRCNO + and a IRC-user list) + +Statistics: (Statistikk) + Does the monthly stats of IRC-use in Norway. + +EBIC contact (EBIC kontakt) + This task is defined in the EBIC-rules. + +Link master (Link ansvarlig) + Job is to find the best links for Norwegian servers, and how they + should connect to each other. In link-matters this person often + has the last word. The link master write a link-report from time + to time (found on the archive as "links"). This report is the only + english document beside this one. This person must have good + knowlege on net-structure in Norway and how the server-linking works. + +UNINETT contact (UNINETT kontakt) + UNINETT want one contact person. This person will likely aslo be + known as the one who is "responsible for IRC in Norway". + + +Other stuff +~~~~~~~~~~~ +For a list of servers and their associated persons, see the file irc-no +under "servere in IRCNO". + +This document is proof-read by Espen Anneling (anneling@uiowa.edu) + diff --git a/doc/Nets/Europe/InfoEBIC b/doc/Nets/Europe/InfoEBIC new file mode 100644 index 0000000..1956910 --- /dev/null +++ b/doc/Nets/Europe/InfoEBIC @@ -0,0 +1,48 @@ +InfoEBIC - General information about European IRC //941115 + +Online information sources in Europe +==================================== +- By IRC +#EU-Opers is an adminstrative channel for European IRC networking. + +- Help automatons in the IRC net (based on ircII help pages) +Help_EU, Help_UK Send PRIVMSG, receive NOTICE +Help_IT Requires DCC Chat + +- By WWW +http://www.funet.fi/~irc/ +http://irc.pages.de/ +http://www.nvg.unit.no/irc/IRCNO-page.html + +Public IRC servers in Europe +============================ +- Open for all domains +irc.funet.fi Finland +irc.Univ-Lyon1.FR France + +- Open for national and some neighbouring domains +irc.cdc.polimi.it Italy +irc.span.ch Switzerland +irc.ludd.luth.se Sweden +irc.nvg.unit.no Norway +irc.sci.kun.nl Netherlands +irc.uni-stuttgart.de Germany +stork.doc.ic.ac.uk United Kingdom + +Anonymous FTP archives with IRC software in Europe +================================================== +ftp.funet.fi:/pub/unix/irc +ftp.informatik.tu-muenchen.de:/pub/comp/networking/irc +hplyot.obspm.fr:/irc +src.doc.ic.ac.uk:/packages/irc + +Mailing list +============ +There is administrative mailing list for european IRC networking. +The list address is irc-eu@ifens01.insa-lyon.fr. This list is run by +an automated mailing-list manager tool, so all requests concerning +the list should be mailed to listserv@ifens01.insa-lyon.fr. To get help, +send "help" in mail message to the listserv address, and you will +get help file in reply. + + diff --git a/doc/Nets/Europe/RulesEBIC b/doc/Nets/Europe/RulesEBIC new file mode 100644 index 0000000..8e693ff --- /dev/null +++ b/doc/Nets/Europe/RulesEBIC @@ -0,0 +1,90 @@ + ######################################################################## + ##### RULES FOR ESTABLISHING NEW IRC SERVERS IN EUROPE (v1.1) ##### + ######################################################################## + + + 1.) Establishing a new server and inner domain linking should be + a local toplevel domain (country) decision. + + Guidelines: + + + New servers should be leafed until their admin(s) + have sufficient experience to handle their server + responsibly. (This avoids routing disasters). + + + Only a link for ONE server should be given to the new + server site, that means the new site shouldn't be able to + connect test-servers to other than its own server. + (This avoids confusion about linking hierarchy). + + + Be sure that if a toplevel domain hostmask link is given, + all hubs of that domain can connect the masked server! + (this should avoid disagreement between serveral hub + admins in one domain). + + + 2.) All other links between toplevel domains (countries) should be + dicussed between the major link coordinators of each toplevel + domain (country). These coordinators are called European Board + of IRC Coordinators (EBIC). + + Guidelines: + + + Major link coordinators of each toplevel domain (country) + should be published with the server sourcecode in + directory ./doc/Europe + + + Each toplevel domain (country) participating in the + European IRC net must have a coordinator, who is + responsible for country-internal connections AND + represents the country in contacts with the rest of the + world. This person(s) is (are) chosen by their domain, + but must be approved by the EBIC. + + + The EBIC is the only executive in charge of European + interconnections and of connections from Europe to the + rest of the world. They will decide linking issues + WITH the affected local admins. + + + For establishing new links between several toplevel + domains the affected EBIC coordinators should be + consulted. If further coordination is needed it should + be discussed within the EBIC. + + + Additional note: International links should also take + care of the network topology, so even if several national + opers agree on a same international link, they might be + wrong and use unecessary network ressources. The EBIC + should avoid such linking. + + + Any major linking change should be announced in the + european mailing list: + IRC-Operators Europe <irc-eu@grasp.insa-lyon.fr> + + + 3.) Cracked servers are the concern of EBIC, overiding all local + interests. + + Guidelines: + + + In a server with non-standard source code which breaks + the current irc protocol (especially the incorrect + manipulation of channel modes and user/hostname authen- + tication) EBIC will take action. + + + The recommended action is permanent withdrawl of the + server from the IRC-net by removal from all its uplinks + configuration files. + + + 4.) A prerequisite for getting a NEW server connection within + Europe is an understanding of and compliance to the above + rules. + + Guideline: + + + All new admins should get a copy of these rules. + + +############################################################################ + diff --git a/doc/Nets/Europe/links.eu b/doc/Nets/Europe/links.eu new file mode 100644 index 0000000..0d77ac7 --- /dev/null +++ b/doc/Nets/Europe/links.eu @@ -0,0 +1,70 @@ +Written by Per Persson <pp@pfawww.pp.se>, last update: 1996-06-18 + +1) Europe should always be a separate net from the other parts of + (what was formerly known as) "EFNet". For example; Netherlands + with leafs and Sweden/Finland (with leafs) should always be + connected to eachother. There are a few times when that wont work + though... NORDUnet might have fuckups from time to time and in + those few cases we have to use more then one link to USA. + +2) Europe "should" be connected this way; + + * irc.nada.kth.se is the primary HUB for northern Europe as well + as some southern European servers (.at). irc.nada.kth.se is + also the primary European HUB for connections to US. + * warszawa.irc.pl is the primary .pl HUB, primary uplink for .pl + is .se with .fi/.at as secondary + (.pl is almost never connected to "EFNet" right now) + * ircd.funet.fi is the primary .fi HUB and irc.cs.hut.fi is the + backup. + * irc.pvv.unit.no is the primary .no HUB and irc.ifi.uio.no is + the backup, primary uplink for .no is .se with .fi as secondary. + * irc.ru is the primary .ru HUB, primary uplink is .fi with .se as + secondary. + * irc.isnet.is's primary uplink is .fi, irc.ludd.luth.se is secondary + * sunsite.auc.dk's primary uplink is irc.nada.kth.se + * irc.ccii.unipi.it is the primary HUB for Italy, primary uplink is + .se with .nl/.uk as secondary. + * irc.felk.cvut.cz is the primary .cz HUB, primary uplink is .se. + * irc.sanet.sk's primary uplink is .cz. + + * irc.nijnerode.nl is the primary HUB for sourthern Europe and .uk. + Primary uplink is irc.ludd.luth.se(irc.nada.kth.se) with .fi as + secondary + * irc.univ-lyon1.fr is the primary .fr HUB and + sil.polytechnique.fr is the backup. primary uplink for .fr is + irc.ludd.luth.se and secondary uplink for .fr is irc.cerf.net. + * stork.doc.ic.ac.uk is the primary .uk HUB and serv.eng.abdn.ac.uk + is the backup. Primary uplink is .nl with .se/.fi as secondary. + (.uk also has a .net server, as well as a netcom.net.uk server which + uses a bit different uplinks--the rest of the .uk servers are + connected to those on occasions as well) + * irc.belnet.be is the primary .be HUB, primary uplink for .be is + .uk with .fr/.nl as secondary. + * irc.wu-wien.ac.at is the primary .at HUB, primary uplink for + .at is .fr with .se as secondary. + * irc.uni-paderborn.de is the primary .de HUB, primary uplink for + .de is .nl with .fi as secondary. + (.de isn't often connected, as they have sloooow links) + * irc.arnes.si's primary uplink is .nl, secondary uplink is .se. + + * The primary link for Europe to USA is; .se - USA + backups are; .fi/.nl - USA + (USA can be one of the following; cs-pub.bu.edu, ircd.stealth.net + eff.org, bazooka.rutgers.edu or irc.cerf.net. irc.cerf.net + is the prefered one nowadays with ircd.stealth.net as secondary) + +3) The ASCII map of all this, to make things "easier to comprehend". + + + (.no .dk .pl .it) __ .se __ .fi __ (.is .ru) + /|\ + .uk __ .nl __/ | \__ .cz __ (.sk) + | | | + (.be) | .fr __ (.at) + | + (.si .ch .de) + + ()'s marks leafs +\ _ /'s marks links + diff --git a/doc/Nets/Europe/rules b/doc/Nets/Europe/rules new file mode 100644 index 0000000..4ad34dc --- /dev/null +++ b/doc/Nets/Europe/rules @@ -0,0 +1,55 @@ +Rules for IRC networking - Ratified July 6th 1994 + +1.) The establishment of new servers and intra-domain linking should + be a local toplevel domain (IE: country) decision. + + Guidelines: + + + Only a link for ONE server should be given to the new + server site, that means the new site shouldn't be able to + connect test-servers to other than its own server. + (This avoids confusion about linking hierachy). + + + If a toplevel domain hostmask link is given, ensure that all + hubs of that domain have connect access to the masked server + (this should avoid disagreements between hub admins within a + domain). + +2.) Hacked or cracked servers (and the machines they run on) are the + concern of all Admins, and override all local interests. + + Guidelines: + + + In a server with non-standard source code which breaks + the current irc protocol (especially the incorrect + manipulation of channel modes and user/hostname authen- + tication) Admins will take action, this includes the + testing of these patches. + + + The recommended action is permanent withdrawl of the + server from the IRC-net by removal from all its uplinks + configuration files. + +3.) The Admins are responsible for all operator access. + IRC Administrators should therefore be approved by the + machine and network admins for the site in question. + +4.) Operator power may be used only on server and network + maintenance purposes. KILL may be used only when other + methods to fix a problem don't exist. + +Infringement of the rules as outlined above should lead to +operator and/or admin changes on the offending server. +Responsibility for these changes is primarily that of the uplink +server administrators. + +In the event of continued transgression, further action may be +taken by remote IRC Administrators 24 hours after the problem +has been identified and all responsible parties have been +notified. + +All intended additions to this document must be announced to IRC +Administrators for at least one week prior to ratification. + +-- +Edited June 29th by #EU-Opers diff --git a/doc/Nets/IRCNet b/doc/Nets/IRCNet new file mode 100644 index 0000000..eaa7396 --- /dev/null +++ b/doc/Nets/IRCNet @@ -0,0 +1,17 @@ +The IRC Net Mailing List + +The IRC Net Mailing List is meant for discussion about issues concerning the +IRC Net network. It is currently an open mailing list and you can subscribe +by typing the following in a shell: + + echo subscribe ircnet | mail majordodo@modeemi.cs.tut.fi + +And to see who is on the mailing list you just need to type the following: + + echo who ircnet | mail majordodo@modeemi.cs.tut.fi + +All messages to the mailing list itself are to be sent to: + + ircnet@modeemi.cs.tut.fi + +http://www.irc.at/bic/ diff --git a/doc/README b/doc/README new file mode 100644 index 0000000..0567db9 --- /dev/null +++ b/doc/README @@ -0,0 +1,40 @@ +# @(#)$Id: README,v 1.5 1999/03/08 17:31:42 kalt Exp $ + +This directory contains the documentation related to this package. + + + +The files relevant to the software compilation and configuration are: + +RELEASE_NOTES - useful information for people upgrading from a previous + version +INSTALL.txt - detailed information about compilation and configuration +example.conf - server configuration example file (useful complement to + INSTALL) + + + +Other files of interest: + +LICENSE - license agreement +ChangeLog - log of source changes +BUGS - list of known bugs +2.10-New - transition documentation from 2.9 to 2.10 version +Etiquette - IRC Etiquette +irc.1 - man page for the client +ircd.8 - man page for the server +iauth.8 - man page for iauth +iauth.conf.5 - man page for the iauth.conf file +Authors - irc contributors +Nets/ - documentation about various IRC networks +Juped/ - old/obsolete documentation files +alt-irc-faq - alt.irc faq +m4macros - note on m4 macros for the server configuration file +2.9-New - old transition documentation from 2.8 to 2.9 version + + + +related documents on the World Wide Web: + + http://www.stealth.net/~kalt/irc/faq.html + http://www.irc.org/~irc/server/ diff --git a/doc/RELEASE_LOG b/doc/RELEASE_LOG new file mode 100644 index 0000000..f3b20c6 --- /dev/null +++ b/doc/RELEASE_LOG @@ -0,0 +1,23 @@ +# @(#)$Id: RELEASE_LOG,v 1.6 1999/08/13 19:53:11 kalt Exp $ + +990813 2.10.3 +990203 2.10.2 +981112 2.10.1 +980927 2.10.0 +980613 2.9.5+IPv6 +980218 2.9.5 +971020 2.9.4 +970724 2.9.3 +961109 2.9.2 +960707 2.9.1 +941203 2.8.21 +940610 2.8.20 +931109 2.8.16 +930914 2.8.14 +930807 2.8.12 +930626 2.8.10 +930405 2.7.2h +920811 2.7.2g +920514 2.7.2 +920114 2.7.1 +910906 2.6.2 diff --git a/doc/RELEASE_NOTES b/doc/RELEASE_NOTES new file mode 100644 index 0000000..ee6b2e3 --- /dev/null +++ b/doc/RELEASE_NOTES @@ -0,0 +1,120 @@ +# @(#)$Id: RELEASE_NOTES,v 1.34 1999/08/13 17:55:01 kalt Exp $ + +This is version 2.10.3 of the IRC software. + +=============================================================================== + +New features in 2.10.3: + * new options for iauth.conf to better control iauth behaviour + * iauth now supports dynamically shared modules. + * socks module now checks for both v4 and v5 of the SOCKS protocol. + * iauth has a new module: LHEx, see ftp://ftp.irc.org/irc/server/LHEx + +Important changes in 2.10.3 (since 2.10.2): + * default PATHs have changed, see INSTALL file and Makefile. + * V line code was fixed, and format slightly changed again. + +------ + +Because of the many changes concerning iauth, it is recommended that this new +version of the iauth program not be used with older version of the IRC daemon. + +=============================================================================== + +Version 2.10.2 of the software adds support for IPv6. + +Important changes in 2.10.2 (since 2.10.1): + * iauth's socks module now uses an internal cache. + * iauth's socks module now checks for SOCKSv4 (rather than v5) proxies. + +=============================================================================== + +2.10 uses a new (server-server) protocol. + +New features in 2.10.0: + + * slave process handles authentication (ident lookups, ..). + * creation of a collision proof type of channels (prefix !). + * opless !channels may be reoped by the server (mode +r). + * added channel mode +e (EFnet's exceptions to bans). + * added channel mode +I (invitations). + * /invite can now be used to override channel bans & limit. + * away status is propagated again. (away messages are not). + * users need +o (or +v) to speak on a channel where they're banned. + +Important configuration changes between 2.9.x and 2.10.x: + + * The V line format has changed! + +------ + +If the irc daemon is unable to bind any socket to listen to for incoming +connections, it will die rather than stay alive. + +=============================================================================== + +New feature in 2.9.5: + * D lines created. + +------ + +2.9.5 is taking steps to suppress the usage of the 2.9 JOIN +format (:nickname JOIN #channel^Gov). Future versions will +not generate such joins anymore. In order to make the +transition smooth, it is imperative that all servers on the +IRC network be upgraded to 2.9.5 when the JOIN syntax is +abandonned. Not doing so will result in a considerable +increase of the amount of bandwidth used during netjoins. + +As a result, MIRC_KLUDGE is now defined by default in config.h + +------ + +2.9.5 can be compiled on a W32 system using the Cygwin32 +library (http://www.cygnus.com/misc/gnu-win32/). + +=============================================================================== + +2.9.4 doesn't support 2.8 links anymore. A 2.8.x server cannot +be directly linked to a 2.9.4 server. They can however coexist +on the same IRC network. + +------ + +Configuration changes between 2.9.3 and 2.9.4: + + * The format for I lines was extended. + * The format for B lines has slightly changed. + * The format for Y lines has changed ([user@]host limits). + * K lines on IP addresses now match resolving hosts by default. + +------ + +As announced with the 2.9.3 release, the NOTE feature has been removed. +A replacement has been written as an independant package, and can be found +at the following location: ftp://ftp.cs.tu-berlin.de/pub/net/irc/noteserv/ + +=============================================================================== + +2.9.3 doesn't support 2.7 protocol anymore. Don't run 2.9.3 +and 2.7 servers on the same IRC network. + +------ + +New features in 2.9.3: + + * compression of server links. + * virtual IP support. + * B lines created. (client redirection) + * k lines created. (OTHER ident) + * V lines created. (restrict peers' compile time options) + * new type of client: services. + +------ + +Important configuration changes between 2.9.2 and 2.9.3: + + * M and P lines format has changed since 2.9.2, it is important + to update your ircd.conf ! + * kill lines are now case sensitive (K: and k: are different) + diff --git a/doc/SERVICE.sgml b/doc/SERVICE.sgml new file mode 100644 index 0000000..ad72843 --- /dev/null +++ b/doc/SERVICE.sgml @@ -0,0 +1,285 @@ +<!doctype linuxdoc system> + +<article> + +<title>IRC Services +<author>Christophe Kalt +<date>$Id: SERVICE.sgml,v 1.6 1999/04/15 21:55:52 kalt Exp $ +<abstract> +The IRC protocol described in RFC 1459 defines two types of +connections (client, and server). A third type was +introduced with version 2.9 of the IRC software: service +connections. This document describes what services are, and +how to use them. +</abstract> + +<sect>A new type of connection +<p> +A service connection is something between a client and a +server connection. It is not closer from any, as a matter +of fact, the scope is pretty broad. +<sect1>A bit client +<p> +services are similar to clients because they cannot: +<itemize> +<item> introduce other clients, services, or servers. +<item> change the global state of the net. (kill, squit..) +</itemize> +<sect1>A bit server +<p> +services are similar to servers because: +<itemize> +<item> they cannot join channels. +<item> they are not limited by flood control or penalty. +<item> they can see all users, servers, services. +<item> they can see all channel names. +<item> they cannot freely connect to a server. +<item> they may optionally receive a connection burst. +</itemize> +<sect1>Really unique +<p> +services are unique because: +<itemize> +<item> they are not subject to collisions. +<item> they can be local to one, or more servers, or global. +<item> they can only send notices, not private messages. +<item> they can only be contacted by the use of SQUERY. +</itemize> +<p> +Services are not meant to be used interactively, but provide +adequate support for automatons, statistic gathering, +monitoring. + +<sect>What users see +<p> +This section covers the aspects visible to the users. +<sect1>&SERVICES +<p> +This is a special channel, similar to &SERVERS, on which +are sent notices when a service connects to or quit the net. +<sect1>SERVLIST +<p> +This new command gives the list of services currently +present on the IRC network. It can take two arguments. +<enum> +<item> a mask to limit the output to the services which +names matches the mask. +<item> a type to list only services of a specific type. +</enum> +It returns a list of servers using numeric 234, the +different fields are: +<itemize> +<item> The service name. +<item> The name of the server which introduced it on the +net. +<item> The <ref id="dist" name="distribution"> mask. +<item> The service <ref id="type" name="type">. +<item> The hop count between you and the service. +<item> A comment. +</itemize> +<sect1>SQUERY +<p> +This new command stands for ``Service Query''. The first +argument is the service name, and the second the text to be +sent to the service. + +<sect>How to set up a service +<sect1>Compile time option for the server +<p> +First of all, it is important to note that in order to be +able to connect a service to a server, this server must have +been compiled with ``<bf>USE_SERVICES</bf>'' defined in the +config.h file. To know if your server has been compiled +with this option, check the version: +<p> +351 Server irc.stealth.net: 2.9.3. AaCeEFiIkMu$_V1 +<p> +351 Server irc.pvv.unit.no: 2.9.3. AaeEFHiKMp<bf>s</bf>tuYZ_V1 +<p> +Here, only ``irc.pvv.unit.no'' was compiled with the +``USE_SERVICES'' defined as the lowercase ``s'' shows in the +version string. +<p> +As they are special clients, services need to be allowed +access to the server in the configuration file. Each +service needs its own access to be setup. This is gone by +adding an S: line to the configuration file. This lines +defines the name of the service, as well as the type. +<sect1>Glossary +<p> +Services have two main characteristics: +<descrip> +<label id="type"> +<tag/Type/ This is a misleading name. The type is actually +a bit mask which defines what information the service can +see. The server configuration file limits the type allowed +for a service. The meaning of the bits is defined in the +service.h file coming with the IRC software: +<verb> +SERVICE_WANT_SERVICE 0x00000001 /* other services signing on/off */ +SERVICE_WANT_OPER 0x00000002 /* operators, included in umodes too */ +SERVICE_WANT_UMODE 0x00000004 /* user modes, iow + local modes */ +SERVICE_WANT_AWAY 0x00000008 /* away isn't propaged anymore.. */ +SERVICE_WANT_KILL 0x00000010 /* KILLs */ +SERVICE_WANT_NICK 0x00000020 /* all NICKs (new user, change) */ +SERVICE_WANT_USER 0x00000040 /* USER signing on */ +SERVICE_WANT_QUIT 0x00000080 /* all QUITs (users signing off) */ +SERVICE_WANT_SERVER 0x00000100 /* servers signing on */ +SERVICE_WANT_WALLOP 0x00000200 /* wallops */ +SERVICE_WANT_SQUIT 0x00000400 /* servers signing off */ +SERVICE_WANT_RQUIT 0x00000800 /* regular user QUITs (these which + are also sent between servers) */ +SERVICE_WANT_MODE 0x00001000 /* channel modes (not +ov) */ +SERVICE_WANT_CHANNEL 0x00002000 /* channel creations/destructions */ +SERVICE_WANT_VCHANNEL 0x00004000 /* channel joins/parts */ +SERVICE_WANT_TOPIC 0x00008000 /* channel topics */ + +SERVICE_WANT_ERRORS 0x01000000 /* &ERRORS */ +SERVICE_WANT_NOTICES 0x02000000 /* &NOTICES */ +SERVICE_WANT_LOCAL 0x04000000 /* &LOCAL */ +SERVICE_WANT_NUMERICS 0x08000000 /* &NUMERICS */ + +SERVICE_WANT_USERLOG 0x10000000 /* FNAME_USERLOG */ +SERVICE_WANT_CONNLOG 0x20000000 /* FNAME_CONNLOG */ +</verb> +<label id="dist"> +<tag/Distribution/ This controls the propagation of the +service. The distribution is checked against server names, +the service will only be on servers which names matches the +distribution. +<p> +It also eventually limits the information received by the +service (depending on the service type). A service will not +have any information concerning users or services connected +to a server which name does not match the distribution. +<p> +Examples: +<descrip> +<tag/irc.funet.fi/Using a server name as distribution makes +the service local to the particular server. +<tag/*.fr/This would match any server in the toplevel ``fr''. +<tag/*/This is the distribution to be used to make the +service global. +</descrip> +<p> +It is important to note that the path between the service +and a server <bf>must</bf> be composed of servers which have +matching names: +<verb> +trondheim.irc.no <----> ircd.funet.fi <-----> oslo.irc.no + ^ ^ + | | + | +------> bergen.irc.no + | + +-------[MyService - Distribution *.no] +</verb> +As shown above, if two ``*.no'' servers have a non ``*.no'' +(for example here a ``*.fi'') server connected between them, +in this case the information related to ``MyService'' will +not propagate to ``oslo.irc.no''. +<p> +This means that the service will see information concerning +the ``3 *.no'' servers, but ``oslo.irc.no'' will have no +knowledge of the presence of ``MyService''. Also, the +service is unable to send anything thru ``ircd.funet.fi''. +</descrip> +<sect1>Signing on as a service +<p> +Once the S: line setup on the server, the service connects +by sending the password (PASS command), and then issuing a +``SERVICE'' command: +<p> +SERVICE servicename servername distribution servicetype 0 :Information +<descrip> +<tag/servicename/ This is the name of the service as configured +by the S line. +<tag/servername/ This is ignored by the server. +<tag/distribution/ This is the distribution mask for this +connection. +<tag/servicetype/ This is the service type as configured by +the S line. (It must match) +<tag/Information/ This is any information. It will be sent +in ``SERVLIST'' replies and should be a short description of +the service. +</descrip> +<p> +A successfull registering of a service at the server will +result in a RPL_YOURESERVICE (383) being sent back to +the service. Any other reply as a result of sending service +indicates an error has occured. +<sect1>Requesting data from the server +<p> +Once the connection is established, the service needs to +issue a ``SERVSET'' command to receive the data it wants: +<p> +SERVSET mask1 mask2 +<descrip> +<tag/mask1/ It is a subset of the service type. It defines +what the kind of information the service wants to receive +for this particular connection. +<p> +This mask can also have the following bits set, regardless +of what the S line setting is: +<verb> +SERVICE_WANT_PREFIX 0x10000 /* to receive n!u@h instead of n */ +SERVICE_WANT_TOKEN 0x20000 /* use server token instead of name */ +SERVICE_WANT_EXTNICK 0x40000 /* user extended NICK syntax */ +</verb> +<tag/mask2/ It is optional. It is a subset of mask1 that +defines which information the service wants to receive in a +``connection burst''. The information is similar to a +server ``connection burst'', it describe the current set of +the network. The service can therefore store the +information in memory and update it. +<tag/Note/The ``SERVSET'' command can only be issued once. +</descrip> + +<sect>General notes for server and service administrators +<sect1>User privacy +<p> +Services can see almost as much information as a server. +This means that granting a service connection should be +considered with as much care as granting a server +connection. In particular, the service type should be +limited to the strict minimum needed for the service to be +operational. In most cases, a service type of 0 is enough. +<p> +A great care should be taken to make sure that a service +cannot be (ab)used to obtain information not normally +accessible to users (such as showing invisible +users). <bf>Administrators must remember that the privacy of +the users is at stake</bf>. +<sect1>Guidelines +<p> +To avoid confusion, it is a good idea to obey the following +simple rules: +<descrip> +<tag/Name/The name should be descriptive, and if possible +unique on the network. +<tag/Information/The service ``information'' should be short +and descriptive. +<tag/Mandatory queries/The service must reply to at least 2 +queries: +<descrip> +<tag/ADMIN/Name and e-mail address of the administrator. +<tag/HELP/List of queries understood by the service. Each +query should also have an help. +</descrip> +<tag/Basic queries/These queries should also be understood +by the service: +<descrip> +<tag/INFO/This should be a short text explaining what the +service and its purpose are. +<tag/VERSION/The version of the running code. +</descrip> +</descrip> +<sect1>Flood control +<p> +Also, since services are not affected by flood control, they +can easily flood the IRC network with information. They +should be conceived so this does not happen. +<p> +Services should implement their own flood control (for +outgoing traffic) to be safe. + +</article> diff --git a/doc/SERVICE.txt b/doc/SERVICE.txt new file mode 100644 index 0000000..fa07c3a --- /dev/null +++ b/doc/SERVICE.txt @@ -0,0 +1,330 @@ + IRC Services + Christophe Kalt + $Id: SERVICE.txt,v 1.7 1999/04/15 21:56:53 kalt Exp $ + + The IRC protocol described in RFC 1459 defines two types of connec- + tions (client, and server). A third type was introduced with version + 2.9 of the IRC software: service connections. This document describes + what services are, and how to use them. + + 11.. AA nneeww ttyyppee ooff ccoonnnneeccttiioonn + + A service connection is something between a client and a server + connection. It is not closer from any, as a matter of fact, the scope + is pretty broad. + + 11..11.. AA bbiitt cclliieenntt + + services are similar to clients because they cannot: + + +o introduce other clients, services, or servers. + + +o change the global state of the net. (kill, squit..) + + 11..22.. AA bbiitt sseerrvveerr + + services are similar to servers because: + + +o they cannot join channels. + + +o they are not limited by flood control or penalty. + + +o they can see all users, servers, services. + + +o they can see all channel names. + + +o they cannot freely connect to a server. + + +o they may optionally receive a connection burst. + + 11..33.. RReeaallllyy uunniiqquuee + + services are unique because: + + +o they are not subject to collisions. + + +o they can be local to one, or more servers, or global. + + +o they can only send notices, not private messages. + + +o they can only be contacted by the use of SQUERY. + + Services are not meant to be used interactively, but provide adequate + support for automatons, statistic gathering, monitoring. + + + 22.. WWhhaatt uusseerrss sseeee + + This section covers the aspects visible to the users. + + 22..11.. &&SSEERRVVIICCEESS + + This is a special channel, similar to &SERVERS, on which are sent + notices when a service connects to or quit the net. + + + + 22..22.. SSEERRVVLLIISSTT + + This new command gives the list of services currently present on the + IRC network. It can take two arguments. + + 1. a mask to limit the output to the services which names matches the + mask. + + 2. a type to list only services of a specific type. + + It returns a list of servers using numeric 234, the different + fields are: + + +o The service name. + + +o The name of the server which introduced it on the net. + + +o The ``distribution'' mask. + + +o The service ``type''. + + +o The hop count between you and the service. + + +o A comment. + + 22..33.. SSQQUUEERRYY + + This new command stands for ``Service Query''. The first argument is + the service name, and the second the text to be sent to the service. + + + 33.. HHooww ttoo sseett uupp aa sseerrvviiccee + + 33..11.. CCoommppiillee ttiimmee ooppttiioonn ffoorr tthhee sseerrvveerr + + First of all, it is important to note that in order to be able to + connect a service to a server, this server must have been compiled + with ``UUSSEE__SSEERRVVIICCEESS'' defined in the config.h file. To know if your + server has been compiled with this option, check the version: + + 351 Server irc.stealth.net: 2.9.3. AaCeEFiIkMu$_V1 + + 351 Server irc.pvv.unit.no: 2.9.3. AaeEFHiKMpsstuYZ_V1 + + Here, only ``irc.pvv.unit.no'' was compiled with the ``USE_SERVICES'' + defined as the lowercase ``s'' shows in the version string. + + As they are special clients, services need to be allowed access to the + server in the configuration file. Each service needs its own access + to be setup. This is gone by adding an S: line to the configuration + file. This lines defines the name of the service, as well as the + type. + + 33..22.. GGlloossssaarryy + + Services have two main characteristics: + + + TTyyppee + This is a misleading name. The type is actually a bit mask + which defines what information the service can see. The server + configuration file limits the type allowed for a service. The + meaning of the bits is defined in the service.h file coming with + the IRC software: + + + SERVICE_WANT_SERVICE 0x00000001 /* other services signing on/off */ + SERVICE_WANT_OPER 0x00000002 /* operators, included in umodes too */ + SERVICE_WANT_UMODE 0x00000004 /* user modes, iow + local modes */ + SERVICE_WANT_AWAY 0x00000008 /* away isn't propaged anymore.. */ + SERVICE_WANT_KILL 0x00000010 /* KILLs */ + SERVICE_WANT_NICK 0x00000020 /* all NICKs (new user, change) */ + SERVICE_WANT_USER 0x00000040 /* USER signing on */ + SERVICE_WANT_QUIT 0x00000080 /* all QUITs (users signing off) */ + SERVICE_WANT_SERVER 0x00000100 /* servers signing on */ + SERVICE_WANT_WALLOP 0x00000200 /* wallops */ + SERVICE_WANT_SQUIT 0x00000400 /* servers signing off */ + SERVICE_WANT_RQUIT 0x00000800 /* regular user QUITs (these which + are also sent between servers) */ + SERVICE_WANT_MODE 0x00001000 /* channel modes (not +ov) */ + SERVICE_WANT_CHANNEL 0x00002000 /* channel creations/destructions */ + SERVICE_WANT_VCHANNEL 0x00004000 /* channel joins/parts */ + SERVICE_WANT_TOPIC 0x00008000 /* channel topics */ + + SERVICE_WANT_ERRORS 0x01000000 /* &ERRORS */ + SERVICE_WANT_NOTICES 0x02000000 /* &NOTICES */ + SERVICE_WANT_LOCAL 0x04000000 /* &LOCAL */ + SERVICE_WANT_NUMERICS 0x08000000 /* &NUMERICS */ + + SERVICE_WANT_USERLOG 0x10000000 /* FNAME_USERLOG */ + SERVICE_WANT_CONNLOG 0x20000000 /* FNAME_CONNLOG */ + + + + DDiissttrriibbuuttiioonn + This controls the propagation of the service. The distribution + is checked against server names, the service will only be on + servers which names matches the distribution. + + It also eventually limits the information received by the + service (depending on the service type). A service will not + have any information concerning users or services connected to a + server which name does not match the distribution. + + Examples: + + iirrcc..ffuunneett..ffii + Using a server name as distribution makes the service local + to the particular server. + + **..ffrr + This would match any server in the toplevel ``fr''. + + ** This is the distribution to be used to make the service + global. + + It is important to note that the path between the service and a + server mmuusstt be composed of servers which have matching names: + + trondheim.irc.no <----> ircd.funet.fi <-----> oslo.irc.no + ^ ^ + | | + | +------> bergen.irc.no + | + +-------[MyService - Distribution *.no] + + + As shown above, if two ``*.no'' servers have a non ``*.no'' (for + example here a ``*.fi'') server connected between them, in this + case the information related to ``MyService'' will not propagate to + ``oslo.irc.no''. + + This means that the service will see information concerning the ``3 + *.no'' servers, but ``oslo.irc.no'' will have no knowledge of the + presence of ``MyService''. Also, the service is unable to send + anything thru ``ircd.funet.fi''. + + 33..33.. SSiiggnniinngg oonn aass aa sseerrvviiccee + + Once the S: line setup on the server, the service connects by sending + the password (PASS command), and then issuing a ``SERVICE'' command: + + SERVICE servicename servername distribution servicetype 0 :Information + + sseerrvviicceennaammee + This is the name of the service as configured by the S line. + + sseerrvveerrnnaammee + This is ignored by the server. + + ddiissttrriibbuuttiioonn + This is the distribution mask for this connection. + + sseerrvviicceettyyppee + This is the service type as configured by the S line. (It must + match) + + IInnffoorrmmaattiioonn + This is any information. It will be sent in ``SERVLIST'' + replies and should be a short description of the service. + + A successfull registering of a service at the server will result in a + RPL_YOURESERVICE (383) being sent back to the service. Any other reply + as a result of sending service indicates an error has occured. + + 33..44.. RReeqquueessttiinngg ddaattaa ffrroomm tthhee sseerrvveerr + + Once the connection is established, the service needs to issue a + ``SERVSET'' command to receive the data it wants: + + SERVSET mask1 mask2 + + mmaasskk11 + It is a subset of the service type. It defines what the kind of + information the service wants to receive for this particular + connection. + + This mask can also have the following bits set, regardless of + what the S line setting is: + + SERVICE_WANT_PREFIX 0x10000 /* to receive n!u@h instead of n */ + SERVICE_WANT_TOKEN 0x20000 /* use server token instead of name */ + SERVICE_WANT_EXTNICK 0x40000 /* user extended NICK syntax */ + + + + mmaasskk22 + It is optional. It is a subset of mask1 that defines which + information the service wants to receive in a ``connection + burst''. The information is similar to a server ``connection + burst'', it describe the current set of the network. The + service can therefore store the information in memory and update + it. + + NNoottee + The ``SERVSET'' command can only be issued once. + + + 44.. GGeenneerraall nnootteess ffoorr sseerrvveerr aanndd sseerrvviiccee aaddmmiinniissttrraattoorrss + + 44..11.. UUsseerr pprriivvaaccyy + + Services can see almost as much information as a server. This means + that granting a service connection should be considered with as much + care as granting a server connection. In particular, the service type + should be limited to the strict minimum needed for the service to be + operational. In most cases, a service type of 0 is enough. + + A great care should be taken to make sure that a service cannot be + (ab)used to obtain information not normally accessible to users (such + as showing invisible users). AAddmmiinniissttrraattoorrss mmuusstt rreemmeemmbbeerr tthhaatt tthhee + pprriivvaaccyy ooff tthhee uusseerrss iiss aatt ssttaakkee. + + 44..22.. GGuuiiddeelliinneess + + To avoid confusion, it is a good idea to obey the following simple + rules: + + NNaammee + The name should be descriptive, and if possible unique on the + network. + + IInnffoorrmmaattiioonn + The service ``information'' should be short and descriptive. + + MMaannddaattoorryy qquueerriieess + The service must reply to at least 2 queries: + + AADDMMIINN + Name and e-mail address of the administrator. + + HHEELLPP + List of queries understood by the service. Each query should + also have an help. + + BBaassiicc qquueerriieess + These queries should also be understood by the service: + + IINNFFOO + This should be a short text explaining what the service and + its purpose are. + + VVEERRSSIIOONN + The version of the running code. + + 44..33.. FFlloooodd ccoonnttrrooll + + Also, since services are not affected by flood control, they can + easily flood the IRC network with information. They should be + conceived so this does not happen. + + Services should implement their own flood control (for outgoing + traffic) to be safe. + + + + + + + + + + + diff --git a/doc/alt-irc-faq b/doc/alt-irc-faq new file mode 100644 index 0000000..3a5bdb5 --- /dev/null +++ b/doc/alt-irc-faq @@ -0,0 +1,293 @@ +(1) What is IRC? + + IRC stands for "Internet Relay Chat". It was originally +written by Jarkko Oikarinen (jto@tolsun.oulu.fi) in 1988. Since starting +in Finland, it has been used in over 60 countries around the world. It +was designed as a replacement for the "talk" program but has become much +much more than that. IRC is a multi-user chat system, where people convene +on "channels" (a virtual place, usually with a topic of conversation) to +talk in groups, or privately. IRC is constantly evolving, so the way +things to work one week may not be the way they work the next. Read the +MOTD (message of the day) every time you use IRC to keep up on any new +happenings or server updates. + + IRC gained international fame during the 1991 Persian Gulf War, +where updates from around the world came accross the wire, and most irc +users who were online at the time gathered on a single channel to hear +these reports. IRC had similar uses during the coup against Boris Yeltsin +in September 1993, where IRC users from Moscow were giving live reports +about the unstable situation there. + +(2) How is IRC set up? + + The user runs a "client" program (usually called 'irc') which +connects to the IRC network via another program called a "server". +Servers exist to pass messages from user to user over the IRC network. + +(3) How do I use a client? + + First, check to see if irc is installed on your system. Type +"irc" from your prompt. If this doesn't work, ask your local systems +people if irc is already installed. This will save you the work of +installing it yourself. + + If an IRC client isn't already on your system, you either +compile the source yourself, have someone else on your machine compile +the source for you, or use the TELNET client. +"telnet ircclient.itc.univie.ac.at 6668". Please only use the latter when +you have no other way of reaching IRC, as this resource is quite +limited, slow, and *very* unreliable. + +(4) Where can I get source for an IRC client? + + You can anonymous ftp to any of the following sites (use the +one closest to you): *** If you don't know what anonymous ftp is, ask +your local systems people to show you *** + +UNIX client-> cs.bu.edu /irc/clients + ftp.acsu.buffalo.edu /pub/irc + ftp.funet.fi /pub/unix/irc + coombs.anu.edu.au /pub/irc + (NB. if there is something related to IRC and it can't + be found under coombs.anu.edu.au:/pub/irc then it isn't + worth having). + ftp.informatik.tu-muenchen.de /pub/comp/networking/irc/clients + slopoke.mlb.semi.harris.com /pub/irc + there is also a client avaliable with the server code. +EMACS elisp-> cs.bu.edu /irc/clients/elisp + ftp.funet.fi /pub/unix/irc/Emacs + ftp.informatik.tu-muenchen.de /pub/comp/networking/irc/clients + slopoke.mlb.semi.harris.com /pub/irc/emacs + cs.hut.fi /pub/irchat +X11 client-> catless.ncl.ac.uk /pub + harbor.ecn.purdue.edu /pub/tcl/code +VMS -> cs.bu.edu /irc/clients/vms + coombs.anu.edu.au /pub/irc/vms + ftp.funet.fi /pub/unix/irc/vms + ftp.informatik.tu-muenchen.de /pub/net/irc +REXX client for VM-> cs.bu.edu /irc/clients/rxirc + ftp.informatik.uni-oldenburg.de /pub/irc/rxirc + ftp.informatik.tu-muenchen.de /pub/net/irc/VM + coombs.anu.edu.au /pub/irc/rxirc + ftp.funet.fi /pub/unix/irc/rxirc +MSDOS-> cs.bu.edu /irc/clients/msdos + ftp.funet.fi /pub/unix/irc/msdos +Macintosh-> cs.bu.edu /irc/clients/macintosh + sumex-aim.stanford.edu /info-mac/comm + ftp.funet.fi /pub/unix/irc/mac + ftp.ira.uka.de /pub/systems/mac + +(5) Which server do I connect to? + + It's usually best to try and connect to one geographically +close, even though that may not be the best. You can always ask when you +get on IRC. Here's a list of servers avaliable for connection: + +USA: + cs-pub.bu.edu + irc.colorado.edu + irc-2.mit.edu + +Canada: + ug.cs.dal.ca + +Europe: + irc.funet.fi + cismhp.univ-lyon1.fr + disuns2.epfl.ch + irc.nada.kth.se + sokrates.informatik.uni-kl.de + bim.itc.univie.ac.at + +Australia: + jello.qabc.uq.oz.au + + +This is, by no means, a comprehensive list, but merely a start. Connect +to the closest of these servers and join the channel #Twilight_Zone +When you get there, immediately ask what you want. Don't say "I have a +question" because then hardly anyone will talk. + +(6) OK, I've got a client and I'm connected to a server, now what? + + It's probably best to take a look around and see what you want +to do first. All IRC commands start with a "/", and most are one word. +Typing /help will get you help information. /names will get you a list +of names, etc. + +The output of /names is typically something like this-> + +Pub: #hack zorgo eiji Patrick fup htoaster +Pub: #Nippon @jircc @miyu_d +Pub: #nicole MountainD +Pub: #hottub omar liron beer Deadog moh pfloyd Dode greywolf SAMANTHA + +(Note there are LOTS more channels than this, this is just sample +output -- one way to stop /names from being too large is doing /names +-min 20 which will only list channels with 20 or more people on it, +but you can only do this with the ircII client). + +"Pub" means public (or "visible") channel. "hack" is the channel name. +"#" is the prefix. A "@" before someone's nickname indicates he/she is the +"Channel operator" (see #7) of that channel. A Channel Operator is someone +who has control over a specific channel. It can be shared or not as the +first Channel Operator sees fit. The first person to join the channel +automatically receives Channel Operator status, and can share it with +anyone he/she chooses (or not). Another thing you might see is "Prv" +which means private. You will only see this if you are on that private +channel. No one can see Private channels except those who are on that +particular private channel. + +(7) What is a channel operator? What is an IRC operator? + + A channel operator is someone with a "@" by their nickname in +a /names list, or a "@" by the channel name in /whois output. Channel +operators are kings/queens of their channel. This means they can kick +you out of their channel for no reason. If you don't like this, you +can start your own channel and become a channel operator there. + + An IRC operator is someone who maintains the IRC network. They +cannot fix channel problems. They cannot kick someone out of a channel +for you. They cannot /kill (kick someone out of IRC temporarily) +someone just because you gave the offender channel operator privileges +and said offender kicked *you* off. + +(8) What is a "bot"? + + "bot" is short for "robot". It is a script run from an ircII +client or a separate program (in perl, C, and sometimes more obscure +languages). StarOwl@uiuc.edu (Michael Adams) defined bots very well: "A +bot is a vile creation of /lusers to make up for lack of penis length". +IRC bots are generally not needed. See (10) below about "ownership" of +nicknames and channels. + + It should be noted that many servers (especially in the USA) have +started to ban ALL bots. Some ban bots so much that if you run a bot on +their server, you will be banned from using that server (see segment below +on K: lines). + +(9) What are good channels to try while using IRC? + + #hottub and #initgame are almost always teeming with people. +#hottub is meant to simulate a hot tub, and #initgame is a non-stop game +of "inits" (initials). Just join and find out! + + To get a list of channels with their names and topics, do +/list -min 20 (on ircII) which will show you channels with 20 or more +members. You can also do this for smaller numbers. + + Many IRC operators are in #Twilight_Zone ... so if you join +that channel be prepared for a lot of senseless dribble, more like what +you find on the other channels listed above (#hottub). What was once a +place of people who could help you has turned into just another place +for those who have nothing better to do with themselves than just be +there. If you find other documents saying go there to ask questions, +ignore them. They should be considered to be out of date. + +(10) Someone is using my nickname, can anyone do anything about it? + Someone is using my channel, can anyone do anything about it? + + There are not enough nicknames to have nickname ownership. If +someone takes your nickname while you are not on IRC, you can ask for +them to give it back, but you can not *demand* it, nor will IRC operators +/kill for nickname ownership. If you goto #Twilight_zone, you will find +a bunch of people who will refuse to do this for you, yet they will do it +for themselves or their friends or use /kill for even less reasonable uses. + + There are, literally, millions of possible channel names, so if +someone is on your usual channel, just go to another. You can /msg them +and ask for them to leave, but you can't *force* them to leave. + +(11) There aren't any channel operators on my channel, now what? + + Channel operators are the owner(s) of their respective channels. +Keep this in mind when giving out channel operator powers (make sure to +give them to enough people so that all of the channel operators don't +unexpectedly leave and the channel is stuck without a channel operator). + + On the other hand, do not give out channel operator to +*everyone*. This causes the possibility of mass-kicking, where the +channel would be stuck without any channel operators. + + You have one option. You can ask everyone to leave and rejoin +the channel. This is a good way to get channel operator back. It +doesn't work on large channels or ones with bots, for obvious reasons. + +(12) What if someone tells me to type something cryptic? + + Never type anything anyone tells you to without knowing what it +is. There is a problem with typing certain commands with the ircII +client that give anyone immediate control of your client (and thus can +gain access to your account). + +(13) What does "*** Ghosts are not allowed on IRC." mean? + + On IRC, you cannot be banned from every single server. +Server-banning exists only on a per-server basis (being banned on one +server does not mean you are automatically banned from another). "Ghosts +are not allowed on IRC" means that you are banned from using that server. +The banning is in one of three forms: + + * You are banned specifically, you yourself. Only you can be responsible + for this (if you are using a shared account, this obviously does not + apply). Thus the responsibility lies completely with you and you have + noone to complain to. + + * Your machine is banned. Chances are it wasn't you who committed the + wrongdoing. Try using another machine on campus and seeing if you can + use that particular irc server then. + + * Your whole site is banned (where "site" == "school", "company", + "country"). This almost certainly wasn't your fault. And chances are + you won't be able to get the server-ban lifted. Try using another + server. + + The most general answer is "use another server", but if it bothers +you, try writing to the irc administrator of that site --> +/admin server.name.here -- plead your case. It might even get somewhere! + +(14) Where can I find GIF archives of IRC people? + + GIF archives of IRC people are available: + + ftp.funet.fi:/pub/pics/people/misc/irc (NORDUnet only) + ftp.informatik.tu-muenchen.de /pub/comp/networking/irc/RP + +(15) Where can I learn more? + + The best, basic, IRC user's manual is the IRC Primer, +available in plain text, PostScript, and LaTeX from +cs-pub.bu.edu:/irc/support ... Another good place to start might be +downloading the IRC tutorials. They're avaliable via anonymous ftp +from cs-pub.bu.edu in /irc/support/tutorial.* + + You can also join various IRC related mailing lists: + + * "operlist" is a list that discusses current (and past) server code, + routing, and protocol. *WARNING* this mailling list has a *LOT* of + flame traffic from those who think they know everything but in reality + have no better idea than you. You can join by mailing + operlist-request@kei.com. + + * "irchat" is an elisp client. You can join the irchat mailing list by + mailing irchat-request@cc.tut.fi. + + * "ircd-three" is a list that exists to discuss protocol revisions + for the 3.0 release of the ircd (irc server), currently in + planning. Mail ircd-three-request@kei.com to be added. + + * "vmsirc" is a list for the questions, problems, and discussions + related to the vms IRC clients. Mail vmsirc-request@vax1.elon.edu + (with "subscribe" in the message body). + +NOTE! These are not "Help me, where can I get started?" lists. For +that information, read the IRCprimer noted above. + + Those looking for more technical information can get the IRC +RFC (rfc1459) available at all RFC ftp sites, as well as +cs-pub.bu.edu:/irc/support/rfc1459.txt + +(16) What do I do if I'm still confused or have additions to this document? + + email hrose@kei.com or avalon@coombs.anu.edu.au + diff --git a/doc/example.conf b/doc/example.conf new file mode 100644 index 0000000..afcc9c2 --- /dev/null +++ b/doc/example.conf @@ -0,0 +1,531 @@ +# IRC - Internet Relay Chat, doc/example.conf +# Copyright (C) 1994, Helen Rose +# +# $Id: example.conf,v 1.11 1999/07/14 16:17:23 kalt Exp $ +# +# some changes for 295 and cleaning, delta, Sat Jun 13 01:09:25 MES 1998 +# +# 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 is an example configuration file for the IRC server. +# It's highly suggested that you also read INSTALL.* in doc/ and talk with +# your uplinks if linking to an already existent IRC network. +# +# You only need an ircd.conf (IRC server configuration file) if you are +# running an IRC server. If you are running a standalone client this file +# is not necessary. +# +# This file will explain the various lines in the IRC server +# configuration file. Not all lines are mandatory. You can check to make +# sure that your configuration file is correct by using the program +# "chkconf", provided in the server distribution (and when you do "make +# install" this program will be installed in the same directory as the irc +# server). +# +# The options for whether a line is needed or not are: +# MANDATORY: you absolutely MUST have this line +# NETWORKED: you must have this line if you are connecting this irc +# server to any other server (servers can run standalone). +# SUGGESTED: it is HIGHLY suggested that you use this line +# OPTIONAL: it's completely up to you whether to define this or not +# DISCOURAGED: you really really should not use this line if at all +# possible. +# NOT NECESSARY: an old or out of date line that isn't needed. +# +# +# ======================================================================== +# NOTE! this entire configuration file is read UPSIDE-DOWN! So if you have +# to put something in a specific order (for example, client-connection +# lines), put them in reverse order! +# ======================================================================== +# +# +############################ +# M: [MANDATORY]. This line sets your server's name, description and port +# the server listens for UDP pings (used to determine the fastest link in a +# class when autoconnecting) +# +# M:<Server NAME>:<YOUR Internet IP#>:<Geographic Location>:<Port> +# +# Note that 'server name' refers to the name of the irc-server which needs +# not to be the same as the hostname of the machine it's running on. +# +# this let's ircd use the primary ip of your host to establish connections +M:csa.bu.edu::Boston University Computer Science Department:6667 +# +# this let's ircd use the ip 128.197.13.20 to establish connections, useful +# if you're running virtual interfaces +#M:csa.bu.edu:128.197.13.20:Boston University Computer Science Department:6667 +# +# +############################ +# A: [MANDATORY]. This line lists your administrative information +# (contact address, etc). To view this information, /admin (server) will +# show it to you. +# +# A:<Your Name/Location>:<Your Electronic Mailing Addr>:<other information>:: +# +A:Boston University CS Department:Helen Rose <hrose@cs.bu.edu>:Client Server:: +# +# +############################ +# P: [MANDATORY]. This field allows the server to listen on various ports +# for connections. Any internet domain port that is below 1024 means the +# ircd has to be run as root, or from inetd. The server can listen to ports +# in the UNIX domain or the internet domain. If you wish to create a port +# in the UNIX domain you must compile with UNIXPORT defined in config.h. +# +# P:<YOUR Internet IP#>:<*>:<Internet IP Mask>:<Port>: +# P:<Directory>:<*>:<*>:<Port>: +# +# Note that it's a good idea to open some more ports than 6667 for +# server-server connections and local clients in case some running wild +# client blocks the default 6667. +# +# the default, an internet domain socket on port 6667 listening on all +# ip addresses of the machine running ircd +P::::6667: +# +# an internet domain socket listening on port 6668 on address 206.252.192.20 +# (again useful if you're running virtual interfaces) +P:206.252.192.20:::6668: +# +# an internet domain socket listening on port 6669 for connections from +# addresses matching 147.210.18.* : +P:::147.210.18.*:6669: +# +# This line is an example of a UNIX domain socket in /tmp +P:/tmp/.ircd:*:*:6666: +# +# +############################ +# Y: [SUGGESTED]. These lines define connection classes. Connection +# classes allow you to fine-tune your client and server connections. +# Since the fields have different meanings for server and client classes +# you shouldn't mix them, and if you have lots of server connections (if +# you do have lots of servers you shouldn't be reading this file :-) each +# set of servers (defined arbitrarily by you) should have its own class. +# If you have clients coming in from lots of different sites, you may want +# to seperate them out into classes. For instance, you may want to put +# local users in one class, with remote users in another class. You may also +# want to put limits on some client classes (one client only for indials +# for example). In any larger network you definitely want to do this. +# +# For SERVER CLASSES, the fields are: +# Y:<Class>:<Ping Frequency>:<Connect freq>:<Max Links>:<SendQ>:: +# 1 2 3 4 5 67 +# 1 class number +# 2 ping frequency (in seconds) +# 3 connect frequency (in seconds) +# 4 maximum number of automatically initiated links in this class +# 5 sendq (this overrides any MAXSENDQLENGTH set in config.h) +# 6 unused for server classes +# 7 unused for server classes +# +# The class numbers are not arbitrary. In auto-connecting servers -- that is, +# servers that you have a port number (e.g. 6667) on the end of the C: line +# (see below) the higher the number the higher the priority in auto-connecting. +# +# Note that it is a good idea to have ping frequency the same at both ends +# of the link. +# +# this is a normal server connection (normal as of October, 1997) +# Y:<Class>:<Ping Frequencys>:<Connect freq>:<Max Links>:<SendQ>:: +Y:2:90:300:1:4000000 +# +# +# For CLIENT CLASSES, the fields are: +# Y:<Class>:<Ping Frequency>::<Max Links>:<SendQ>:<Local Limit>:<Global Limit> +# 1 2 3 4 5 6 7 +# 1 class number +# 2 ping frequency (in seconds) +# 3 unused for client classes +# 4 maximum number of links in this class (per I line) +# 5 sendQ for each client +# 6 maximum number of links from this [user@]host on the server +# 7 maximum number of links from this [user@]host on the net +# +# local and global limits have the format <x>.<y> where x defines the maximum +# number of clients from the same host (IP) whereas y defines the maximum +# number of clients from the same user@host (IP) allowed to connect. the +# latter uses the identd replies to identify a user, falling back to an +# @host limit if no identd runs on the client and fails for identds generating +# dynamical answers. +# +# Note that any unset values default to zero which means 'unlimited'. +# +# Y:<Class>:<Ping Frequency>::<Max Links>:<SendQ>:<Local Limit>:<Global Limit> +# this is a class for multiuser systems allowing 10 local clients per host +Y:10:90::100:512000:10:32 +# +# this is a class for multiuser systems running a trustworthy identd +Y:11:90::100:512000:0.1:0.2 +# +# this is a class for single user systems (PCs, most indials, ...) +Y:12:90::100:512000:1:3 +# +# this is a class for remote systems you want to allow as fallback only +# (if you run an open server in a net you might really want this) +Y:13:90::100:512000:1:1 +# +# +############################ +# i/I: [MANDATORY]. The I: lines are client-authorization lines. Without +# these lines, no clients will be able to connect to your server. +# Wildcards ("*") are permitted. Passwords are also possible (clients can +# be configured to send passwords) but optional. 'I' allows full access, +# 'i' sets restricted mode which forbids nick changes and channel op status. +# +# I:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class> +# i:<TARGET Host Addr>:<Password>:<TARGET Hosts NAME>:<Port>:<Class> +# +# NOTE that ircd matches on the *right-most* match and doesn't stop matching +# after the <TARGET Hosts NAME> didn't match (see also examples below). +# +# Not that if <TARGET Hosts NAME> is empty ircd will show clients matching +# the <TARGET Host Addr> and do resolve as user@host. if an I:-line has both +# NAME and Addr defined and a client matches only the Addr part it will be +# shown as user@ip-address regardless if it does resolv or not. +# +# this would allow access for any client reaching this line which doesn't +# already have at least one connection to the net. if you run an open server +# in a net this might be the right choice, talk to your uplinks first anyway. +# resolving clients matching this line would be shown as user@host since +# the field <TARGET Hosts NAME> is empty. +# Note listing this i: line first, it will be read *last*, meaning it is +# the "fall-through". +#i:*@*::::13 +# With the password 'foobar' +#i:*@*:foobar:::13 +# Note that I:*::*.bu.edu:10 would also allow _all_ clients regardless +# if they're from *.bu.edu or not since ircd doesn't stop matching after the +# <TARGET Hosts NAME> didn't match. +# +# this would allow access for any client coming from *.net, *.org, *.com or +# other 3 char TLD +#i:::*@*.???:13 +# +# this allows access for any client from the ip block 192.168.0.0/16 +# regardless of its domain. if it's resolvable it will be shown as +# user@host since the field <TARGET Hosts NAME> is empty (useful to +# allow whole provider's blocks). +I:*@192.168.*::::12 +# +# This is a standard vanilla I: line which will permit anyone with an IP +# address starting with 128.197 OR with a hostname ending in .bu.edu to +# connect to the server. NOTE, the ircd matches on the *right-most* match, +# so if I connect as hrose@csa.bu.edu (which is hrose@128.197.10.3) I will +# show up on irc as hrose@csa.bu.edu since that is the first match it +# found. (Even though the second match is valid). +I:*@128.197.*::*@*.bu.edu::10 +# +# and you can even specify just certain usernames as long as the client's +# site is running a trustworthy ident daemon: +I:::hrose@csa.bu.edu::10 +# +# this will limit access for indials to one client per host +I:::*@ppp*.bu.edu::12 +I:::*@indial*.bu.edu::12 +# +# +############################ +# O: [OPTIONAL]. These lines define operator access. You do not need to +# have an operator to run a server. A well configured leaf site should not +# need an operator online, if it's connections are well defined, the irc +# administrator can use 'kill -HUP' on the ircd to reload the configuration +# file. +# +# O:<TARGET Host NAME>:<Password>:<Nickname>:<Port>:<Class> +# +# If the person in "Nickname" is not coming from the hostname defined in +# the first field then the person will get the error message "No O: lines +# for your host". +# +# Note that you don't need to use 'Nickname' to become operator, if you're +# using some other nick at that moment '/op Nickname' will do also. +# +O:*.bu.edu:Zaphod:Trillian::10 +# +# and this line forces ident match: +O:hrose@csa.bu.edu:Zaphod:Trillian::10 +# +# This line is a "local operator", it is specified with a lower-case "o" +# +# this line permits the nickname "jhs" with the password of "ITBites" to +# be a local operator only (be able to issue commands locally -- can /kill +# and /squit and /connect -- but *only* locally) +# +o:*.bu.edu:ITBites:jhs::10 +# +# a crypted password line (NOTE that if you have crypted passwords, *all* +# of you passwords must be crypted! In fact, if you are getting an error +# "Incorrect Password" it may well be because crypted passwords are +# defined and you have used plaintext. So my example of plaintext and +# crypted strings in the same IRC server configuration file is an +# impossibility (but it is just theoretical, which is why I explained both). +# +O:rocker@csa.bu.edu:T0eiVgHrqeKTQ:Rocker::10 +# +# +############################ +# c/C: [NETWORKED]. These lines define what servers your server tries to +# connect to. 'c' means your server will support compression for this link +# if you've compiled with zlib, 'C' will enforce an uncompressed link. +# N: [NETWORKED]. These lines define what servers your server permits +# to connect. +# +# c/N lines MUST be used in pairs. You cannot have one without the other. +# +# C:<TARGET Host Addr>:<Password>:<TARGET Server NAME>:<TARGET PORT>:<Class> +# c:<TARGET Host Addr>:<Password>:<TARGET Server NAME>:<TARGET PORT>:<Class> +# +# if the target server listens on different ports you can use for <TARGET PORT> +# <port_to_connect_to>.<port_target_server_listens_for_udp_pings>. +# <TARGET Host Addr> can be also an ip address or CNAME. +# +# N:<TARGET Host Addr>:<Password>:<TARGET Server NAME>:<Domain Mask>:<Class> +# +# "domain mask" is the number of parts in *your* hostname to mask to. For +# instance, with my servername being "csa.bu.edu", if I wanted to present +# my servername to be "*.bu.edu" I would have a host-mask portion of "1". +# +# it is *strongly* advised that your c/N line passwords be different for +# security's sake. +# +# ident is allowed in the server's hostname part of the field. +# these lines tell the server to automatically (note the port number, that +# means automatic connection) connect to cs-ftp.bu.edu: +C:hrose@cs-ftp.bu.edu:bigspark:cs-ftp.bu.edu:6667:2 +N:hrose@cs-ftp.bu.edu:bigalpha:cs-ftp.bu.edu::2 +# +# This server's connection lines are more vanilla, masking the host to +# *.bu.edu (as described above): +C:irc-2.mit.edu:camelsrk00l:irc-2.mit.edu::2 +N:irc-2.mit.edu:andsoarellamas:irc-2.mit.edu:1:2 +# +# If you have defined ZIP_LINKS and wish the connection to irc-2.mit.edu to +# be compressed, you need to use a lowercase c. If the other server refuses +# or doesn't support compression it will fall back to an uncompressed link. +c:irc-2.mit.edu:camelsrk00l:irc-2.mit.edu::2 +N:irc-2.mit.edu:andsoarellamas:irc-2.mit.edu:1:2 +# +# +############################ +# K: [OPTIONAL]. These lines define user@host patterns to be banned from +# this particular server (with an optional time field). Note that K: lines +# are *not* global, and if you ban a user they can still use any other IRC +# server (unless they have specifically been banned there as well). +# 'K' uses the the type unix reply from the client's identd if available or +# the USER information supplied by the client if not. 'k' uses the reply from +# the client's identd also if it's type other (it's prefixed with '-' then). +# +# K:<Host Name or IP>:<time interval(s)|comment>:<User>:<port>: +# k:<Host Name or IP>:<time interval(s)|comment>:<Auth>:<port>: +# +# wildcards are permitted in any one of the fields, in other words, you can +# K:*::* if you wanted (but your server wouldn't be used much ;-) +# +# Note that if you specify an IP address, or IP mask, it will match clients +# connecting from the matching addresses, no matter if they resolve or not. +# You can prefix an IP address or IP mask by '=' in which case only non +# resolving matching hosts will be banned. +# +# This k: line bans the username "FSSPR" (the wildcard is used to make +# sure that any ident-checking character will match) on any machine from +# the University of Alaska. +k:*.alaska.edu::*FSSPR:0 +# +# This K: line bans any users from acs*.bu.edu between the hours of 8am +# and 12pm and 1pm and 5pm (the time is always the server's local time): +# Note that 24 hour time is used (no "AM" or "PM"). +K:acs*.bu.edu:0800-1200,1300-1700:*:0 +# +# This K: line bans any users from *foo.edu sending them the notice +# "Use server irc.bar" instead of the default notice +# "You are not welcome to this server" +K:*foo.edu:Use server irc.bar:*:0 +# +# This K: line bans any users from *toto.fr from using the port 6667, +# and tells them to use port 6666 instead. +K:*toto.fr:Use port 6666:*:6667: +# +# This K: line bans any user from 129.69.0.0/16 as long the host doesn't run +# identd (no matter if it replies type unix or other) from all ports. +k:129.69.*:identd (rfc1413) required:unknown:: +# +# This does the same but only for unresolvable clients +k:=129.69.*:identd (rfc1413) required:unknown:: +# +# +############################ +# L: [OPTIONAL]. These lines "Leaf" specified servers. They are only +# useful if you are a non-leaf site yourself. There are two ways you can +# use L: lines. The first will limit one particular site to a particular +# tree depth (including 0, which would mean the server has to connect with +# no servers linked behind it otherwise the connection will fail). The +# second will allow you to be selective about which other servers you wish +# the connecting server to behave as a leaf towards. +# +# The fields are as follows: +# L:disallow connections to this hostmask::server name:depth +# For example, this will force kaja.gi.alaska.edu to connect only as a +# leaf (if it is not a leaf, the link will be dropped): +L:::kaja.gi.alaska.edu:: +# This line will force cm5.eng.umd.edu to have a depth of only 1 below it +# (that is, it is allowed to have only leaves connected to it): +L:::cm5.eng.umd.edu:1: +# +# This line will prohibit anything matching *.edu to be connected behind +# any server matching *.au: +L:*.edu::*.au:: +# +# +############################ +# H: [OPTIONAL]. These lines define who you permit to act as a "hub" to +# you (that is, who you permit to connect non-leafed servers to you). +# +# the first field may use wildcards, the third field *must* be an exact +# match for a server's name (NOT a server's hostname, if they differ, the +# server's name must be used). If the servername is a wildcard (e.g. *.au) +# that is an acceptable name for the third field. +# +# The fields are as follows: +# H:servers which are permitted entry::hub server +# +# Example, permit cs-ftp.bu.edu to allow any servers behind it to connect: +H:*::cs-ftp.bu.edu:: +# +# Example, permit irc-2.mit.edu to allow any MIT servers behind it to +# connect: +H:*.mit.edu::irc-2.mit.edu:: +# +# +############################ +# D: [OPTIONAL]. Control how auto connections are done. This will be mostly +# useful for networks with complex configurations. +# +# D:<Denied Server Mask>:<Denied Class>:<Server Mask>:<Server Class>: +# 1 2 3 4 +# +# If a server matching <Denied Server Mask> or a server in <Denied Class> +# is present ircd won't auto connect to any server matching <Server Mask> +# or being in <Server Class> although auto connect for those is active. +# +# Example, don't auto connect to *.fi if some server of *.edu is already +# linked +D:*.edu::*.fi:: +# +# Example, don't auto connect to *.fi or any server in class '3' if a +# server from our class '2' is already present +D::2:*.fi:3: +# +# +############################ +# V: [OPTIONAL]. These lines define restrictions on servers connecting to +# you. +# +# The first and third fields accept wildcards. The fields are as follow: +# V:<Version Mask>:<Flags>:<Server Mask>:: +# +# Example, you believe 2.9.1 is a really old version, and you want your +# peers to upgrade: +V:020901*::*:: +# +# If you are running a production network, you most likely don't want to +# allow servers compiled in DEBUGMODE which is a threat for the net +# as well as for the privacy of the users: +V:*:D:*:: +# +# Finally, you don't want *.edu servers to be version 2.9.2 *OR* to be +# compiled with remote oper kills enabled: +V:020902*:K:*.edu:: +# +# +############################ +# B: [SUGGESTED]. These lines define the alternate servers that the users +# will be redirected to if your server is full. +# +# The fiels are as follow: +# B:<Class|Host Mask>::<Server Name>:<Port>: +# +# For example, if you want to redirect your users to irc.stealth.net on port +# 6667 when your server is full, use: +B:-1::irc.stealth.net:6667: +# +# To redirect *.fi users when your server cannot accept any new user with +# a hostname matching *.fi, use: +B:*.fi::irc.funet.fi:6667: +# +# +############################ +# S: [OPTIONAL]. These lines define services allowed to connect to your +# server. Each service needs a separate line which only allows him to +# connect once. Remember to compile the ircd with #define USE_SERVICES +# in config.h, otherwise you can't use services. +# +# The fields are as follow: +# S:<TARGET Host Mask>:<Password>:<Service Name>:<Service Type>:<Class> +# +# Example, you want to allow a local information service: +S:eep.local.net:thisisapassword:EepInfo:0:1 +# +# Another example, ircd versions since 04/10/1999 support also a hex +# mask. This is a temporary kline service (tkserv) as you can find it in +# contrib/tkserv : +S:eep.local.net:thisisapassword:TkEep:0x2000000:1 +# +# +############################ +# U: [NOT NECESSARY]. This line defines the default server for the IRC +# client that ships with the server -- the default client is in irc/irc +# You should not use U: lines but instead use the UPHOST definition in +# config.h +U:csa.bu.edu:foobar:csa.bu.edu +# +# +############################ +# R: [DISCOURAGED]. These lines restrict user access based on a more +# stringent checking system than is available in the K: line. It looks for +# a match (based on hostname and username) and then runs an outside +# program (which MUST be specified using a full pathname). The output of +# the program should be a string in the form "Y <message>" (which permits +# access for the user) or "N <message>" (which denies access for the +# user). If "Y <message>" is received by the server, the server ignores +# the message and permits access for the user. If "N <message>" is +# returned, the server tells the user that he/she is not permitted to +# access that irc server, and gives the reason. +# +# Again, like K: lines, R: lines are local and thus not very effective in +# blocking certain machines from having IRC access. +# +# Use of R: requires that you have defined R_LINES in config.h +# +# The fields are as follows: +# R:hostmask:/full/path/to/program:username +# you can use wildcards in either the hostmask or username portion +# +R:csl.bu.edu:/home/hrose/bin.sun3/sun3access:*:: +# +# +############################ +# Q: [DISCOURAGED]. These lines "quarantine" specified servers. Because +# of the way they operates, the same Q: lines MUST be installed by +# everyone or the net will keep breaking. I CANNOT EMPHASIZE THIS ENOUGH. +# Do NOT use Q: lines lightly! +# +# The fields are as follows: +# Q:*:reason why quarantine is in place:servername +# +Q::this server is too slow and lags the net:cm5.eng.umd.edu:: diff --git a/doc/iauth-internals.txt b/doc/iauth-internals.txt new file mode 100644 index 0000000..ccfa8e8 --- /dev/null +++ b/doc/iauth-internals.txt @@ -0,0 +1,350 @@ + Internal IAUTH Workings + ======================= + + Andrew Snare + +Introduction +------------ + +The iauth daemon was written to offload some aspects of authenticating +incoming ircd connections. Using a modular design, the original +modules provides for identd lookup of incoming connections as well as +checking for open socks proxies. + +When the ircd starts up, the iauth process is started as a slave +process. The ircd communicates with the iauth daemon about new +connections, and the iauth slave communicates information back as it +becomes available. + +Communication Protocol +---------------------- + +IRCD Messages:- + +The communication protocol used to communicate from ircd to iauth is +line-based and has the following form: + + <id> <category> <information> + + * <id> is used to identify the connection the information + concerns, and consists of the ircd's file-descriptor for the + connection. + + * <category> is a single letter used to denote the type of + information being sent. + + * <information> is the rest of the line ("\n"-terminated), + whose format depends on the category of information. + +Categories: + + - "C" + + Denotes a new connection to start on. The information has the + form of <remote-ip> <remote-port> <local-ip> <local-port>. Eg: + + 2 C 192.168.2.10 13578 192.168.1.1 6667 + + This indicates a connection has been received on port 6667 + with local IP-address of 192.167.1.1. The remote IP-address + was 192.168.2.10 (port 13578). + + - "O" + + Denotes an update to information about an existing + connection. The format of this is identical to a C-message (as + described above). + + - "D" + + Denotes a client has disconnected. No extra information is + provided. Eg: + + 2 D + + - "R" + + This denotes a change of identifier for a client. The reason + for this currently is that sometimes ircd can re-map + file-descriptors (used as the identifier). The format of the + information is <new identifier>. Eg: + + 2 R 1 + + This indicates the client that was on file-descriptor 2 is now + on file-descriptor 1 (unlikely, I'm sure!:). + + - "N" + + This denotes information has been received about the hostname + of a client. Format of the information is <hostname>. Eg: + + 2 N host.example.com + + This indicates the hostname of that client is + host.example.com. + + - "d" + + This denotes a DNS lookup for the client has timed out or + failed. This message has no other information. Eg: + + 2 d + + - "A" * + + This denotes a host alias for the connection. Currently this + message is ignored by iauth and any information discarded. + + - "U" + + This denotes the username information provided by a + client. This information cannot be trusted, and is only used + by ircd when an identd lookup has failed. Format of the + information is <username>. Eg: + + 2 U earthpig + + This indicates the client supplied "earthpig" as the username + in the USER line during client handshaking with ircd. + + - "P" + + This denotes password information supplied by the client. Eg: + + 2 P uhuh + + This indicates the user supplied a password of "uhuh" during + client handshaking with ircd. A "U" message will always + immediately follow this message. + + - "T" + + This denotes the ircd is registering a client, which will + usually only occur if iauth has taken too long to get back + to ircd with a response. This message has no other + information. Eg: + + 2 T + + - "E" * + + This denotes an error message from ircd. The information + provided has the form of <error message>. Eg: + + 2 E I am a teapot. + +IAUTH Messages: + +The communication protocol used to communicate from iauth to ircd is +line-based and has the following form: + + <category> <information> + + * <category> is a single letter used to denote the type of + information being sent. + + * <information> is the rest of the line ("\n"-terminated), + whose format depends on the category of information. + + - ">" + + This is used to by iauth to send messages to &AUTH. + + - "G" + + This is used by iauth to set up debugging feedback from + ircd. Eg: + + G 1 + + - "O" + + This is used by iauth to tell ircd of some global iauth + policy decisions. Valid <information> includes the letters + "R", "T", "A" and "W" only. Eg: + + O RTA + + Valid policy types are: + R -- All clients _must_ be authenticated by iauth + to be allowed through; + T -- The IRC server should not accept new user + connections if iauth hasn't finished its work; + A -- The IRC server should send additional information + to iauth, such as a client-supplied password; + W -- Extra time should be allowed for requests + (usually to allow for hostname information to + become available). + + - "a" + + This indicates that iauth is reading a new configuration + file. Eg: + + a + + - "A" * + + This is used to describe the iauth configuration as it is + read. The information consists of <hosts?> <module name> + <options>. Eg: + + A * rfc931 + + This means that the rfc931 (identd) module is invoked for + every connection, and no options were given. + + - "s" * + + This is used to denote that any recorded statistics on iauth + should be reset. Eg: + + s + + - "S" + + This is used to send iauth statistics. The information has the + form of <module name> <module-specific information>. Eg: + + S rfc931 connected 0 unix 0 other 0 bad 0 out of 0 + + This indicates some statistics from the rfc931 module. + + - "U" * + + This is used to send username information (returned by identd) + to the ircd. This corresponds to information that has been + deemed usable to ircd by iauth. The information has the form + of <identifier> <remote IP> <remote port> <username>. Eg: + + U 2 192.168.2.10 13578 earthpig + + - "u" * + + This is used to send username information (returned by identd) + to the ircd. This corresponds to information that has been not + deemed usable to ircd by iauth, usually due to the type of + reply received from identd. The information has the form of + <identifier> <remote IP> <remote port> <username>. Eg: + + u 2 192.168.2.10 13578 earthpig + + - "K" + + This is used to indicate a client should be killed. The + information provided is of the form <identifier> <remote IP> + <remote port>. Eg: + + K 2 203.36.167.162 13578 + + - "k" + + This is used to indicate a client should be killed. The + information provided is the same as for the above "K" message + with the exception that this version is "quieter". ie, The + ircd won't be as verbose about the client being rejected. + + - "D" + + This is used to indicate that iauth's processing of a client + has finished. The information provided is of the form <id> + <remote IP> <remote port>. Eg: + + D 2 203.36.167.162 13578 + + - "r" * + + This is used by iauth to indicate it is shutting down. No + extra information is provided. Eg: + + r + +Items marked with a * may be incorrect or contain uncertain +information. + +Module Processing +----------------- + +Module processing is done in a linear manner, one module at a +time. When one module indicates it is finished with the client, iauth +starts the next module on it. However, the matter is complicated +slightly in that multiple passes can be made through the list of +modules. By default each module is given 15 seconds to complete its +work on a given client, before it gets timed-out. + +The first pass commences immediately when ircd notifies iauth of a +client to check. A new pass commences: + +1) When DNS information about the client's hostname is finalised. + +2) When the USER information supplied by the client becomes available. + +Earlier versions of iauth did not commence a subsequent pass if DNS +information was not available, but the current version starts one +regardless. + +All modules are by default included in the first pass, with unused +modules being included in the second pass if it commences prior to +them being invoked. Modules are deferred to the second pass if they +were configured using the "host = " directive (unless a "ip = " option +was also specified and matched). There is a special case of "host = *" +which forces a module to be delayed until hostname information is +known, where it will always be invoked. + +Module Interface +---------------- + +The default modules are statically linked into the iauth +daemon. However, there are now provisions for dynamically-loadable +modules, as described by the iauth.conf man-page. Regardless of how +they are linked/loaded, modules are currently expected to export the +following functions (and array): + +char *name_init(AnInstance *self); +void name_release(AnInstance *self); +void name_stats(AnInstance *self); +int name_start(u_int client); +int name_work(u_int client); +int name_timeout(u_int client); + +aModule Module_name = + { "name", name_init, name_release, name_stats, + name_start, name_work, name_timeout, name_clean }; + +By convention the exported symbols use the form "name_symbol" where +"name" is replaced by the module's name. For modules that are linked +statically, a reference to Module_name must be added to the MList +array near the start of conf_read() in a_conf.c + +For examples of what the exported functions are expected to do, please +refer to the (internally documented) modules included in iauth. + +Limitations +----------- + +Currently iauth suffers from several limitations. It is hoped that in +the future these will be fixed. Patches are welcome. :) These +limitations (in rough order of importance) are: + +1) After ircd has registered a client, iauth cannot reject or kill a +connection. It is strongly desired that this be fixed. + +2) There is no way for a module to specify the "reason" a client +connection was rejected (for display or other purposes). + +3) The current module design assumes a separate TCP/IP connection is +required for each client check (or at least separate file-descriptors +for each client can be watched for activity). While it's possible +tricks could be used to work around this assumption, it has not been +successfully done yet. + +Document Availability and Maintainence +-------------------------------------- + +This document was originally written by Andrew Snare and may contain +errors and/or omissions. Please send any corrections to +ajs@pigpond.com for inclusion in future versions. An up-to-date +version of this document is available on the web at: + + http://www.pigpond.com/~earthpig/iauth-internals.txt diff --git a/doc/iauth.8 b/doc/iauth.8 new file mode 100644 index 0000000..14a415a --- /dev/null +++ b/doc/iauth.8 @@ -0,0 +1,54 @@ +.\" @(#)$Id: iauth.8,v 1.4 1998/11/09 20:07:12 kalt Exp $ +.TH IAUTH 8 "$Date: 1998/11/09 20:07:12 $" +.SH NAME +iauth \- The Internet Relay Chat Authentication Program +.SH SYNOPSIS +.hy 0 +.IP \fBiauth\fP +[ +.B -v +| +.BI \-c " configfile" +] +.SH DESCRIPTION +.LP +\fIiauth\fP is a slave process used by the \fIircd\fP program to perform +the authentication of incoming connections. The \fIircd\fP program starts +\fIiauth\fP upon startup. + +\fIiauth\fP will close and reopen the log file whenever it receives a user +signal 2, SIGUSR2. This is useful to rotate the log file. +.SH OPTIONS +.TP +.BI \-c " filename" +When this flag is given, the program will read the configuration file +specify and validate it. This is useful to check for errors in the setup. +.TP +.B \-v +This option dumps information about the version. +.SH EXAMPLE +.RS +.nf +millennium% \fBiauth -c iauth.conf\fP +iauth 2.10 + +Reading "iauth.conf" + +Module(s) loaded: + rfc931 +.fi +.RE +.SH COPYRIGHT +(c) 1998 Christophe Kalt +.LP +For full COPYRIGHT see LICENSE file with IRC package. +.LP +.RE +.SH FILES + "iauth.conf" +.SH "SEE ALSO" +iauth.conf(5) ircd(8) +.SH BUGS +None... ;-) if somebody finds one, please send mail to ircd-bugs@irc.org +.SH AUTHOR +Christophe Kalt. diff --git a/doc/iauth.conf.5 b/doc/iauth.conf.5 new file mode 100644 index 0000000..832d9a8 --- /dev/null +++ b/doc/iauth.conf.5 @@ -0,0 +1,159 @@ +.\" @(#)$Id: iauth.conf.5,v 1.16 1999/07/04 22:09:09 kalt Exp $ +.TH IAUTH.CONF 5 "$Date: 1999/07/04 22:09:09 $" +.SH NAME +iauth.conf \- The Internet Relay Chat Authentication Configuration File +.SH DESCRIPTION +.LP +The \fIiauth.conf\fP file is read by the \fIiauth\fP program upon startup, +it contains the list of modules that should be used to authenticate a +particular connection. The list is ordered, which means that the first +module to successfully authenticate a connection will be the last to be +tried. + +The file is divided in sections, the first section is used for iauth +options, each subsequent section specifies a module with eventual options +using the following format: + +.RS +.nf +module\ \fImodule-name\fP +[TAB]option = \fIstring\fP +[TAB]host = \fIhost-name\fP +[TAB]ip = \fIip-address\fP +[TAB]timeout = \fIvalue\fP + +.fi +.RE +The section ends with an empty line. The \fImodule-name\fP defines which +module the section applies to. A particular module may be used in several +sections. A \fIstring\fP of undefined format may be specified, it will +then be passed to the module upon initialization, see the MODULES section +to find out if a module accepts any option. + +If \fIhost-name\fP and \fIip-address\fP fields are specified, then the +module will only be used for connections matching one of the fields given +in the configuration. An entry prefixed with the character ! indicates a +negative match. IP addresses are checked first. + +If no host nor ip entry is specified, then the module will always be used. + +When writing a configuration file, one should \fBalways\fP verify the +syntax using the \fIiauth\fP program to avoid later problems. +.SH IAUTH OPTIONS +.TP +.B timeout = <seconds> +This allows to specify how much time each module has to complete its work +for each connection. This option can also be specified individually for +each module. The default is 30 seconds. +.TP +.B required +By specifying this keyword, the IRC server is told not to accept new user +connections unless the authentication is handled by \fIiauth\fP. This does +NOT mean that the server will wait forever to get the data from iauth, see +the \fInotimeout\fP option. +.TP +.B notimeout +By specifying this keyword, the IRC server is told not to accept new user +connections if \fIiauth\fP hasn't finished its work in time. +.TP +.B extinfo +This keyword allows extra information (user supplied username, and +eventually password) to be received by \fIiauth\fP from the server. This +is only useful is a module using this information is loaded. +.TP +.B shared <name> <mod_name.so> +If iauth was compiled with Dynamically Shared Module support, it can be +told to dynamically load a module using this option. The module can then +be loaded. +.SH MODULES +.TP +.B pipe +This module is provided as a replacement to the (now obsolete) R +configuration lines supported by the IRC daemon. It runs an external +program with the client IP and port as arguments. The program should +output either 'Y' (Yes, let the client in), or 'N' (No, don't let them +in). + +Note that this module is quite expensive as it forks a separate process for +each connection received by the IRC daemon. + +This module requires the following option: +.B prog=/path/to/external/program +.TP +.B socks +This module performs a basic check to verify that the host where the +connection originated from doesn't run a SOCKS v4 or v5 proxy server on +port 1080 that is open to the world. It is useful to reject abusive +clients using a relay to evade kill lines and bans. + +This module understands seven options: +.B reject +to reject connections originating from a host where an open proxy +was detected, +.B log +to log hostnames where an open proxy is detected. +.B paranoid +to consider proxies which deny the request because of a userid/ident +mismatch to be OPEN proxies. +.B cache[=value] +to set the cache lifetime in minutes. By default, caching is enabled for +30 minutes. A value of 0 disables caching. +.B careful +to make sure socks v5 is properly configured with IP rulesets. Without +this parameter, module will not send additional query and assume first +positive answer as valid. +.B v4only +to check only socks v4. +.B v5only +to check only socks v5. +.TP +.B rfc931 +This module is for authentication TCP connections using the protocol +defined in RFC 1413 (which obsoletes RFC 931). It is always loaded, and +does not recognize the \fIhost\fP nor \fIip\fP fields. +.TP +.B lhex +This module acts as a proxy, communicating with a LHEx server to perform +authentication of client connections. It takes a single (mandatory) +option, which is the IP-address of the LHEx server to use. +.SH EXAMPLE +The following file will cause the IRC daemon to reject all connections +originating from a system where an open proxy is running for hosts within +*.fr and *.enserb.u-bordeaux.fr but not for other hosts matching +*.u-bordeaux.fr. For all connections, an ident lookup (RFC 1413) will be +performed. In addition, every connection is authenticated with the LHEx +server at IP-address 127.0.0.1. + +.RS +.nf +module socks + option = reject,paranoid + host = *.enserb.u-bordeaux.fr + host = !*.u-bordeaux.fr + host = *.fr + +module rfc931 + +module lhex + option = 127.0.0.1 +.fi +.RE +.SH CAVEATS +When the option +.B extinfo +is set, connections registering as a server or a service with the IRC +server are not guaranteed to receive the "user" authentication provided by +modules (such as the rfc931 module). +.RE +.SH COPYRIGHT +(c) 1998,1999 Christophe Kalt +.LP +For full COPYRIGHT see LICENSE file with IRC package. +.LP +.RE +.SH FILES +"iauth.conf" +.SH "SEE ALSO" +iauth(8) +.SH AUTHOR +Christophe Kalt. diff --git a/doc/irc.1 b/doc/irc.1 new file mode 100644 index 0000000..d8dd677 --- /dev/null +++ b/doc/irc.1 @@ -0,0 +1,85 @@ +.\" @(#)$Id: irc.1,v 1.5 1998/12/13 00:02:34 kalt Exp $ +.TH IRC 1 "$Date: 1998/12/13 00:02:34 $" +======= +.\" @(#)$Id: irc.1,v 1.5 1998/12/13 00:02:34 kalt Exp $ +.TH IRC 1 "$Date: 1998/12/13 00:02:34 $" +.SH NAME +irc \- User Interface to Internet Relay Chat Protocol +.SH SYNOPSIS +\fBirc\fP [\fB-p\fP \fIportnum\fP] [\fB-c\fP \fIchannel\fP] [ \fInickname\fP [ \fIserver\fP ]] +.SH DESCRIPTION +.LP +\fBIrc\fP is a user interface to the Internet Relay Chat, a CB-like +interactive discussion environment. It is structured into \fIchannels\fP, +which are public discussion forums, and also allows for private intercommunication. +Each participant has a \fInickname\fP, which is the one specified in the command +line or else his login name. +.LP +Once invoked, \fBirc\fP connects as a client to the specified server, +\fIserver\fP or to the default one (see below). The screen splits into a dialogue +window (the major part +of the screen) and a command line, from which messages can be sent and +commands given to control irc. +.SH COMMAND SYNTAX +The syntax of irc commands is of the form \fB/COMMAND\fP. The most notable +ones are listed below. For an uptodate list, use the \fBHELP\fP command +of \fBirc\fP. Case is ignored. +.IP "\fB/ADMIN\fR [\fIserver\fP]" +Prints administrative information about an IRC \fIserver\fP. +.IP "\fB/AWAY\fP [\fImessage\fP]" +Mark yourself as being away (with an automatic reply \fImessage\fP +if specified) +.IP "\fB/BYE\fR, \fB/EXIT\fR, \fB/QUIT\fR" +Terminate the session +.IP "\fB/CHANNEL\fR [\fIchannel\fP]" +Join another \fIchannel\fP +.IP "\fB/CLEAR\fR" +Clear the screen +.IP "\fB/HELP\fR [\fIcommand\fP]" +Display a brief description of the \fIcommand\fP (or list all commands, if none +specified). +.IP "\fB/SUMMON\fR \fIuser\fP" +Allows to summon a \fIuser\fP specified as a full Internet address, i.e., +\fIlogin@host.domain\fP, to an IRC dialogue session (in much the same +way as the talk(1) command). It is usable ONLY if the irc daemon runs on +the target machine (host.domain). +.IP "\fB/TOPIC\fR \fItopic\fP" +Sets the \fItopic\fP for the current channel +.IP "\fB/WHO\fR [\fIchannel\fP|*]" +Lists all users of IRC if no argument, of the specified \fIchannel\fP or of the +current channel (*). +.SH ARGUMENTS +.IP "\fB-p\fP \fIportnum\fP" +TCP/IP "port number. Default is 6667 and this option should seldom if ever" +be used. +.IP "\fB-c\fP \fIchannel\fP" +\fIChannel\fP number to join upon beginning of the session. Default is no channel. +.IP "\fInickname\fP" +\fINickname\fP used in the session (can be changed with the \fB/NICK\fP command). +Default is user login name. +.IP "\fIserver\fP" +\fIServer\fP to connect to. Default is specified in the irc system configuration +file, and can be superseded with the environment variable IRCSERVER. +.SH EXAMPLE +.RS +.nf +tolmoon% \fBirc -p6667 Wizard tolsun\fP +.fi +.RE +.LP +connects you to irc server in host tolsun (port 6667) with nickname Wizard +.SH COPYRIGHT +Copyright (c) 1988 University of Oulu, Computing Center, Finland. +.nf +Copyright (c) 1988,1989,1990 Jarkko Oikarinen +.nf +All rights reserved. +For full COPYRIGHT see LICENSE file with IRC package. +.SH "SEE ALSO" +ircd(8) +.SH BUGS +What bugs ? +.SH AUTHOR +Jarkko Oikarinen <jto@tolsun.oulu.fi> +.nf +Manual page updated by Michel Fingerhut <Michel.Fingerhut@ircam.fr> diff --git a/doc/ircd.8 b/doc/ircd.8 new file mode 100644 index 0000000..2727815 --- /dev/null +++ b/doc/ircd.8 @@ -0,0 +1,202 @@ +.\" @(#)$Id ircd.8 2.0 (beta version) 29 Mar 1989 $ +.TH IRCD 8 "$Date: 1999/04/08 22:12:19 $" +.SH NAME +ircd \- The Internet Relay Chat Program Server +.SH SYNOPSIS +.hy 0 +.IP \fBircd\fP +[ +.B \-abcioqst +] [ +.BI \-f " configfile" +] [ +.BI \-x " debuglevel" +] [ +.BI \-h " hostname" +] [ +.BI \-T " tunefile" +] [ +.BI \-p " mode" +] +.IP \fBircd\fP +.B \-v +.SH DESCRIPTION +.LP +\fIircd\fP is the server (daemon) program for the Internet Relay Chat +Program. The \fIircd\fP is a server in that its function is to "serve" +the client program \fIirc(1)\fP with messages and commands. All commands +and user messages are passed directly to the \fIircd\fP for processing +and relaying to other ircd sites. The \fIirc(1)\fP program depends upon +there being an \fIircd\fP server running somewhere (either on your local +UNIX site or a remote ircd site) so that it will have somewhere to connect +to and thus allow the user to begin talking to other users. + +\fIircd\fP will reread its configuration file whenever it received a hangup +signal, SIGHUP. + +Sending an interrupt signal to \fIircd\fP process will cause it to restart. + +.SH OPTIONS +.TP +.B \-a +Instructs the server to automatically die off if it loses all it's clients. +.TP +.B \-b +If the ircd.tune file is corrupted, by default the server +will not start. This option will make the server start +anyways, with the default values (ignoring the corrupted +file). +.TP +.B \-c +This flag must be given if you are running ircd from \fI/dev/console\fP or +any other situation where fd 0 isnt a tty and you want the server to fork +off and run in the background. This needs to be given if you are starting +\fIircd\fP from an \fIrc\fP (such as \fI/etc/rc.local\fP) file. +.TP +.B \-i +The server was started by inetd and it should start accepting connections +from standard input. The following inetd.conf-line could be used to start +up ircd automatically when needed: +.TP +.B +ircd stream tcp wait irc /etc/ircd ircd \-i + +allows inetd to start up ircd on request. +.TP +.B \-o +Starts up a local ircdaemon. Standard input can be used to send IRC +commands to the daemon. The user logging in from standard input will +be given operator privileges on this local ircd. If ircd is a setuid program, +it will call setuid(getuid()) before going to local mode. This option +can be used in inetd.conf to allow users to open their own irc clients +by simply connecting their clients to the correct ports. For example: +.TP +.B +irc stream tcp nowait irc /etc/ircd ircd \\-f/etc/ircd.conf \\-o + +allows users connecting to irc port (specified in /etc/services) to start +up their own ircdaemon. The configuration file should be used to check from +which hosts these connections are allowed from. This option also turns +on the autodie option -a. +.TP +.B \-q +Using this option stops the server from doing DNS lookups on all the +servers in your \fIircd.conf\fP file when it boots. This can take a lengthy +amount of time if you have a large number of servers and they are not all +close by. +.TP +.B \-s +When this option is specified, \fIiauth\fP will not be +started. This means that the IRC daemon will perform "ident +lookups" (RFC 1413) internally to attempt to authenticate +incoming connections. No other authentication mechanism +will be used. +.TP +.B \-t +Instructs the server to direct debugging output to standard output. +.TP +.BI \-f " filename" +Specifies the ircd.conf file to be used for this ircdaemon. The option +is used to override the default ircd.conf given at compile time. +.TP +.BI \-x " #" +Defines the debuglevel for ircd. The higher the debuglevel, the more stuff +gets directed to debugging file (or standard output if -t option was used +as well). +.TP +.BI \-h " hostname" +Allows the user to manually set the server name at startup. The default +name is hostname.domainname. +.TP +.BI \-p " mode" +Specify whether the server should enable built-in +protections against various type of user abuse that is +commonly found on big public networks. Possible modes are +.BR strict " (default)," +.BR on " and" +.BR off . +The +.B strict +option enables the protections, and refuses to establish a +link to a server not running with this option. This is +useful to force all servers on an IRC network to enable +them. +.TP +.BI \-T " tunefile" +Specifies the ircd.tune file to be used for this ircdaemon. The option +is used to override the default ircd.tune given at compile +time. +.TP +.B \-v +This option prevents the server from starting, and dumps +some information about the version instead. +.TP +.SH +If you plan to connect your \fIircd\fP server to an existing Irc-Network, +you will need to alter your local IRC CONFIGURATION FILE (typically named +"ircd.conf") so that it will accept and make connections to other \fIircd\fP +servers. This file contains the hostnames, Network Addresses, and sometimes +passwords for connections to other ircds around the world. Because +description of the actual file format of the "ircd.conf" file is beyond the +scope of this document, please refer to the file INSTALL in the IRC source +files documentation directory. +.LP +BOOTING THE SERVER: The \fIircd\fP server can be started as part of the +UNIX boot procedure or just by placing the server into Unix Background. +Keep in mind that if it is *not* part of your UNIXES Boot-up procedure +then you will have to manually start the \fIircd\fP server each time your +UNIX is rebooted. This means if your UNIX is prone to crashing +or going for for repairs a lot it would make sense to start the \fIircd\fP +server as part of your UNIX bootup procedure. In some cases the \fIirc(1)\fP +will automatically attempt to boot the \fIircd\fP server if the user is +on the SAME UNIX that the \fIircd\fP is supposed to be running on. If the +\fIirc(1)\fP cannot connect to the \fIircd\fP server it will try to start +the server on it's own and will then try to reconnect to the newly booted +\fIircd\fP server. +.SH EXAMPLE +.RS +.nf +tolsun% \fBircd\fP +.fi +.RE +.LP +Places \fIircd\fP into UNIX Background and starts up the server for use. +Note: You do not have to add the "&" to this command, the program will +automatically detach itself from tty. +.LP +.RS +.nf +tolsun% \fBircd \-v\fP +ircd 2.9.3 AaCDEfFHiIkMsu_V1 + zlib not used + Tue Apr 1 1997 at 20:17:50 EDT #1 +.fi +.RE +.LP +This indicates that this binary is the version 2.9.3 of the +software. AaCDEfFHiIkMsu_V1 are the compile time options +which were used. This binary does not support compression +of server\-server links (does not use zlib) and was compiled +on April the 1st. +.SH COPYRIGHT +(c) 1988,1989 University of Oulu, Computing Center, Finland, +.LP +(c) 1988,1989 Department of Information Processing Science, +University of Oulu, Finland +.LP +(c) 1988,1989,1990,1991 Jarkko Oikarinen +.LP +For full COPYRIGHT see LICENSE file with IRC package. +.LP +.RE +.SH FILES + /etc/utmp + "ircd.conf" +.SH "SEE ALSO" +iauth(8) irc(1) ircdwatch(8) +.SH BUGS +None... ;-) if somebody finds one, please send mail to ircd-bugs@irc.org +.SH AUTHOR +Jarkko Oikarinen, currently jto@tolsun.oulu.fi, +manual page written by Jeff Trim, jtrim@orion.cair.du.edu, +later modified by jto@tolsun.oulu.fi. diff --git a/doc/m4macros b/doc/m4macros new file mode 100644 index 0000000..2cc17d3 --- /dev/null +++ b/doc/m4macros @@ -0,0 +1,48 @@ +# @(#)$Id: m4macros,v 1.2 1997/04/21 13:50:04 kalt Exp $ + +The following macros are included in "ircd.m4" for use with the m4 text +preprocessor. "ircd.m4" is parsed before the IRC server conf file so they +are all available for use with that. + +NOTE: The "ircd.m4" file is *ONLY* created by a "make install". + +VERSION - current version string as in patchlevel.h +DEBUGMODE - if DEBUGMODE is define in config.h, is also defined for m4. +HOSTNAME - taken from hostname(1) +USER - username of person doing the "make install" +PORT - default port number as in config.h +PFREQ - default ping frequency as in config.h +CFREQ - default connect frequency as in config.h +MAXSENDQ - default max sendq as in config.h +CL - use this to wrap a class number +HOST - use this to wrap a hostname +HOSTM - use this to wrap the hostmask number in N-lines +ID - when wrapping the host field in an I-line, causes ident string return + to be used instead of user supplised username. +PASS - use this to wrap passwords in C/N/I/O lines +PING - use this to wrap the ping value in Y-lines +APORT - use this to wrap the port number in I-lines +CPORT - use this to wrap the port number in C-lines +SERV - use this to wrap server names + +You might use some of these as +C:foo.bar.edu:PASS(boo):foo.bar.edu:APORT(6667) +I:ID(128.250.*)::ID(*.mu.oz.au):CPORT(6667) + +In addition to these (rather weak macros), some more complete ones are +defined which already perform the above. + +ADMIN - provide fields to it as you would an A-line +ALLOW - provide fields to it as you would an N-line +BAN - provide fields to it as you would an K-line +CLASS - provide fields to it as you would an Y-line +CLIENT - provide fields to it as you would an I-line +CONNECT - provide fields to it as you would an C-line +ME - provide fields to it as you would an M-line +HUB - first parameter is server you want to hub, second is optional and is + a mask against which other servers introduced must match against. +LEAF - works like HUB, except that the mask is matched against server names + to check if the link should be dropped. +SERVER - uses 6 fields, the first 4 as are found in an N-line, the last two + should be as you would use in a C-line. It expands out to provide + both a C and N line. diff --git a/iauth/a_conf.c b/iauth/a_conf.c new file mode 100644 index 0000000..602ab53 --- /dev/null +++ b/iauth/a_conf.c @@ -0,0 +1,548 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_conf.c + * Copyright (C) 1998 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: a_conf.c,v 1.21 1999/07/11 22:11:33 kalt Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define A_CONF_C +#include "a_externs.h" +#undef A_CONF_C + +static aModule *Mlist[16]; + +#define DEFAULT_TIMEOUT 30 + +u_int debuglevel = 0; + +AnInstance *instances = NULL; + +static void +conf_err(nb, msg, chk) +u_int nb; +char *msg, *chk; +{ + if (chk) + printf("line %d: %s\n", nb, msg); + else + sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR, + "Configuration error line %d: %s", nb, msg); +} + +/* + * Match address by #IP bitmask (10.11.12.128/27) + */ +static int +match_ipmask(mask, ipaddr) +aTarget *mask; +char *ipaddr; +{ +#ifdef INET6 + return 1; +#else + int i1, i2, i3, i4; + u_long iptested; + + if (sscanf(ipaddr, "%d.%d.%d.%d", &i1, &i2, &i3, &i4) != 4) + return -1; + iptested = htonl(i1 * 0x1000000 + i2 * 0x10000 + i3 * 0x100 + i4); + return ((iptested & mask->lmask) == mask->baseip) ? 0 : 1; +#endif +} + +/* conf_read: read the configuration file, instanciate modules */ +char * +conf_read(cfile) +char *cfile; +{ + AnInstance *ident = NULL; /* make sure this module is used */ + u_char needh = 0; /* do we need hostname information for any host? */ + u_char o_req = 0, o_dto = 0, o_wup = 0; + static char o_all[5]; + u_int timeout = DEFAULT_TIMEOUT, totto = 0; + u_int lnnb = 0, i; + u_char icount = 0, Mcnt = 0; + char buffer[160], *ch; + AnInstance **last = &instances, *itmp; + FILE *cfh; + + Mlist[Mcnt++] = &Module_rfc931; + Mlist[Mcnt++] = &Module_socks; + Mlist[Mcnt++] = &Module_pipe; + Mlist[Mcnt++] = &Module_lhex; + Mlist[Mcnt] = NULL; + + cfh = fopen((cfile) ? cfile : IAUTHCONF_PATH, "r"); + if (cfh) + { + while (fgets(buffer, 160, cfh)) + { + if (ch = index(buffer, '\n')) + lnnb += 1; + else + { + conf_err(lnnb, "line too long, ignoring.", + cfile); + /* now skip what's left */ + while (fgets(buffer, 160, cfh)) + if (index(buffer, '\n')) + break; + continue; + } + if (buffer[0] == '#' || buffer[0] == '\n') + continue; + *ch = '\0'; + if (ch = index(buffer, '#')) + *ch = '\0'; + if (!strncmp("required", buffer, 8)) + { + o_req = 1; + continue; + } + if (!strncmp("notimeout", buffer, 9)) + { + o_dto = 1; + continue; + } + if (!strncmp("extinfo", buffer, 7)) + { + o_wup = 1; + continue; + } + if (!strncmp("timeout = ", buffer, 10)) + { + if (sscanf(buffer, "timeout = %u", + &timeout) != 1) + conf_err(lnnb, "Invalid setting.", + cfile); + continue; + } + /* debugmode setting */ + if (!strncmp("debuglvl = 0x", buffer, 13)) + { + if (sscanf(buffer, "debuglvl = %x", + &debuglevel) != 1) + conf_err(lnnb, "Invalid setting.", + cfile); + else if (!cfile) + sendto_log(ALOG_DCONF, LOG_DEBUG, + "debuglevel = %X", + debuglevel); + continue; + } +#if defined(USE_DSM) + if (!strncmp("shared ", buffer, 7)) + { + char lfname[80]; + void *mod_handle; + aModule *(*load_func)(); + + ch = index(buffer+7, ' '); + if (ch == NULL) + { + conf_err(lnnb, "Syntax error.", cfile); + continue; + } + *ch++ = '\0'; + mod_handle = dlopen(ch, RTLD_NOW); + if (mod_handle == NULL) + { + conf_err(lnnb, dlerror(), cfile); + continue; + } +# if defined(DLSYM_NEEDS_UNDERSCORE) + sprintf(lfname, "_%s_load", buffer+7); +# else + sprintf(lfname, "%s_load", buffer+7); +# endif + load_func = (aModule *(*)())dlsym(mod_handle, + lfname); + if (load_func == NULL) + { + conf_err(lnnb,"Invalid shared object.", + cfile); + dlclose(mod_handle); + continue; + } + Mlist[Mcnt] = load_func(); + if (Mlist[Mcnt]) + { + Mcnt += 1; + Mlist[Mcnt] = NULL; + } + else + { + conf_err(lnnb, "Failed.", cfile); + dlclose(mod_handle); + } + continue; + } +#endif + if (buffer[0] == '\t') + { + conf_err(lnnb, "Ignoring unexpected property.", + cfile); + continue; + } + /* at this point, it has to be the following */ + if (strncasecmp("module ", buffer, 7)) + { + conf_err(lnnb, + "Unexpected line: not a module.", + cfile); + continue; + } + for (i = 0; Mlist[i] != NULL; i++) + if (!strcasecmp(buffer+7, Mlist[i]->name)) + break; + if (Mlist[i] == NULL) + { + conf_err(lnnb, "Unknown module name.", cfile); + continue; + } + if (Mlist[i] == &Module_rfc931 && ident) + { + conf_err(lnnb, + "This module can only be loaded once.", + cfile); + continue; + } + *last = (AnInstance *) malloc(sizeof(AnInstance)); + (*last)->nexti = NULL; + (*last)->in = icount++; + (*last)->mod = Mlist[i]; + (*last)->opt = NULL; + (*last)->popt = NULL; + (*last)->data = NULL; + (*last)->hostname = NULL; + (*last)->address = NULL; + (*last)->timeout = timeout; + if (Mlist[i] == &Module_rfc931) + ident = *last; + + while (fgets(buffer, 160, cfh)) + { + aTarget **ttmp; + u_long baseip = 0, lmask = 0; + + if (ch = index(buffer, '\n')) + lnnb += 1; + else + { + conf_err(lnnb, + "line too long, ignoring.", + cfile); + /* now skip what's left */ + while (fgets(buffer, 160, cfh)) + if (index(buffer,'\n')) + break; + continue; + } + if (buffer[0] == '#') + continue; + if (buffer[0] == '\n') + break; + if (buffer[0] != '\t') + { + conf_err(lnnb, "Invalid syntax.", + cfile); + continue; + } + *ch = '\0'; + if (!strncasecmp(buffer+1, "option = ", 9)) + { + if ((*last)->opt) + conf_err(lnnb, + "Duplicate option keyword: ignored.", + cfile); + else + (*last)->opt = + mystrdup(buffer + 10); + continue; + } + if (!strncasecmp(buffer+1, "host = ", 7)) + { + needh = 1; + ttmp = &((*last)->hostname); + ch = buffer + 8; + } + else if (!strncasecmp(buffer+1, "ip = ", 5)) + { + ttmp = &((*last)->address); + ch = buffer + 6; + if (strchr(ch, '/')) + { + int i1, i2, i3, i4, m; + + if (sscanf(ch,"%d.%d.%d.%d/%d", + &i1, &i2, &i3, &i4, + &m) != 5 || + m < 1 || m > 31) + { + conf_err(lnnb, + "Bad mask.", + cfile); + continue; + } + lmask = htonl((u_long)0xffffffffL << (32 - m)); + baseip = htonl(i1 * 0x1000000 + + i2 * 0x10000 + + i3 * 0x100 + + i4); + } + else + { + lmask = 0; + baseip = 0; + } + } + else if (!strncmp(buffer+1, "timeout = ", 10)) + { + u_int local_timeout; + if (sscanf(buffer+1, "timeout = %u", + &local_timeout) != 1) + conf_err(lnnb, + "Invalid setting.", + cfile); + (*last)->timeout = local_timeout; + continue; + } + else + { + conf_err(lnnb, "Invalid keyword.", + cfile); + continue; + } + if (Mlist[i] == &Module_rfc931) + continue; + while (*ttmp) + ttmp = &((*ttmp)->nextt); + *ttmp = (aTarget *) malloc(sizeof(aTarget)); + if (*ch == '!') + { + (*ttmp)->yes = -1; + ch++; + } + else + (*ttmp)->yes = 0; + (*ttmp)->value = mystrdup(ch); + if ((*ttmp)->baseip) + { + (*ttmp)->lmask = lmask; + (*ttmp)->baseip = baseip; + } + (*ttmp)->nextt = NULL; + } + + last = &((*last)->nexti); + } + } + else if (cfile) + { + perror("fopen"); + exit(0); + } + if (ident == NULL) + { + ident = *last = (AnInstance *) malloc(sizeof(AnInstance)); + (*last)->nexti = NULL; + (*last)->opt = NULL; + (*last)->mod = &Module_rfc931; + (*last)->hostname = NULL; + (*last)->address = NULL; + (*last)->timeout = DEFAULT_TIMEOUT; + } + ident->timeout = MAX(DEFAULT_TIMEOUT, ident->timeout); + + itmp = instances; + while (itmp) + { + totto += itmp->timeout; + itmp = itmp->nexti; + } + if (totto > ACCEPTTIMEOUT) + { + if (cfile) + printf("Warning: sum of timeouts exceeds ACCEPTTIMEOUT!\n"); + else + sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR, + "Warning: sum of timeouts exceeds ACCEPTTIMEOUT!"); + if (o_dto) + if (cfile) + printf("Error: \"notimeout\" is set!\n"); + else + sendto_log(ALOG_IRCD|ALOG_DCONF, LOG_ERR, + "Error: \"notimeout\" is set!"); + } + + itmp = instances; + if (cfile) + { + aTarget *ttmp; + char *err; + + printf("\nModule(s) loaded:\n"); + while (itmp) + { + printf("\t%s\t%s\n", itmp->mod->name, + (itmp->opt) ? itmp->opt : ""); + if (ttmp = itmp->hostname) + { + printf("\t\tHost = %s%s", + (ttmp->yes == 0) ? "" : "!", + ttmp->value); + while (ttmp = ttmp->nextt) + printf(",%s%s", + (ttmp->yes == 0) ? "" : "!", + ttmp->value); + printf("\n"); + } + if (ttmp = itmp->address) + { + printf("\t\tIP = %s", + (ttmp->yes == 0) ? "" : "!", + ttmp->value); + while (ttmp = ttmp->nextt) + printf(",%s%s", + (ttmp->yes == 0) ? "" : "!", + ttmp->value); + printf("\n"); + } + if (itmp->timeout != DEFAULT_TIMEOUT) + printf("\t\ttimeout: %u seconds\n", + itmp->timeout); + if (itmp->mod->init) + { + err = itmp->mod->init(itmp); + printf("\t\tInitialization: %s\n", + (err) ? err : "Successful"); + } + itmp = itmp->nexti; + } + } + else + while (itmp) + { + if (itmp->mod->init) + itmp->mod->init(itmp); + itmp = itmp->nexti; + } + + ch = o_all; + if (o_req) *ch++ = 'R'; + if (o_dto) *ch++ = 'T'; + if (o_wup) *ch++ = 'A'; + if (needh) *ch++ = 'W'; + *ch++ = '\0'; + return o_all; +} + +/* conf_match: check if an instance is to be applied to a connection + Returns -1: no match, and never will + 0: got a match, doIt[tm] + 1: no match, but might be later so ask again */ +int +conf_match(cl, inst) +u_int cl; +AnInstance *inst; +{ + aTarget *ttmp; + + /* general case, always matches */ + if (inst->address == NULL && inst->hostname == NULL) + return 0; + /* feature case, "host = *" to force to wait for DNS info */ + if ((cldata[cl].state & A_NOH) && inst->hostname && + !strcmp(inst->hostname->value, "*")) + return 0; + /* check matches on IP addresses */ + if (ttmp = inst->address) + while (ttmp) + { + if (ttmp->baseip) + { + if (match_ipmask(ttmp, cldata[cl].itsip) == 0) + return ttmp->yes; + } + else + if (match(ttmp->value, cldata[cl].itsip) == 0) + return ttmp->yes; + ttmp = ttmp->nextt; + } + /* check matches on hostnames */ + if (ttmp = inst->hostname) + { + if (cldata[cl].state & A_GOTH) + { + while (ttmp) + { + if (match(ttmp->value, cldata[cl].host) == 0) + return ttmp->yes; + ttmp = ttmp->nextt; + } + /* no match, will never match */ + return -1; + } + else if (cldata[cl].state & A_NOH) + return -1; + else + /* may be later, once we have DNS information */ + return 1; + } + /* fall through, no match, will never match */ + return -1; +} + +/* conf_ircd: send the configuration to the ircd daemon */ +void +conf_ircd() +{ + AnInstance *itmp = instances; + aTarget *ttmp; + + sendto_ircd("a"); + while (itmp) + { + if (itmp->address == NULL && itmp->hostname == NULL) + sendto_ircd("A * %s %s", itmp->mod->name, + (itmp->popt) ? itmp->popt : ""); + else + { + ttmp = itmp->address; + while (ttmp) + { + sendto_ircd("A %s %s %s", ttmp->value, + itmp->mod->name, + (itmp->popt) ? itmp->popt : ""); + ttmp = ttmp->nextt; + } + ttmp = itmp->hostname; + while (ttmp) + { + sendto_ircd("A %s %s %s", ttmp->value, + itmp->mod->name, + (itmp->popt) ? itmp->popt : ""); + ttmp = ttmp->nextt; + } + } + itmp = itmp->nexti; + } +} diff --git a/iauth/a_conf_def.h b/iauth/a_conf_def.h new file mode 100644 index 0000000..078a9a0 --- /dev/null +++ b/iauth/a_conf_def.h @@ -0,0 +1,56 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_conf_def.h + * Copyright (C) 1998 Christophe Kalt + * + * 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. + */ + +typedef struct Module aModule; +typedef struct Instance AnInstance; +typedef struct Target aTarget; + +struct Module +{ + char *name; /* module name */ + char *(*init)(AnInstance *); /* instance initialization */ + void (*release)(AnInstance *);/* instance releasing >UNUSED< */ + void (*stats)(AnInstance *); /* send instance stats to ircd */ + int (*start)(u_int); /* start authentication */ + int (*work)(u_int); /* called whenever something has to be + * done (incoming data, timeout..) */ + int (*timeout)(u_int); /* called when timeout is reached */ + void (*clean)(u_int); /* finish/abort: cleanup*/ +}; + +struct Instance +{ + AnInstance *nexti; + u_char in; /* instance number */ + aModule *mod; /* module */ + char *opt; /* options read from file */ + char *popt; /* options to send to ircd */ + void *data; /* private data: stats, ... */ + aTarget *address; + aTarget *hostname; + u_int timeout; +}; + +struct Target +{ + char *value; + u_long baseip, lmask; /* a.b.c.d/z */ + char yes; + aTarget *nextt; +}; diff --git a/iauth/a_conf_ext.h b/iauth/a_conf_ext.h new file mode 100644 index 0000000..f0416be --- /dev/null +++ b/iauth/a_conf_ext.h @@ -0,0 +1,43 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_conf_ext.h + * Copyright (C) 1998 Christophe Kalt + * + * 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 contains external definitions for global variables and functions + defined in iauth/a_conf.c. + */ + +/* External definitions for global variables. + */ +#ifndef A_CONF_C +extern u_int debuglevel; +extern AnInstance *instances; +#endif /* A_CONF_C */ + +/* External definitions for global functions. + */ +#ifndef A_CONF_C +# define EXTERN extern +#else /* A_CONF_C */ +# define EXTERN +#endif /* A_CONF_C */ + +EXTERN char *conf_read __P((char *)); +EXTERN int conf_match __P((u_int, AnInstance *)); +EXTERN void conf_ircd(); + +#undef EXTERN diff --git a/iauth/a_defines.h b/iauth/a_defines.h new file mode 100644 index 0000000..aff3038 --- /dev/null +++ b/iauth/a_defines.h @@ -0,0 +1,39 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_defines.h + * Copyright (C) 1998 Christophe Kalt + * + * 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 includes all files defining constants, macros and types + definitions used by the authentication process. + */ + +#define IAUTH_DEBUG 1 + +#include "config.h" +#include "patchlevel.h" + +#include "dbuf_def.h" /* needed for struct_def.h, sigh */ +#include "class_def.h" /* needed for struct_def.h, sigh */ +#include "struct_def.h" +#if INET6 +# include "../ircd/nameser_def.h" +#endif +#include "support_def.h" + +#include "a_conf_def.h" +#include "a_struct_def.h" +#include "a_log_def.h" diff --git a/iauth/a_externs.h b/iauth/a_externs.h new file mode 100644 index 0000000..5108b56 --- /dev/null +++ b/iauth/a_externs.h @@ -0,0 +1,34 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_externs.h + * Copyright (C) 1998 Christophe Kalt + * + * 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 includes all *_ext.h files containing external declarations + * for the authentication process. + */ + +#include "match_ext.h" +#include "support_ext.h" + +#include "a_conf_ext.h" +#include "a_io_ext.h" +#include "a_log_ext.h" + +#include "mod_rfc931_ext.h" +#include "mod_socks_ext.h" +#include "mod_pipe_ext.h" +#include "mod_lhex_ext.h" diff --git a/iauth/a_io.c b/iauth/a_io.c new file mode 100644 index 0000000..a4bd57e --- /dev/null +++ b/iauth/a_io.c @@ -0,0 +1,831 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_io.c + * Copyright (C) 1998 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: a_io.c,v 1.22 1999/07/11 22:09:59 kalt Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define A_IO_C +#include "a_externs.h" +#undef A_IO_C + +anAuthData cldata[MAXCONNECTIONS]; /* index == ircd fd */ +static int cl_highest = -1; +#if defined(USE_POLL) +static int fd2cl[MAXCONNECTIONS]; /* fd -> cl mapping */ +#endif + +#define IOBUFSIZE 4096 +static char iobuf[IOBUFSIZE+1]; +static char rbuf[IOBUFSIZE+1]; /* incoming ircd stream */ +static int iob_len = 0, rb_len = 0; + +void +init_io() +{ + bzero((char *) cldata, sizeof(cldata)); +} + +/* sendto_ircd() functions */ +#if ! USE_STDARG +void +sendto_ircd(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10; +#else +void +vsendto_ircd(char *pattern, va_list va) +#endif +{ + char ibuf[4096]; + +#if ! USE_STDARG + sprintf(ibuf, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#else + vsprintf(ibuf, pattern, va); +#endif + DebugLog((ALOG_DSPY, 0, "To ircd: [%s]", ibuf)); + strcat(ibuf, "\n"); + if (write(0, ibuf, strlen(ibuf)) != strlen(ibuf)) + { + sendto_log(ALOG_DMISC, LOG_NOTICE, "Daemon exiting. [w %s]", + strerror(errno)); + exit(0); + } +} + +#if USE_STDARG +void +sendto_ircd(char *pattern, ...) +{ + va_list va; + va_start(va, pattern); + vsendto_ircd(pattern, va); + va_end(va); +} +#endif + +/* + * next_io + * + * given an entry, look for the next module instance to start + */ +static void +next_io(cl, last) +int cl; +AnInstance *last; +{ + DebugLog((ALOG_DIO, 0, "next_io(#%d, %x): last=%s state=0x%X", cl, last, + (last) ? last->mod->name : "", cldata[cl].state)); + + /* first, bail out immediately if the entry is flagged A_DONE */ + if (cldata[cl].state & A_DONE) + return; + + /* second, make sure the last instance which ran cleaned up */ + if (cldata[cl].rfd > 0 || cldata[cl].wfd > 0) + { + /* last is defined here */ + sendto_log(ALOG_IRCD|ALOG_DMISC, LOG_ERR, + "module \"%s\" didn't clean up fd's! (%d %d)", + last->mod->name, cldata[cl].rfd, cldata[cl].wfd); + if (cldata[cl].rfd > 0) + close(cldata[cl].rfd); + if (cldata[cl].wfd > 0 && cldata[cl].rfd != cldata[cl].wfd) + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; + } + + cldata[cl].buflen = 0; + cldata[cl].mod_status = 0; + cldata[cl].instance = NULL; + cldata[cl].timeout = 0; + + /* third, if A_START is set, a new pass has to be started */ + if (cldata[cl].state & A_START) + { + cldata[cl].state ^= A_START; + DebugLog((ALOG_DIO, 0, "next_io(#%d, %x): Starting again", + cl, last)); + last = NULL; /* start from beginning */ + } + + /* fourth, find next instance to be ran */ + if (last == NULL) + { + cldata[cl].instance = instances; + cldata[cl].ileft = 0; + } + else + cldata[cl].instance = last->nexti; + + while (cldata[cl].instance) + { + int cm; + + if (CheckBit(cldata[cl].idone, cldata[cl].instance->in)) + { + DebugLog((ALOG_DIO, 0, + "conf_match(#%d, %x, goth=%d, noh=%d) skipped %x (%s)", + cl, last, (cldata[cl].state & A_GOTH) == A_GOTH, + (cldata[cl].state & A_NOH) == A_NOH, + cldata[cl].instance, + cldata[cl].instance->mod->name)); + cldata[cl].instance = cldata[cl].instance->nexti; + continue; + } + cm = conf_match(cl, cldata[cl].instance); + DebugLog((ALOG_DIO, 0, + "conf_match(#%d, %x, goth=%d, noh=%d) said \"%s\" for %x (%s)", + cl, last, (cldata[cl].state & A_GOTH) == A_GOTH, + (cldata[cl].state & A_NOH) == A_NOH, + (cm==-1) ? "no match" : (cm==0) ? "match" : "try again", + cldata[cl].instance, cldata[cl].instance->mod->name)); + if (cm == 0) + break; + if (cm == -1) + SetBit(cldata[cl].idone, cldata[cl].instance->in); + else /* cm == 1 */ + cldata[cl].ileft += 1; + cldata[cl].instance = cldata[cl].instance->nexti; + } + + if (cldata[cl].instance == NULL) + /* fifth, when there's no instance to try.. */ + { + DebugLog((ALOG_DIO, 0, + "next_io(#%d, %x): no more instances to try (%d)", + cl, last, cldata[cl].ileft)); + if (cldata[cl].ileft == 0) + { + /* we are done */ + sendto_ircd("D %d %s %u ", cl, cldata[cl].itsip, + cldata[cl].itsport); + cldata[cl].state |= A_DONE; + free(cldata[cl].inbuffer); + cldata[cl].inbuffer = NULL; + } + return; + } + else + /* sixth, we've got an instance to try */ + { + int r; + + cldata[cl].timeout = time(NULL) + cldata[cl].instance->timeout; + r = cldata[cl].instance->mod->start(cl); + DebugLog((ALOG_DIO, 0, + "next_io(#%d, %x): %s->start() returned %d", + cl, last, cldata[cl].instance->mod->name, r)); + if (r != 1) + /* started, or nothing to do or failed: don't try again */ + SetBit(cldata[cl].idone, cldata[cl].instance->in); + if (r == 1) + cldata[cl].ileft += 1; + if (r != 0) + /* start() didn't start something */ + next_io(cl, cldata[cl].instance); + } +} + +/* + * parse_ircd + * + * parses data coming from ircd (doh ;-) + */ +static void +parse_ircd() +{ + char *ch, *chp, *buf = iobuf; + int cl = -1, ncl; + + iobuf[iob_len] = '\0'; + while (ch = index(buf, '\n')) + { + *ch = '\0'; + DebugLog((ALOG_DSPY, 0, "parse_ircd(): got [%s]", buf)); + + cl = atoi(chp = buf); + while (*chp++ != ' '); + switch (chp[0]) + { + case 'C': /* new connection */ + case 'O': /* old connection: do nothing, just update data */ + if (cldata[cl].state & A_ACTIVE) + { + /* this is not supposed to happen!!! */ + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d [%c] is already active (fatal)!", + cl, chp[0]); + exit(1); + } + if (cldata[cl].instance || cldata[cl].rfd > 0 || + cldata[cl].wfd > 0) + { + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d [%c] is already active! (fatal)", + cl, chp[0]); + exit(1); + } + if (cldata[cl].authuser) + { + /* shouldn't be here - hmmpf */ + sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING, + "Unreleased data [%c %d]!", chp[0], + cl); + free(cldata[cl].authuser); + cldata[cl].authuser = NULL; + } + if (cldata[cl].inbuffer) + { + /* shouldn't be here - hmmpf */ + sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING, + "Unreleased buffer [%c %d]!", + chp[0], cl); + free(cldata[cl].inbuffer); + cldata[cl].inbuffer = NULL; + } + cldata[cl].user[0] = '\0'; + cldata[cl].passwd[0] = '\0'; + cldata[cl].host[0] = '\0'; + bzero(cldata[cl].idone, BDSIZE); + cldata[cl].buflen = 0; + if (chp[0] == 'C') + cldata[cl].state = A_ACTIVE; + else + { + cldata[cl].state = A_ACTIVE|A_IGNORE; + break; + } + if (sscanf(chp+2, "%[^ ] %hu %[^ ] %hu", + cldata[cl].itsip, &cldata[cl].itsport, + cldata[cl].ourip, &cldata[cl].ourport) != 4) + { + sendto_log(ALOG_IRCD, LOG_CRIT, + "Bad data from ircd [%s] (fatal)", + chp); + exit(1); + } + /* we should really be using a pool of buffer here */ + cldata[cl].inbuffer = malloc(INBUFSIZE+1); + if (cl > cl_highest) + cl_highest = cl; + next_io(cl, NULL); /* get started */ + break; + case 'D': /* client disconnect */ + if (!(cldata[cl].state & A_ACTIVE)) + /* + ** this is not fatal, it happens with servers + ** we connected to (and more?). + ** It's better/safer to ignore here rather + ** than try to filter in ircd. -kalt + */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [D] is not active.", cl); + cldata[cl].state = 0; + if (cldata[cl].rfd > 0 || cldata[cl].wfd > 0) + cldata[cl].instance->mod->clean(cl); + cldata[cl].instance = NULL; + /* log something here? hmmpf */ + if (cldata[cl].authuser) + free(cldata[cl].authuser); + cldata[cl].authuser = NULL; + if (cldata[cl].inbuffer) + free(cldata[cl].inbuffer); + cldata[cl].inbuffer = NULL; + break; + case 'R': /* fd remap */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* this should really not happen */ + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d [R] is not active!", cl); + break; + } + ncl = atoi(chp+2); + if (cldata[ncl].state & A_ACTIVE) + { + /* this is not supposed to happen!!! */ + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d [R] is already active (fatal)!", ncl); + exit(1); + } + if (cldata[ncl].instance || cldata[ncl].rfd > 0 || + cldata[ncl].wfd > 0) + { + sendto_log(ALOG_IRCD, LOG_CRIT, + "Entry %d is already active! (fatal)", + ncl); + exit(1); + } + if (cldata[ncl].authuser) + { + /* shouldn't be here - hmmpf */ + sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING, + "Unreleased data [%d]!", ncl); + free(cldata[ncl].authuser); + cldata[ncl].authuser = NULL; + } + if (cldata[ncl].inbuffer) + { + /* shouldn't be here - hmmpf */ + sendto_log(ALOG_IRCD|ALOG_DIO, LOG_WARNING, + "Unreleased buffer [%c %d]!", + chp[0], ncl); + free(cldata[ncl].inbuffer); + cldata[ncl].inbuffer = NULL; + } + bcopy(cldata+cl, cldata+ncl, sizeof(anAuthData)); + + cldata[cl].state = 0; + cldata[cl].rfd = cldata[cl].wfd = 0; + cldata[cl].instance = NULL; + cldata[cl].authuser = NULL; + cldata[cl].inbuffer = NULL; + /* + ** this is the ugly part of having a slave (considering + ** that ircd remaps fd's: there is lag between the + ** server and the slave. + ** I can't think of any better way to handle this at + ** the moment -kalt + */ + if (cldata[ncl].state & A_IGNORE) + break; + if (cldata[ncl].state & A_LATE) + /* pointless 99.9% of the time */ + break; + if (cldata[ncl].authuser) + sendto_ircd("%c %d %s %u %s", + (cldata[ncl].state&A_UNIX)?'U':'u', + ncl, cldata[ncl].itsip, + cldata[ncl].itsport, + cldata[ncl].authuser); + if (cldata[ncl].state & A_DENY) + sendto_ircd("K %d %s %u ", ncl, + cldata[ncl].itsip, + cldata[ncl].itsport, + cldata[ncl].authuser); + if (cldata[ncl].state & A_DONE) + sendto_ircd("D %d %s %u ", ncl, + cldata[ncl].itsip, + cldata[ncl].itsport, + cldata[ncl].authuser); + break; + case 'N': /* hostname */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [N] is not active.", cl); + break; + } + if (cldata[cl].state & A_IGNORE) + break; + strcpy(cldata[cl].host, chp+2); + cldata[cl].state |= A_GOTH|A_START; + if (cldata[cl].instance == NULL) + next_io(cl, NULL); + break; + case 'A': /* host alias */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [A] is not active.", cl); + break; + } + if (cldata[cl].state & A_IGNORE) + break; + /* hmmpf */ + break; + case 'U': /* user provided username */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [U] is not active.", cl); + break; + } + if (cldata[cl].state & A_IGNORE) + break; + strcpy(cldata[cl].user, chp+2); + cldata[cl].state |= A_GOTU|A_START; + if (cldata[cl].instance == NULL) + next_io(cl, NULL); + break; + case 'P': /* user provided password */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [P] is not active.", cl); + break; + } + if (cldata[cl].state & A_IGNORE) + break; + strcpy(cldata[cl].passwd, chp+2); + cldata[cl].state |= A_GOTP; + /* + ** U message will follow immediately, + ** no need to do any thing else here + */ + break; + case 'T': /* ircd is registering the client */ + /* what to do with this? abort/continue? */ + cldata[cl].state |= A_LATE; + break; + case 'd': /* DNS timeout */ + case 'n': /* No hostname information, but no timeout either */ + if (!(cldata[cl].state & A_ACTIVE)) + { + /* let's be conservative and just ignore */ + sendto_log(ALOG_IRCD, LOG_WARNING, + "Warning: Entry %d [%c] is not active.", + cl, chp[0]); + break; + } + cldata[cl].state |= A_NOH|A_START; + if (cldata[cl].instance == NULL) + next_io(cl, NULL); + break; + case 'E': /* error message from ircd */ + sendto_log(ALOG_DIRCD, LOG_DEBUG, + "Error from ircd: %s", chp); + break; + default: + sendto_log(ALOG_IRCD, LOG_ERR, "Unexpected data [%s]", + chp); + break; + } + + buf = ch+1; + } + rb_len = 0; iob_len = 0; + if (strlen(buf)) + bcopy(buf, rbuf, rb_len = strlen(buf)); +} + +/* + * loop_io + * + * select()/poll() loop + */ +void +loop_io() +{ + /* the following is from ircd/s_bsd.c */ +#if ! USE_POLL +# define SET_READ_EVENT( thisfd ) FD_SET( thisfd, &read_set) +# define SET_WRITE_EVENT( thisfd ) FD_SET( thisfd, &write_set) +# define CLR_READ_EVENT( thisfd ) FD_CLR( thisfd, &read_set) +# define CLR_WRITE_EVENT( thisfd ) FD_CLR( thisfd, &write_set) +# define TST_READ_EVENT( thisfd ) FD_ISSET( thisfd, &read_set) +# define TST_WRITE_EVENT( thisfd ) FD_ISSET( thisfd, &write_set) + + fd_set read_set, write_set; + int highfd = -1; +#else +/* most of the following use pfd */ +# define POLLSETREADFLAGS (POLLIN|POLLRDNORM) +# define POLLREADFLAGS (POLLSETREADFLAGS|POLLHUP|POLLERR) +# define POLLSETWRITEFLAGS (POLLOUT|POLLWRNORM) +# define POLLWRITEFLAGS (POLLOUT|POLLWRNORM|POLLHUP|POLLERR) + +# define SET_READ_EVENT( thisfd ){ CHECK_PFD( thisfd );\ + pfd->events |= POLLSETREADFLAGS;} +# define SET_WRITE_EVENT( thisfd ){ CHECK_PFD( thisfd );\ + pfd->events |= POLLSETWRITEFLAGS;} + +# define CLR_READ_EVENT( thisfd ) pfd->revents &= ~POLLSETREADFLAGS +# define CLR_WRITE_EVENT( thisfd ) pfd->revents &= ~POLLSETWRITEFLAGS +# define TST_READ_EVENT( thisfd ) pfd->revents & POLLREADFLAGS +# define TST_WRITE_EVENT( thisfd ) pfd->revents & POLLWRITEFLAGS + +# define CHECK_PFD( thisfd ) \ + if ( pfd->fd != thisfd ) { \ + pfd = &poll_fdarray[nbr_pfds++];\ + pfd->fd = thisfd; \ + pfd->events = 0; \ + } + + struct pollfd poll_fdarray[MAXCONNECTIONS]; + struct pollfd * pfd = poll_fdarray; + int nbr_pfds = 0; +#endif + + int i, nfds = 0; + struct timeval wait; + time_t now = time(NULL); + +#if !defined(USE_POLL) + FD_ZERO(&read_set); + FD_ZERO(&write_set); + highfd = 0; +#else + /* set up such that CHECK_FD works */ + nbr_pfds = 0; + pfd = poll_fdarray; + pfd->fd = -1; +#endif /* USE_POLL */ + + SET_READ_EVENT(0); nfds = 1; /* ircd stream */ +#if defined(USE_POLL) && defined(IAUTH_DEBUG) + for (i = 0; i < MAXCONNECTIONS; i++) + fd2cl[i] = -1; /* sanity */ +#endif + for (i = 0; i <= cl_highest; i++) + { + if (cldata[i].timeout && cldata[i].timeout < now && + cldata[i].instance /* shouldn't be needed.. but it is */) + { + DebugLog((ALOG_DIO, 0, + "io_loop(): module %s timeout [%d]", + cldata[i].instance->mod->name, i)); + if (cldata[i].instance->mod->timeout(i) != 0) + next_io(i, cldata[i].instance); + } + if (cldata[i].rfd > 0) + { + SET_READ_EVENT(cldata[i].rfd); +#if !defined(USE_POLL) + if (cldata[i].rfd > highfd) + highfd = cldata[i].rfd; +#else + fd2cl[cldata[i].rfd] = i; +#endif + nfds++; + } + else if (cldata[i].wfd > 0) + { + SET_WRITE_EVENT(cldata[i].wfd); +#if ! USE_POLL + if (cldata[i].wfd > highfd) + highfd = cldata[i].wfd; +#else + fd2cl[cldata[i].wfd] = i; +#endif + nfds++; + } + } + + DebugLog((ALOG_DIO, 0, "io_loop(): checking for %d fd's", nfds)); + wait.tv_sec = 5; wait.tv_usec = 0; +#if ! USE_POLL + nfds = select(highfd + 1, (SELECT_FDSET_TYPE *)&read_set, + (SELECT_FDSET_TYPE *)&write_set, 0, &wait); + DebugLog((ALOG_DIO, 0, "io_loop(): select() returned %d, errno = %d", + nfds, errno)); +#else + nfds = poll(poll_fdarray, nbr_pfds, + wait.tv_sec * 1000 + wait.tv_usec/1000 ); + DebugLog((ALOG_DIO, 0, "io_loop(): poll() returned %d, errno = %d", + nfds, errno)); + pfd = poll_fdarray; +#endif + if (nfds == -1) + if (errno == EINTR) + return; + else + { + sendto_log(ALOG_IRCD, LOG_CRIT, + "fatal select/poll error: %s", + strerror(errno)); + exit(1); + } + if (nfds == 0) /* end of timeout */ + return; + + /* no matter select() or poll() this is also fd # 0 */ + if (TST_READ_EVENT(0)) + nfds--; + +#if !defined(USE_POLL) + for (i = 0; i <= cl_highest && nfds; i++) +#else + for (pfd = poll_fdarray+1; pfd != poll_fdarray+nbr_pfds && nfds; pfd++) +#endif + { +#if defined(USE_POLL) + i = fd2cl[pfd->fd]; +# if defined(IAUTH_DEBUG) + if (i == -1) + { + sendto_log(ALOG_DALL, LOG_CRIT,"io_loop(): fatal bug"); + exit(1); + } +# endif +#endif + if (cldata[i].rfd <= 0 && cldata[i].wfd <= 0) + { +#if defined(USE_POLL) + sendto_log(ALOG_IRCD, LOG_CRIT, + "io_loop(): fatal data inconsistency #%d (%d, %d)", + i, cldata[i].rfd, cldata[i].wfd); + exit(1); +#else + continue; +#endif + } + if (cldata[i].rfd > 0 && TST_READ_EVENT(cldata[i].rfd)) + { + int len; + + len = recv(cldata[i].rfd, + cldata[i].inbuffer + cldata[i].buflen, + INBUFSIZE - cldata[i].buflen, 0); + DebugLog((ALOG_DIO, 0, "io_loop(): i = #%d: recv(%d) returned %d, errno = %d", i, cldata[i].rfd, len, errno)); + if (len < 0) + { + cldata[i].instance->mod->clean(i); + next_io(i, cldata[i].instance); + } + else + { + cldata[i].buflen += len; + if (cldata[i].instance->mod->work(i) != 0) + next_io(i, cldata[i].instance); + else if (len == 0) + { + cldata[i].instance->mod->clean(i); + next_io(i, cldata[i].instance); + } + } + nfds--; + } + else if (cldata[i].wfd > 0 && TST_WRITE_EVENT(cldata[i].wfd)) + { + if (cldata[i].instance->mod->work(i) != 0) + next_io(i, cldata[i].instance); + + nfds--; + } + } + + /* + ** no matter select() or poll() this is also fd # 0 + ** this has to be done last (for the USE_POLL version) because + ** of R messages we may get from the server :/ + */ +#if defined(USE_POLL) + pfd = poll_fdarray; +#endif + if (TST_READ_EVENT(0)) + { + /* data from the ircd.. */ + while (1) + { + if (rb_len) + bcopy(rbuf, iobuf, iob_len = rb_len); + if ((i=recv(0,iobuf+iob_len,IOBUFSIZE-iob_len,0)) <= 0) + { + DebugLog((ALOG_DIO, 0, "io_loop(): recv(0) returned %d, errno = %d", i, errno)); + break; + } + iob_len += i; + DebugLog((ALOG_DIO, 0, + "io_loop(): got %d bytes from ircd [%d]", i, + iob_len)); + parse_ircd(); + } + if (i == 0) + { + sendto_log(ALOG_DMISC, LOG_NOTICE, + "Daemon exiting. [r]"); + exit(0); + } + } + +#if defined(IAUTH_DEBUG) + if (nfds > 0) + sendto_log(ALOG_DIO, 0, "io_loop(): nfds = %d !!!", nfds); +# if !defined(USE_POLL) + /* the equivalent should be written for poll() */ + if (nfds == 0) + while (i <= cl_highest) + { + if (cldata[i].rfd > 0 && TST_READ_EVENT(cldata[i].rfd)) + { + /* this should not happen! */ + /* hmmpf */ + } + i++; + } +# endif +#endif +} + +/* + * set_non_blocking (ripped from ircd/s_bsd.c) + */ +static void +set_non_blocking(fd, ip, port) +int fd; +char *ip; +u_short port; +{ + int res, nonb = 0; + +#if NBLOCK_POSIX + nonb |= O_NONBLOCK; +#endif +#if NBLOCK_BSD + nonb |= O_NDELAY; +#endif +#if NBLOCK_SYSV + /* This portion of code might also apply to NeXT. -LynX */ + res = 1; + + if (ioctl (fd, FIONBIO, &res) < 0) + sendto_log(ALOG_IRCD, 0, "ioctl(fd,FIONBIO) failed for %s:%u", + ip, port); +#else + if ((res = fcntl(fd, F_GETFL, 0)) == -1) + sendto_log(ALOG_IRCD, 0, "fcntl(fd, F_GETFL) failed for %s:%u", + ip, port); + else if (fcntl(fd, F_SETFL, res | nonb) == -1) + sendto_log(ALOG_IRCD, 0, + "fcntl(fd, F_SETL, nonb) failed for %s:%u", + ip, port); +#endif +} + +/* + * tcp_connect + * + * utility function for use in modules, creates a socket and connects + * it to an IP/port + * + * Returns the fd + */ +int +tcp_connect(ourIP, theirIP, port, error) +char *ourIP, *theirIP, **error; +u_short port; +{ + int fd; + static char errbuf[BUFSIZ]; + struct SOCKADDR_IN sk; + + fd = socket(AFINET, SOCK_STREAM, 0); + if (fd < 0) + { + sprintf(errbuf, "socket() failed: %s", strerror(errno)); + *error = errbuf; + return -1; + } + /* + * this bzero() shouldn't be needed.. should it? + * AIX 4.1.5 doesn't like not having it tho.. I have no clue why -kalt + */ + bzero((char *)&sk, sizeof(sk)); + sk.SIN_FAMILY = AFINET; +#if defined(INET6) + if(!inet_pton(AF_INET6, ourIP, sk.sin6_addr.s6_addr)) + bcopy(minus_one, sk.sin6_addr.s6_addr, IN6ADDRSZ); +#else + sk.sin_addr.s_addr = inetaddr(ourIP); +#endif + sk.SIN_PORT = htons(0); + if (bind(fd, (SAP)&sk, sizeof(sk)) < 0) + { + sprintf(errbuf, "bind() failed: %s", strerror(errno)); + *error = errbuf; + close(fd); + return -1; + } + set_non_blocking(fd, theirIP, port); +#if defined(INET6) + if(!inet_pton(AF_INET6, theirIP, sk.sin6_addr.s6_addr)) + bcopy(minus_one, sk.sin6_addr.s6_addr, IN6ADDRSZ); +#else + sk.sin_addr.s_addr = inetaddr(theirIP); +#endif + sk.SIN_PORT = htons(port); + if (connect(fd, (SAP)&sk, sizeof(sk)) < 0 && errno != EINPROGRESS) + { + sprintf(errbuf, "connect() to %s %u failed: %s", theirIP, port, + strerror(errno)); + *error = errbuf; + close(fd); + return -1; + } + *error = NULL; + return fd; +} diff --git a/iauth/a_io_ext.h b/iauth/a_io_ext.h new file mode 100644 index 0000000..12ec257 --- /dev/null +++ b/iauth/a_io_ext.h @@ -0,0 +1,50 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_io_ext.h + * Copyright (C) 1998 Christophe Kalt + * + * 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 contains external definitions for global variables and functions + defined in iauth/a_io.c. + */ + +/* External definitions for global variables. + */ +#ifndef A_IO_C +extern anAuthData cldata[MAXCONNECTIONS]; +#endif /* A_IO_C */ + +/* External definitions for global functions. + */ +#ifndef A_IO_C +#define EXTERN extern +#else /* A_IO_C */ +#define EXTERN +#endif /* A_IO_C */ + +EXTERN void io_init(); +#if ! USE_STDARG +EXTERN void sendto_ircd(); +#else /* USE_STDARG */ +EXTERN void vsendto_ircd (char *, va_list); +EXTERN void sendto_ircd (char *, ...); +#endif +EXTERN void init_io __P(()); +EXTERN void loop_io __P(()); +EXTERN int tcp_connect __P((char *, char *, u_short, char **)); + +/* __P(()) */ +#undef EXTERN diff --git a/iauth/a_log.c b/iauth/a_log.c new file mode 100644 index 0000000..5307cfe --- /dev/null +++ b/iauth/a_log.c @@ -0,0 +1,123 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_log.c + * Copyright (C) 1998 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: a_log.c,v 1.6 1999/02/21 00:33:45 kalt Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define A_LOG_C +#include "a_externs.h" +#undef A_LOG_C + +static FILE *debug = NULL, *authlog = NULL; + +void +init_filelogs() +{ +#if defined(IAUTH_DEBUG) + if (debug) + fclose(debug); + debug = fopen(IAUTHDBG_PATH, "w"); +# if defined(USE_SYSLOG) + if (!debug) + syslog(LOG_ERR, "Failed to open \"%s\" for writing", + IAUTHDBG_PATH); +# endif +#endif /* IAUTH_DEBUG */ + if (authlog) + fclose(authlog); + authlog = fopen(FNAME_AUTHLOG, "a"); +#if defined(USE_SYSLOG) + if (!authlog) + syslog(LOG_NOTICE, "Failed to open \"%s\" for writing", + FNAME_AUTHLOG); +#endif +} + +void +init_syslog() +{ +#if defined(USE_SYSLOG) + openlog("iauth", LOG_PID|LOG_NDELAY, LOG_FACILITY); +#endif +} + +#if ! USE_STDARG +void +sendto_log(flags, slflag, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) +int flags, slflag; +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10; +#else +void +vsendto_log(int flags, int slflag, char *pattern, va_list va) +#endif +{ + char logbuf[4096]; + + logbuf[0] = '>'; +#if ! USE_STDARG + sprintf(logbuf+1, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#else + vsprintf(logbuf+1, pattern, va); +#endif + +#if defined(USE_SYSLOG) + if (slflag) + syslog(slflag, logbuf+1); +#endif + + strcat(logbuf, "\n"); + +#if defined(IAUTH_DEBUG) + if ((flags & ALOG_DALL) && (flags & debuglevel) && debug) + { + fprintf(debug, logbuf+1); + fflush(debug); + } +#endif + if (authlog && (flags & ALOG_FLOG)) + { + fprintf(authlog, "%s: %s", myctime(time(NULL)), logbuf+1); + fflush(authlog); + } + if (flags & ALOG_IRCD) + { + write(0, logbuf, strlen(logbuf)); +#if defined(IAUTH_DEBUG) + if ((ALOG_DSPY & debuglevel) && debug) + { + fprintf(debug, "To ircd: %s", logbuf+1); + fflush(debug); + } +#endif + } +} + +#if USE_STDARG +void +sendto_log(int flags, int slflag, char *pattern, ...) +{ + va_list va; + va_start(va, pattern); + vsendto_log(flags, slflag, pattern, va); + va_end(va); +} +#endif diff --git a/iauth/a_log_def.h b/iauth/a_log_def.h new file mode 100644 index 0000000..e50df0b --- /dev/null +++ b/iauth/a_log_def.h @@ -0,0 +1,41 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_log_def.h + * Copyright (C) 1998 Christophe Kalt + * + * 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 defined(IAUTH_DEBUG) +# define DebugLog(x) sendto_log x +#else +# define DebugLog(x) ; +#endif + +#define ALOG_FLOG 0x01 /* file log */ +#define ALOG_IRCD 0x02 /* notice sent to ircd (then sent to &AUTH) */ + +#define ALOG_DCONF 0x000100 /* debug: configuration file */ +#define ALOG_DMISC 0x000200 /* debug: misc stuff */ +#define ALOG_DIO 0x000400 /* debug: IO stuff */ +#define ALOG_DSPY 0x001000 /* debug: show ircd stream */ +#define ALOG_DIRCD 0x002000 /* debug: errors reported by ircd */ + +#define ALOG_D931 0x010000 /* debug: module rfc931 */ +#define ALOG_DSOCKS 0x020000 /* debug: module socks */ +#define ALOG_DSOCKSC 0x040000 /* debug: module socks cache */ +#define ALOG_DPIPE 0x080000 /* debug: module pipe */ +#define ALOG_DLHEX 0x100000 /* debug: module pipe */ + +#define ALOG_DALL 0x1F3700 /* any debug flag */ diff --git a/iauth/a_log_ext.h b/iauth/a_log_ext.h new file mode 100644 index 0000000..d5887a0 --- /dev/null +++ b/iauth/a_log_ext.h @@ -0,0 +1,46 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_log_ext.h + * Copyright (C) 1998 Christophe Kalt + * + * 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 contains external definitions for global variables and functions + defined in iauth/a_log.c. + */ + +/* External definitions for global variables. + */ +#ifndef A_LOG_C +#endif /* A_LOG_C */ + +/* External definitions for global functions. + */ +#ifndef A_LOG_C +# define EXTERN extern +#else /* A_LOG_C */ +# define EXTERN +#endif /* A_LOG_C */ + +EXTERN void init_filelogs(); +EXTERN void init_syslog(); +#if ! USE_STDARG +EXTERN void sendto_log(); +#else /* USE_STDARG */ +EXTERN void vsendto_log (int, int, char *, va_list); +EXTERN void sendto_log (int, int, char *, ...); +#endif /* USE_STDARG */ + +#undef EXTERN diff --git a/iauth/a_struct_def.h b/iauth/a_struct_def.h new file mode 100644 index 0000000..d71b166 --- /dev/null +++ b/iauth/a_struct_def.h @@ -0,0 +1,72 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/a_struct_def.h + * Copyright (C) 1998 Christophe Kalt + * + * 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. + */ + + +typedef struct AuthData anAuthData; + +#define INBUFSIZE 4096 /* I/O buffer size */ +#define MAXI 16 /* maximum number of instances */ +#define BDSIZE ((MAXI + 7) / 8) /* bit data size */ + +struct AuthData +{ + /* the following are set by a_io.c and may be read by modules */ + char user[USERLEN+1]; /* username */ + char passwd[PASSWDLEN+1]; /* password */ + char host[HOSTLEN+1]; /* hostname */ + char itsip[HOSTLEN+1]; /* client ip */ + u_short itsport; /* client port */ + char ourip[HOSTLEN+1]; /* our ip */ + u_short ourport; /* our port */ + u_int state; /* state (general) */ + + /* the following are set by modules */ + char *authuser; /* authenticated username */ + u_char authfrom; /* where we got authuser from */ + + /* the following are for use by a_io.c only */ + char idone[BDSIZE]; /* keeping track of instances' work */ + u_char ileft; /* time saver, anything left? */ + + /* the following are shared by a_io.c & modules */ + char *inbuffer; /* input buffer */ + u_int buflen; /* length of data in buffer */ + int rfd, wfd; /* fd's */ + AnInstance *instance; /* the module instanciation working */ + u_int mod_status; /* used by the module only! */ + time_t timeout; /* timeout */ +}; + +#define A_ACTIVE 0x0001 /* entry is active */ +#define A_START 0x0002 /* go through modules from beginning */ +#define A_DONE 0x0004 /* nothing left to be done */ +#define A_IGNORE 0x0010 /* ignore subsequent messages from ircd */ +#define A_LATE 0x0080 /* ircd is no longer waiting for a reply */ + +#define A_GOTU 0x0100 /* got username (from ircd) */ +#define A_GOTP 0x0200 /* got password (from ircd) */ +#define A_GOTH 0x0400 /* got hostname (from ircd) */ +#define A_NOH 0x0800 /* no hostname available */ + +#define A_UNIX 0x1000 /* authuser is suitable for use by ircd */ +#define A_DENY 0x8000 /* connection should be denied access */ + +#define SetBit(v,n) v[n/8] |= (1 << (n % 8)) +#define UnsetBit(v,n) v[n/8] &= ~(1 << (n % 8)) +#define CheckBit(v,n) (v[n/8] & (1 << (n % 8))) diff --git a/iauth/iauth.c b/iauth/iauth.c new file mode 100644 index 0000000..395be72 --- /dev/null +++ b/iauth/iauth.c @@ -0,0 +1,226 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/iauthd.c + * Copyright (C) 1998 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: iauth.c,v 1.11 1999/06/17 01:22:20 kalt Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define IAUTH_C +#include "a_externs.h" +#undef IAUTH_C + +static int do_log = 0; + +RETSIGTYPE dummy(s) +int s; +{ + /* from common/bsd.c */ +#ifndef HAVE_RELIABLE_SIGNALS + (void)signal(SIGALRM, dummy); + (void)signal(SIGPIPE, dummy); +# ifndef HPUX /* Only 9k/800 series require this, but don't know how to.. */ +# ifdef SIGWINCH + (void)signal(SIGWINCH, dummy); +# endif +# endif +#else +# if POSIX_SIGNALS + struct sigaction act; + + act.sa_handler = dummy; + act.sa_flags = 0; + (void)sigemptyset(&act.sa_mask); + (void)sigaddset(&act.sa_mask, SIGALRM); + (void)sigaddset(&act.sa_mask, SIGPIPE); +# ifdef SIGWINCH + (void)sigaddset(&act.sa_mask, SIGWINCH); +# endif + (void)sigaction(SIGALRM, &act, (struct sigaction *)NULL); + (void)sigaction(SIGPIPE, &act, (struct sigaction *)NULL); +# ifdef SIGWINCH + (void)sigaction(SIGWINCH, &act, (struct sigaction *)NULL); +# endif +# endif +#endif +} + +RETSIGTYPE s_log(s) +int s; +{ +# if POSIX_SIGNALS + struct sigaction act; + + act.sa_handler = s_log; + act.sa_flags = 0; + (void)sigemptyset(&act.sa_mask); + (void)sigaddset(&act.sa_mask, SIGUSR2); + (void)sigaction(SIGUSR2, &act, NULL); +# else + (void)signal(SIGUSR2, s_log); +# endif + do_log = 1; +} + +void +init_signals() +{ + /* from ircd/ircd.c setup_signals() */ +#if 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); +*/ + act.sa_handler = s_log; + (void)sigaddset(&act.sa_mask, SIGUSR2); + (void)sigaction(SIGUSR2, &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); +*/ + (void)signal(SIGUSR2, s_log); +#endif +} + +int main(argc, argv) +int argc; +char *argv[]; +{ + time_t nextst = time(NULL) + 90; + char *xopt; + + if (argc == 2 && !strcmp(argv[1], "-X")) + exit(0); + + if (isatty(0)) + { + (void)printf("iauth %s", make_version()); +#if defined(USE_DSM) + (void)printf(" (with DSM support)\n"); +#else + (void)printf("\n"); +#endif + if (argc == 3 && !strcmp(argv[1], "-c")) + { + (void)printf("\nReading \"%s\"\n\n", argv[2]); + conf_read(argv[2]); + } + else + { +#if defined(INET6) + (void)printf("\t+INET6\n"); +#endif +#if defined(IAUTH_DEBUG) + (void)printf("\t+IAUTH_DEBUG\n"); +#endif +#if defined(USE_POLL) + (void)printf("\t+USE_POLL\n"); +#endif + } + exit(0); + } + + init_signals(); + init_syslog(); + init_filelogs(); + sendto_log(ALOG_DMISC, LOG_NOTICE, "Daemon starting (%s%s).", + make_version(), +#if defined(IAUTH_DEBUG) + "+debug" +#else + "" +#endif + ); + init_io(); + xopt = conf_read(NULL); + sendto_ircd("V %s", make_version()); + sendto_ircd("O %s", xopt); + conf_ircd(); + +#if defined(IAUTH_DEBUG) + if (debuglevel & ALOG_DIRCD) + sendto_ircd("G 1"); + else +#endif + sendto_ircd("G 0"); + + while (1) + { + loop_io(); + + if (do_log) + { + sendto_log(ALOG_IRCD|ALOG_DMISC, LOG_INFO, + "Got SIGUSR2, reinitializing log file(s)."); + init_filelogs(); + do_log = 0; + } + + if (time(NULL) > nextst) + { + AnInstance *itmp = instances; + + sendto_ircd("s"); + while (itmp) + { + if (itmp->mod->stats) + itmp->mod->stats(itmp); + itmp = itmp->nexti; + } + nextst = time(NULL) + 60; + } + } +} diff --git a/iauth/mod_lhex.c b/iauth/mod_lhex.c new file mode 100644 index 0000000..07e7e88 --- /dev/null +++ b/iauth/mod_lhex.c @@ -0,0 +1,318 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/mod_lhex.c + * Copyright (C) 1998-1999 Christophe Kalt and Andrew Snare + * + * 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 rcsid[] = "@(#)$Id mod_lhex.c,v 1.12 1999/02/06 21:43:52 kalt Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define MOD_LHEX_C +#include "a_externs.h" +#undef MOD_LHEX_C + +/****************************** PRIVATE *************************************/ +#define LHEXPORT 9674 + +struct lhex_private +{ + /* stats */ + u_int ok, banned; + u_int tried, clean, timeout; +}; + +/******************************** PUBLIC ************************************/ + +/* + * lhex_init + * + * This procedure is called when a particular module is loaded. + * Returns NULL if everything went fine, + * an error message otherwise. + */ +char * +lhex_init(self) +AnInstance *self; +{ + struct lhex_private *mydata; + +#if defined(INET6) + return "IPv6 unsupported."; +#endif + if(self->opt == NULL) + return "Aie! no option(s): no LHEx server to connect to!"; + if(!inetaton(self->opt,NULL)) + return "Aie! Option wasn't a valid IP address!"; + + /* Allocate the module data */ + mydata = (struct lhex_private *) malloc(sizeof(struct lhex_private)); + bzero((char *) mydata, sizeof(struct lhex_private)); + + self->popt = mystrdup(self->opt); + self->data = mydata; + return NULL; +} + +/* + * lhex_release + * + * This procedure is called when a particular module is unloaded. + */ +void +lhex_release(self) +AnInstance *self; +{ + struct lhex_private *mydata = self->data; + free(mydata); + free(self->popt); +} + +/* + * lhex_stats + * + * This procedure is called regularly to update statistics sent to ircd. + */ +void +lhex_stats(self) +AnInstance *self; +{ + struct lhex_private *mydata = self->data; + + sendto_ircd("S lhex ok %u banned %u", mydata->ok, mydata->banned); + sendto_ircd("S lhex tried %u aborted %u / %u", + mydata->tried, mydata->clean, mydata->timeout); +} + +/* + * lhex_start + * + * This procedure is called to start the LHEx check procedure. + * Returns 0 if everything went fine, + * anything else otherwise (nothing to be done, or failure) + * + * It is responsible for sending error messages where appropriate. + * In case of failure, it's responsible for cleaning up (e.g. lhex_clean + * will NOT be called) + */ +int +lhex_start(cl) +u_int cl; +{ + char *error; + int fd; + struct lhex_private *mydata = cldata[cl].instance->data; + + if (cldata[cl].state & A_DENY) + { + /* no point of doing anything */ + DebugLog((ALOG_DLHEX, 0, + "lhex_start(%d): A_DENY already set ", cl)); + return -1; + } + + DebugLog((ALOG_DLHEX, 0, "lhex_start(%d): Connecting to %s", cl, + cldata[cl].instance->opt)); + mydata->tried += 1; + fd= tcp_connect(cldata[cl].ourip, cldata[cl].instance->opt, + LHEXPORT, &error); + if (fd < 0) + { + DebugLog((ALOG_DLHEX, 0, + "lhex_start(%d): tcp_connect() reported %s", + cl, error)); + return -1; + } + + cldata[cl].wfd = fd; /*so that lhex_work() is called when connected*/ + return 0; +} + +/* + * lhex_work + * + * This procedure is called whenever there's new data in the buffer. + * Returns 0 if everything went fine, and there is more work to be done, + * Returns -1 if the module has finished its work (and cleaned up). + * + * It is responsible for sending error messages where appropriate. + */ +int +lhex_work(cl) +u_int cl; +{ + DebugLog((ALOG_DLHEX, 0, "lhex_work(%d): %d %d buflen=%d", cl, + cldata[cl].rfd, cldata[cl].wfd, cldata[cl].buflen)); + if (cldata[cl].wfd > 0) + { + /* + ** We haven't sent the query yet, the connection was just + ** established. + */ + char query[3+7+6+4+USERLEN+2*HOSTLEN+8+3];/*strlen(atoi(cl))<=8*/ + char *ident = cldata[cl].authuser; + + /* This is part of every request */ + sprintf(query, "id:%u ip:%s", cl, cldata[cl].itsip); + + /* These bits are optional, depending on what's known */ + if (ident) + { + strcat(query, " ident:"); + strcat(query, ident); + } + if (cldata[cl].state & A_GOTH) + { + strcat(query, " host:"); + strcat(query, cldata[cl].host); + } + /* Terminate the request */ + strcat(query, "\r\n"); + + DebugLog((ALOG_DLHEX, 0, "lhex_work(%u): Sending query [%s]", + cl, query)); + if (write(cldata[cl].wfd, query, strlen(query)) < 0) + { + /* most likely the connection failed */ + DebugLog((ALOG_DLHEX, 0, + "lhex_work(%u): write() failed: %s", + cl, strerror(errno))); + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; + return 1; + } + cldata[cl].rfd = cldata[cl].wfd; + cldata[cl].wfd = 0; + } + else + { + /* data's in from the other end */ + char *ch, *nch; + u_int id; + int retval = 0; + + cldata[cl].inbuffer[cldata[cl].buflen] = '\0'; + nch = cldata[cl].inbuffer; + while((nch < (cldata[cl].inbuffer + cldata[cl].buflen)) && + (ch = index(nch, '\r')) && !retval) + { + char *och = nch; + nch = ch+2; /* Skip the \r\n */ + *ch = '\0'; + DebugLog((ALOG_DLHEX, 0, "lhex_work(%u): Got [%s]", + cl, och)); + + /* Have a go at parsing the return info */ + if(sscanf(och, "%u", &id) != 1) + DebugLog((ALOG_DLHEX, 0, "lhex_work(%u): " + "Malformed data!", cl)); + else + { + struct lhex_private *d=cldata[cl].instance->data; + ch = index(och, ':'); + while(isspace(*(++ch))); + if(!strcmp(ch,"OK")) + { + d->ok++; + DebugLog((ALOG_DLHEX, 0, + "lhex_work(%u): OK", id)); + close(cldata[cl].rfd); + cldata[cl].rfd = 0; + retval = -1; + } + else if(!strcmp(ch,"Not OK")) + { + d->banned++; + DebugLog((ALOG_DLHEX, 0, + "lhex_work(%u): Not OK", id)); + cldata[cl].state |= A_DENY; + /* I really wish we could send the + client a "reason" here :P */ + sendto_ircd("K %d %s %u ", cl, + cldata[cl].itsip, + cldata[cl].itsport); + close(cldata[cl].rfd); + cldata[cl].rfd = 0; + retval = -1; + } + else + { +#if 0 + /* Call this info for the client */ + sendto_ircd("I %d %s %u NOTICE AUTH :%s", + cl, cldata[cl].itsip, + cldata[cl].itsport, ch); +#endif + retval = 0; + } + } + } + return retval; + } + return 0; +} + +/* + * lhex_clean + * + * This procedure is called whenever the module should interrupt its work. + * It is responsible for cleaning up any allocated data, and in particular + * closing file descriptors. + */ +void +lhex_clean(cl) +u_int cl; +{ + struct lhex_private *mydata = cldata[cl].instance->data; + + mydata->clean += 1; + DebugLog((ALOG_DLHEX, 0, "lhex_clean(%d): cleaning up", cl)); + /* + ** only one of rfd and wfd may be set at the same time, + ** in any case, they would be the same fd, so only close() once + */ + if (cldata[cl].rfd) + close(cldata[cl].rfd); + else if (cldata[cl].wfd) + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; +} + +/* + * lhex_timeout + * + * This procedure is called whenever the timeout set by the module is + * reached. + * + * Returns 0 if things are okay, -1 if check was aborted. + */ +int +lhex_timeout(cl) +u_int cl; +{ + struct lhex_private *mydata = cldata[cl].instance->data; + + mydata->timeout += 1; + DebugLog((ALOG_DLHEX, 0, "lhex_timeout(%d): calling lhex_clean ", cl)); + lhex_clean(cl); + return -1; +} + +aModule Module_lhex = + { "lhex", lhex_init, lhex_release, lhex_stats, + lhex_start, lhex_work, lhex_timeout, lhex_clean }; diff --git a/iauth/mod_lhex_ext.h b/iauth/mod_lhex_ext.h new file mode 100644 index 0000000..7777ca1 --- /dev/null +++ b/iauth/mod_lhex_ext.h @@ -0,0 +1,28 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/mod_lhex_ext.h + * Copyright (C) 1998-1999 Christophe Kalt and Andrew Snare + * + * 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 contains external definitions for global variables and functions + defined in iauth/mod_lhex.c. + */ + +/* External definitions for global variables. + */ +#ifndef MOD_LHEX_C +extern aModule Module_lhex; +#endif /* MOD_LHEX_C */ diff --git a/iauth/mod_pipe.c b/iauth/mod_pipe.c new file mode 100644 index 0000000..df41157 --- /dev/null +++ b/iauth/mod_pipe.c @@ -0,0 +1,217 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/mod_pipe.c + * Copyright (C) 1999 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: mod_pipe.c,v 1.3 1999/03/11 19:53:20 kalt Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define MOD_PIPE_C +#include "a_externs.h" +#undef MOD_PIPE_C + +/* + * pipe_init + * + * This procedure is called when a particular module is loaded. + * Returns NULL if everything went fine, + * an error message otherwise. + */ +char * +pipe_init(self) +AnInstance *self; +{ + if (self->opt == NULL) + return "Aie! no option(s): nothing to be done!"; + if (strncasecmp(self->opt, "prog=", 5)) + return "Aie! unknown option(s): nothing to be done!"; + self->popt = self->opt + 5; + return self->popt; +} + +/* + * pipe_release + * + * This procedure is called when a particular module is unloaded. +void +pipe_release(self) +AnInstance *self; +{ +} + */ + +/* + * pipe_stats + * + * This procedure is called regularly to update statistics sent to ircd. +void +pipe_stats(self) +AnInstance *self; +{ +} + */ + +/* + * pipe_start + * + * This procedure is called to start an authentication. + * Returns 0 if everything went fine, + * -1 otherwise (nothing to be done, or failure) + * + * It is responsible for sending error messages where appropriate. + * In case of failure, it's responsible for cleaning up (e.g. pipe_clean + * will NOT be called) + */ +int +pipe_start(cl) +u_int cl; +{ + int pp[2], rc; + + DebugLog((ALOG_DPIPE, 0, "pipe_start(%d): Forking for %s %u", cl, + cldata[cl].itsip, cldata[cl].itsport)); + if (pipe(pp) == -1) + { + DebugLog((ALOG_DPIPE, 0, + "pipe_start(%d): Error creating pipe: %s", + cl, strerror(errno))); + return -1; + } + switch (rc = vfork()) + { + case -1 : + DebugLog((ALOG_DPIPE, 0, + "pipe_start(%d): Error forking: %s", + cl, strerror(errno))); + return -1; + case 0 : + { + (void)close(pp[0]); + for (rc = 2; rc < MAXCONNECTIONS; rc++) + if (rc != pp[1]) + (void)close(rc); + if (pp[1] != 2) + (void)dup2(pp[1], 2); + (void)dup2(2, 1); + if (pp[1] != 2 && pp[1] != 1) + (void)close(pp[1]); + (void)execlp(cldata[cl].instance->popt, + cldata[cl].instance->popt, + cldata[cl].itsip, cldata[cl].itsport); + _exit(-1); + } + default : + (void)close(pp[1]); + break; + } + + cldata[cl].rfd = pp[0]; + return 0; +} + +/* + * pipe_work + * + * This procedure is called whenever there's new data in the buffer. + * Returns 0 if everything went fine, and there is more work to be done, + * Returns -1 if the module has finished its work (and cleaned up). + * + * It is responsible for sending error messages where appropriate. + */ +int +pipe_work(cl) +u_int cl; +{ + DebugLog((ALOG_DPIPE, 0, "pipe_work(%d): %d %d buflen=%d %c", cl, + cldata[cl].rfd, cldata[cl].wfd, cldata[cl].buflen, + cldata[cl].inbuffer[0])); + + switch (cldata[cl].inbuffer[0]) + { + case 'Y': + break; + case 'N': + cldata[cl].state |= A_DENY; + sendto_ircd("K %d %s %u ", cl, cldata[cl].itsip, + cldata[cl].itsport); + break; +#if 0 + /* hm.. need deeper mods to ircd */ + case 'y': + /* restricted connection only */ + cldata[cl].state |= A_RESTRICT; + sendto_ircd("k %d %s %u ", cl, cldata[cl].itsip, + cldata[cl].itsport); + break; +#endif + default : + /* error */ + sendto_log(ALOG_FLOG|ALOG_IRCD, LOG_WARNING, + "pipe: unexpected %c for %s[%s]", + cldata[cl].inbuffer[0], + cldata[cl].host, + cldata[cl].itsip); + break; + } + + /* We're done */ + close(cldata[cl].rfd); + cldata[cl].rfd = 0; + return -1; +} + +/* + * pipe_clean + * + * This procedure is called whenever the module should interrupt its work. + * It is responsible for cleaning up any allocated data, and in particular + * closing file descriptors. + */ +void +pipe_clean(cl) +u_int cl; +{ + DebugLog((ALOG_DPIPE, 0, "pipe_clean(%d): cleaning up", cl)); + if (cldata[cl].rfd) + close(cldata[cl].rfd); + cldata[cl].rfd = 0; +} + +/* + * pipe_timeout + * + * This procedure is called whenever the timeout set by the module is + * reached. + * + * Returns 0 if things are okay, -1 if authentication was aborted. + */ +int +pipe_timeout(cl) +u_int cl; +{ + DebugLog((ALOG_DPIPE, 0, "pipe_timeout(%d): calling pipe_clean ", + cl)); + pipe_clean(cl); + return -1; +} + +aModule Module_pipe = + { "pipe", pipe_init, NULL, NULL, + pipe_start, pipe_work, pipe_timeout, pipe_clean }; diff --git a/iauth/mod_pipe_ext.h b/iauth/mod_pipe_ext.h new file mode 100644 index 0000000..9012250 --- /dev/null +++ b/iauth/mod_pipe_ext.h @@ -0,0 +1,28 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/mod_pipe_ext.h + * Copyright (C) 1999 Christophe Kalt + * + * 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 contains external definitions for global variables and functions + defined in iauth/mod_pipe.c. + */ + +/* External definitions for global variables. + */ +#ifndef MOD_PIPE_C +extern aModule Module_pipe; +#endif /* MOD_PIPE_C */ diff --git a/iauth/mod_rfc931.c b/iauth/mod_rfc931.c new file mode 100644 index 0000000..80e5292 --- /dev/null +++ b/iauth/mod_rfc931.c @@ -0,0 +1,368 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/mod_rfc931.c + * Copyright (C) 1998 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: mod_rfc931.c,v 1.16 1999/07/11 20:56:25 chopin Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define MOD_RFC931_C +#include "a_externs.h" +#undef MOD_RFC931_C + +#define OPT_PROTOCOL 0x1 +#define OPT_LAZY 0x2 + +struct _data +{ + u_char options; + u_int tried; + u_int connected; + u_int unx; + u_int other; + u_int bad; + u_int skipped; + u_int clean, timeout; +}; + +/* + * rfc931_init + * + * This procedure is called when a particular module is loaded. + * Returns NULL if everything went fine, + * an error message otherwise. + */ +char * +rfc931_init(self) +AnInstance *self; +{ + struct _data *dt; + + dt = (struct _data *) malloc(sizeof(struct _data)); + bzero((char *) dt, sizeof(struct _data)); + self->data = (void *) dt; + + /* undocumented option */ + if (self->opt && strstr(self->opt, "protocol")) + dt->options |= OPT_PROTOCOL; + if (self->opt && strstr(self->opt, "lazy")) + dt->options |= OPT_LAZY; + + if (dt->options & (OPT_LAZY|OPT_PROTOCOL)) + self->popt = "protocol,lazy"; + else if (dt->options & OPT_LAZY) + self->popt = "lazy"; + else if (dt->options & OPT_PROTOCOL) + self->popt = "protocol"; + else + return NULL; + return self->popt; +} + +/* + * rfc931_release + * + * This procedure is called when a particular module is unloaded. + */ +void +rfc931_release(self) +AnInstance *self; +{ + struct _data *st = self->data; + free(st); +} + +/* + * rfc931_stats + * + * This procedure is called regularly to update statistics sent to ircd. + */ +void +rfc931_stats(self) +AnInstance *self; +{ + struct _data *st = self->data; + + sendto_ircd("S rfc931 connected %u unix %u other %u bad %u out of %u", + st->connected, st->unx, st->other, st->bad, st->tried); + sendto_ircd("S rfc931 skipped %u aborted %u / %u", + st->skipped, st->clean, st->timeout); +} + +/* + * rfc931_start + * + * This procedure is called to start an authentication. + * Returns 0 if everything went fine, + * -1 else otherwise (nothing to be done, or failure) + * + * It is responsible for sending error messages where appropriate. + * In case of failure, it's responsible for cleaning up (e.g. rfc931_clean + * will NOT be called) + */ +int +rfc931_start(cl) +u_int cl; +{ + char *error; + int fd; + struct _data *st = cldata[cl].instance->data; + + if (st->options & OPT_LAZY && cldata[cl].state & A_DENY) + { + DebugLog((ALOG_D931, 0, "rfc931_start(%d): Lazy.", cl)); + return -1; + } + if (cldata[cl].authuser && + cldata[cl].authfrom < cldata[cl].instance->in) + { + DebugLog((ALOG_D931, 0, + "rfc931_start(%d): Instance %d already got the info", + cl, cldata[cl].authfrom)); + return -1; + } + DebugLog((ALOG_D931, 0, "rfc931_start(%d): Connecting to %s %u", cl, + cldata[cl].itsip, 113)); + st->tried += 1; + fd = tcp_connect(cldata[cl].ourip, cldata[cl].itsip, 113, &error); + if (fd < 0) + { + DebugLog((ALOG_D931, 0, + "rfc931_start(%d): tcp_connect() reported %s", + cl, error)); + return -1; + } + + cldata[cl].wfd = fd; /*so that rfc931_work() is called when connected*/ + return 0; +} + +/* + * rfc931_work + * + * This procedure is called whenever there's new data in the buffer. + * Returns 0 if everything went fine, and there is more work to be done, + * Returns -1 if the module has finished its work (and cleaned up). + * + * It is responsible for sending error messages where appropriate. + */ +int +rfc931_work(cl) +u_int cl; +{ + struct _data *st = cldata[cl].instance->data; + + DebugLog((ALOG_D931, 0, "rfc931_work(%d): %d %d buflen=%d", cl, + cldata[cl].rfd, cldata[cl].wfd, cldata[cl].buflen)); + if (cldata[cl].wfd > 0) + { + /* + ** We haven't sent the query yet, the connection was just + ** established. + */ + char query[32]; + + sprintf(query, "%u , %u\r\n", cldata[cl].itsport, + cldata[cl].ourport); + if (write(cldata[cl].wfd, query, strlen(query)) < 0) + { + /* most likely the connection failed */ + DebugLog((ALOG_D931, 0, + "rfc931_work(%d): write() failed: %s", cl, + strerror(errno))); + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; + return 1; + } + else + st->connected += 1; + cldata[cl].rfd = cldata[cl].wfd; + cldata[cl].wfd = 0; + } + else + { + /* data's in from the ident server */ + char *ch; + u_char bad = 0; + + cldata[cl].inbuffer[cldata[cl].buflen] = '\0'; + ch = index(cldata[cl].inbuffer, '\r'); + if (ch) + { + /* got all of it! */ + *ch = '\0'; + DebugLog((ALOG_D931, 0, "rfc931_work(%d): Got [%s]", + cl, cldata[cl].inbuffer)); + if (cldata[cl].buflen > 1024) + cldata[cl].inbuffer[1024] = '\0'; + if (ch = index(cldata[cl].inbuffer, '\n')) + /* delimiter for ircd<->iauth messages. */ + *ch = '\0'; + ch = cldata[cl].inbuffer; + while (*ch && !isdigit(*ch)) ch++; + if (!*ch || atoi(ch) != cldata[cl].itsport) + { + DebugLog((ALOG_D931, 0, + "remote port mismatch.")); + ch = NULL; + } + while (ch && *ch && *ch != ',') ch++; + while (ch && *ch && !isdigit(*ch)) ch++; + if (ch && (!*ch || atoi(ch) != cldata[cl].ourport)) + { + DebugLog((ALOG_D931, 0, + "local port mismatch.")); + ch = NULL; + } + if (ch) ch = index(ch, ':'); + if (ch) ch += 1; + while (ch && *ch && *ch == ' ') ch++; + if (ch && strncmp(ch, "USERID", 6)) + { + DebugLog((ALOG_D931, 0, "No USERID.")); + ch = NULL; + } + if (ch) ch = index(ch, ':'); + if (ch) ch += 1; + while (ch && *ch && *ch == ' ') ch++; + if (ch) + { + int other = 0; + + if (!strncmp(ch, "OTHER", 5)) + other = 1; + ch = rindex(ch, ':'); + if (ch) ch += 1; + while (ch && *ch && *ch == ' ') ch++; + if (ch && *ch) + { + if (cldata[cl].authuser) + free(cldata[cl].authuser); + cldata[cl].authuser = mystrdup(ch); + cldata[cl].authfrom = + cldata[cl].instance->in; + if (other) + st->other += 1; + else + { + st->unx += 1; + cldata[cl].state |= A_UNIX; + } + sendto_ircd("%c %d %s %u %s", + (other) ? 'u' : 'U', cl, + cldata[cl].itsip, + cldata[cl].itsport, + cldata[cl].authuser); + } + else + bad = 1; + } + else + bad = 1; + if (bad) + { + st->bad += 1; + + if (st->options & OPT_PROTOCOL) + { + ch = cldata[cl].inbuffer; + while (*ch) + { + if (!(isalnum(*ch) || + ispunct(*ch) || + isspace(*ch))) + break; + ch += 1; + } + *ch = '\0'; + sendto_log(ALOG_IRCD|ALOG_FLOG, + LOG_WARNING, + "rfc931: bad reply from %s[%s] to \"%u, %u\": %u, \"%s\"", + cldata[cl].host, + cldata[cl].itsip, + cldata[cl].itsport, + cldata[cl].ourport, + cldata[cl].buflen, + cldata[cl].inbuffer); + } + } + /* + ** In any case, our job is done, let's cleanup. + */ + close(cldata[cl].rfd); + cldata[cl].rfd = 0; + return -1; + } + else + return 0; + } + return 0; +} + +/* + * rfc931_clean + * + * This procedure is called whenever the module should interrupt its work. + * It is responsible for cleaning up any allocated data, and in particular + * closing file descriptors. + */ +void +rfc931_clean(cl) +u_int cl; +{ + struct _data *st = cldata[cl].instance->data; + + st->clean += 1; + DebugLog((ALOG_D931, 0, "rfc931_clean(%d): cleaning up", cl)); + /* + ** only one of rfd and wfd may be set at the same time, + ** in any case, they would be the same fd, so only close() once + */ + if (cldata[cl].rfd) + close(cldata[cl].rfd); + else if (cldata[cl].wfd) + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; +} + +/* + * rfc931_timeout + * + * This procedure is called whenever the timeout set by the module is + * reached. + * + * Returns 0 if things are okay, -1 if authentication was aborted. + */ +int +rfc931_timeout(cl) +u_int cl; +{ + struct _data *st = cldata[cl].instance->data; + + st->timeout += 1; + DebugLog((ALOG_D931, 0, "rfc931_timeout(%d): calling rfc931_clean ", + cl)); + rfc931_clean(cl); + return -1; +} + +aModule Module_rfc931 = + { "rfc931", rfc931_init, rfc931_release, rfc931_stats, + rfc931_start, rfc931_work, rfc931_timeout, rfc931_clean }; diff --git a/iauth/mod_rfc931_ext.h b/iauth/mod_rfc931_ext.h new file mode 100644 index 0000000..b37892e --- /dev/null +++ b/iauth/mod_rfc931_ext.h @@ -0,0 +1,45 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/mod_rfc931_ext.h + * Copyright (C) 1998 Christophe Kalt + * + * 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 contains external definitions for global variables and functions + defined in iauth/mod_rfc931.c. + */ + +/* External definitions for global variables. + */ +#ifndef MOD_RFC931_C +extern aModule Module_rfc931; +#endif /* MOD_RFC931_C */ + +/* External definitions for global functions. + */ +#ifndef MOD_RFC931_C +# define EXTERN extern +#else /* MOD_RFC931_C */ +# define EXTERN +#endif /* MOD_RFC931_C */ + +/* +EXTERN int rfc931_start __P((u_int)); +EXTERN int rfc931_work __P((u_int)); +EXTERN int rfc931_timeout __P((u_int)); +EXTERN void rfc931_clean __P((u_int)); +*/ + +#undef EXTERN diff --git a/iauth/mod_socks.c b/iauth/mod_socks.c new file mode 100644 index 0000000..94742c4 --- /dev/null +++ b/iauth/mod_socks.c @@ -0,0 +1,632 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/mod_socks.c + * Copyright (C) 1998 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: mod_socks.c,v 1.25 1999/08/13 21:06:30 chopin Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#define MOD_SOCKS_C +#include "a_externs.h" +#undef MOD_SOCKS_C + +/****************************** PRIVATE *************************************/ + +#define CACHETIME 30 + +#define SOCKSPORT 1080 + +struct proxylog +{ + struct proxylog *next; + char ip[HOSTLEN+1]; + u_char state; /* 0 = no proxy, 1 = open proxy, 2 = closed proxy */ + time_t expire; +}; + +#define OPT_LOG 0x001 +#define OPT_DENY 0x002 +#define OPT_PARANOID 0x004 +#define OPT_CAREFUL 0x008 +#define OPT_V4ONLY 0x010 +#define OPT_V5ONLY 0x020 +#define OPT_PROTOCOL 0x100 + +#define PROXY_NONE 0 +#define PROXY_OPEN 1 +#define PROXY_CLOSE 2 +#define PROXY_UNEXPECTED 3 +#define PROXY_BADPROTO 4 + +#define ST_V4 0x01 +#define ST_V5 0x02 +#define ST_V5b 0x04 + +struct socks_private +{ + struct proxylog *cache; + u_int lifetime; + u_char options; + /* stats */ + u_int chitc, chito, chitn, cmiss, cnow, cmax; + u_int closed4, closed5, open4, open5, noprox; + u_int closed5b, open5b; +}; + +/* + * socks_open_proxy + * + * Found an open proxy for cl: deal with it! + */ +static void +socks_open_proxy(cl, strver) +int cl; +char *strver; +{ + struct socks_private *mydata = cldata[cl].instance->data; + + /* open proxy */ + if (mydata->options & OPT_DENY) + { + cldata[cl].state |= A_DENY; + sendto_ircd("k %d %s %u ", cl, cldata[cl].itsip, + cldata[cl].itsport); + } + if (mydata->options & OPT_LOG) + sendto_log(ALOG_FLOG, LOG_INFO, "socks%s: open proxy: %s[%s]", + strver, cldata[cl].host, cldata[cl].itsip); +} + +/* + * socks_add_cache + * + * Add an entry to the cache. + */ +static void +socks_add_cache(cl, state) +int cl, state; +{ + struct socks_private *mydata = cldata[cl].instance->data; + struct proxylog *next; + + if (state == PROXY_OPEN) + if (cldata[cl].mod_status == ST_V4) + mydata->open4 += 1; + else if (cldata[cl].mod_status == ST_V5) + mydata->open5 += 1; + else + mydata->open5b += 1; + else if (state == PROXY_NONE) + mydata->noprox += 1; + else /* state == PROXY_CLOSE|PROXY_UNEXPECTED|PROXY_BADPROTO */ + if (cldata[cl].mod_status == ST_V4) + mydata->closed4 += 1; + else if (cldata[cl].mod_status == ST_V5) + mydata->closed5 += 1; + else + mydata->closed5b += 1; + + if (mydata->lifetime == 0) + return; + + mydata->cnow += 1; + if (mydata->cnow > mydata->cmax) + mydata->cmax = mydata->cnow; + + next = mydata->cache; + mydata->cache = (struct proxylog *)malloc(sizeof(struct proxylog)); + mydata->cache->expire = time(NULL) + mydata->lifetime; + strcpy(mydata->cache->ip, cldata[cl].itsip); + mydata->cache->state = state; + mydata->cache->next = next; + DebugLog((ALOG_DSOCKSC, 0, "socks_add_cache(%d): new cache %s, open=%d", + cl, mydata->cache->ip, state)); +} + +/* + * socks_check_cache + * + * Check cache for an entry. + */ +static int +socks_check_cache(cl) +{ + struct socks_private *mydata = cldata[cl].instance->data; + struct proxylog **last, *pl; + time_t now = time(NULL); + + if (mydata->lifetime == 0) + return 0; + + DebugLog((ALOG_DSOCKSC, 0, "socks_check_cache(%d): Checking cache for %s", + cl, cldata[cl].itsip)); + + last = &(mydata->cache); + while (pl = *last) + { + DebugLog((ALOG_DSOCKSC, 0, "socks_check_cache(%d): cache %s", + cl, pl->ip)); + if (pl->expire < now) + { + DebugLog((ALOG_DSOCKSC, 0, + "socks_check_cache(%d): free %s (%d < %d)", + cl, pl->ip, pl->expire, now)); + *last = pl->next; + free(pl); + mydata->cnow -= 1; + continue; + } + if (!strcasecmp(pl->ip, cldata[cl].itsip)) + { + DebugLog((ALOG_DSOCKSC, 0, + "socks_check_cache(%d): match (%u)", + cl, pl->state)); + pl->expire = now + mydata->lifetime; /* dubious */ + if (pl->state == 1) + { + socks_open_proxy(cl, "C"); + mydata->chito += 1; + } + else if (pl->state == 0) + mydata->chitn += 1; + else + mydata->chitc += 1; + return -1; + } + last = &(pl->next); + } + mydata->cmiss += 1; + return 0; +} + +static int +socks_write(cl, strver) +u_int cl; +char *strver; +{ + u_char query[13]; /* big enough to hold all queries */ + int query_len = 13; /* lenght of socks4 query */ + u_int a, b, c, d; + + if (sscanf(cldata[cl].ourip, "%u.%u.%u.%u", &a,&b,&c,&d) != 4) + { + sendto_log(ALOG_DSOCKS|ALOG_IRCD, LOG_ERR, + "socks_write%s(%d): sscanf(\"%s\") failed", + strver, cl, cldata[cl].ourip); + close(cldata[cl].wfd); + cldata[cl].wfd = 0; + return -1; + } + if (cldata[cl].mod_status == ST_V4) + { + query[0] = 4; query[1] = 1; + query[2] = ((cldata[cl].ourport & 0xff00) >> 8); + query[3] = (cldata[cl].ourport & 0x00ff); + query[4] = a; query[5] = b; query[6] = c; query[7] = d; + query[8] = 'u'; query[9] = 's'; query[10] = 'e'; query[11] = 'r'; + query[12] = 0; + } + else + { + query[0] = 5; query[1] = 1; query[2] = 0; + query_len = 3; + if (cldata[cl].mod_status == ST_V5b) + { + query_len = 10; + query[3] = 1; + query[4] = a; query[5] = b; query[6] = c; query[7] = d; + query[8] = ((cldata[cl].ourport & 0xff00) >>8); + query[9] = (cldata[cl].ourport & 0x00ff); + } + } + + DebugLog((ALOG_DSOCKS, 0, "socks%s_write(%d): Checking %s %u", + strver, cl, cldata[cl].ourip, SOCKSPORT)); + if (write(cldata[cl].wfd, query, query_len) != query_len) + { + /* most likely the connection failed */ + DebugLog((ALOG_DSOCKS, 0, "socks%s_write(%d): write() failed: %s", + strver, cl, strerror(errno))); + socks_add_cache(cl, PROXY_NONE, 0); + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; + return 1; + } + cldata[cl].rfd = cldata[cl].wfd; + cldata[cl].wfd = 0; + return 0; +} + +static int +socks_read(cl, strver) +u_int cl; +char *strver; +{ + struct socks_private *mydata = cldata[cl].instance->data; + int again = 0; + u_char state = PROXY_CLOSE; + + /* data's in from the other end */ + if (cldata[cl].buflen < 2) + return 0; + + /* got all we need */ + DebugLog((ALOG_DSOCKS, 0, "socks%s_read(%d): Got [%d %d]", strver, cl, + cldata[cl].inbuffer[0], cldata[cl].inbuffer[1])); + + if (cldata[cl].mod_status == ST_V4) + { + if (cldata[cl].inbuffer[0] == 0) + { + if (cldata[cl].inbuffer[1] < 90 || + cldata[cl].inbuffer[1] > 93) + state = PROXY_UNEXPECTED; + else + { + if (cldata[cl].inbuffer[1] == 90) + state = PROXY_OPEN; + else if ((mydata->options & OPT_PARANOID) && + cldata[cl].inbuffer[1] != 91) + state = PROXY_OPEN; + } + } + else + state = PROXY_BADPROTO; + } + else /* ST_V5 or ST_V5b */ + { + if (cldata[cl].inbuffer[0] == 5) + if (cldata[cl].inbuffer[1] == 0) + state = PROXY_OPEN; + else + { + if (cldata[cl].mod_status == ST_V5) + { + if ((u_char)cldata[cl].inbuffer[1] == 4 || + ((u_char)cldata[cl].inbuffer[1] > 9 && + (u_char)cldata[cl].inbuffer[1] != 255)) + state = PROXY_UNEXPECTED; + } + else /* ST_V5b */ + if ((u_char) cldata[cl].inbuffer[1] > 8) + state = PROXY_UNEXPECTED; + else if ((mydata->options&OPT_PARANOID) && + cldata[cl].inbuffer[1] != 2) + state = PROXY_OPEN; + } + else + state = PROXY_BADPROTO; + } + + if (cldata[cl].mod_status == ST_V4 && state != PROXY_OPEN && + !(mydata->options & OPT_V4ONLY)) + { + cldata[cl].mod_status = ST_V5; + cldata[cl].buflen=0; + close(cldata[cl].rfd); + cldata[cl].rfd = 0; + again = 1; + } + + if (cldata[cl].mod_status == ST_V5 && state == PROXY_OPEN && + (mydata->options & OPT_CAREFUL)) + { + cldata[cl].mod_status = ST_V5b; + cldata[cl].buflen=0; + close(cldata[cl].rfd); + cldata[cl].rfd = 0; + again = 1; + } + + if (state == PROXY_OPEN && again == 0) + socks_open_proxy(cl, strver); + + if (state == PROXY_UNEXPECTED) + { + sendto_log(ALOG_FLOG, LOG_WARNING, + "socks%s: unexpected reply: %u,%u %s[%s]", strver, + cldata[cl].inbuffer[0], cldata[cl].inbuffer[1], + cldata[cl].host, cldata[cl].itsip); + sendto_log(ALOG_IRCD, 0, "socks%s: unexpected reply: %u,%u", + strver, cldata[cl].inbuffer[0], + cldata[cl].inbuffer[1]); + state = PROXY_CLOSE; + } + + if (state == PROXY_BADPROTO && (mydata->options & OPT_PROTOCOL)) + { + sendto_log(ALOG_FLOG, LOG_WARNING, + "socks%s: protocol error: %u,%u %s[%s]", strver, + cldata[cl].inbuffer[0], cldata[cl].inbuffer[1], + cldata[cl].host, cldata[cl].itsip); + sendto_log(ALOG_IRCD, 0, "socks%s: protocol error: %u,%u", + strver, cldata[cl].inbuffer[0], + cldata[cl].inbuffer[1]); + state = PROXY_CLOSE; + } + + if (again == 1) + return socks_start(cl); + else + { + socks_add_cache(cl, state); + close(cldata[cl].rfd); + cldata[cl].rfd = 0; + return -1; + } + return 0; +} + +/******************************** PUBLIC ************************************/ + +/* + * socks_init + * + * This procedure is called when a particular module is loaded. + * Returns NULL if everything went fine, + * an error message otherwise. + */ +char * +socks_init(self) +AnInstance *self; +{ + struct socks_private *mydata; + char tmpbuf[80], cbuf[32]; + static char txtbuf[80]; + +#if defined(INET6) + return "IPv6 unsupported."; +#endif + if (self->opt == NULL) + return "Aie! no option(s): nothing to be done!"; + + mydata = (struct socks_private *) malloc(sizeof(struct socks_private)); + bzero((char *) mydata, sizeof(struct socks_private)); + mydata->cache = NULL; + mydata->lifetime = CACHETIME; + + tmpbuf[0] = txtbuf[0] = '\0'; + if (strstr(self->opt, "log")) + { + mydata->options |= OPT_LOG; + strcat(tmpbuf, ",log"); + strcat(txtbuf, ", Log"); + } + if (strstr(self->opt, "reject")) + { + mydata->options |= OPT_DENY; + strcat(tmpbuf, ",reject"); + strcat(txtbuf, ", Reject"); + } + if (strstr(self->opt, "paranoid")) + { + mydata->options |= OPT_PARANOID; + strcat(tmpbuf, ",paranoid"); + strcat(txtbuf, ", Paranoid"); + } + if (strstr(self->opt, "careful")) + { + mydata->options |= OPT_CAREFUL; + strcat(tmpbuf, ",careful"); + strcat(txtbuf, ", Careful"); + } + if (strstr(self->opt, "v4only")) + { + mydata->options |= OPT_V4ONLY; + strcat(tmpbuf, ",v4only"); + strcat(txtbuf, ", V4only"); + } + if (strstr(self->opt, "v5only")) + { + mydata->options |= OPT_V5ONLY; + strcat(tmpbuf, ",v5only"); + strcat(txtbuf, ", V5only"); + } + if (strstr(self->opt, "protocol")) + { + mydata->options |= OPT_PROTOCOL; + strcat(tmpbuf, ",protocol"); + strcat(txtbuf, ", Protocol"); + } + + if (mydata->options == 0) + return "Aie! unknown option(s): nothing to be done!"; + + if (strstr(self->opt, "cache")) + { + char *ch = index(self->opt, '='); + + if (ch) + mydata->lifetime = atoi(ch+1); + } + sprintf(cbuf, ",cache=%d", mydata->lifetime); + strcat(tmpbuf, cbuf); + sprintf(cbuf, ", Cache %d (min)", mydata->lifetime); + strcat(txtbuf, cbuf); + mydata->lifetime *= 60; + + self->popt = mystrdup(tmpbuf+1); + self->data = mydata; + return txtbuf+2; +} + +/* + * socks_release + * + * This procedure is called when a particular module is unloaded. + */ +void +socks_release(self) +AnInstance *self; +{ + struct sock_private *mydata = self->data; + free(mydata); + free(self->popt); +} + +/* + * socks_stats + * + * This procedure is called regularly to update statistics sent to ircd. + */ +void +socks_stats(self) +AnInstance *self; +{ + struct socks_private *mydata = self->data; + + sendto_ircd("S socks open %u/%u/%u closed %u/%u/%u noproxy %u", + mydata->open4, mydata->open5, mydata->open5b, + mydata->closed4, mydata->closed5, mydata->closed5b, + mydata->noprox); + sendto_ircd("S socks cache open %u closed %u noproxy %u miss %u (%u <= %u)", + mydata->chito, mydata->chitc, mydata->chitn, + mydata->cmiss, mydata->cnow, mydata->cmax); +} + +/* + * socks_start + * + * This procedure is called to start the socks check procedure. + * Returns 0 if everything went fine, + * -1 otherwise (nothing to be done, or failure) + * + * It is responsible for sending error messages where appropriate. + * In case of failure, it's responsible for cleaning up (e.g. socks_clean + * will NOT be called) + */ +int +socks_start(cl) +u_int cl; +{ + struct socks_private *mydata = cldata[cl].instance->data; + char *error; + int fd; + + if (cldata[cl].state & A_DENY) + { + /* no point of doing anything */ + DebugLog((ALOG_DSOCKS, 0, + "socks_start(%d): A_DENY alredy set ", cl)); + return -1; + } + + if (socks_check_cache(cl)) + return -1; + + DebugLog((ALOG_DSOCKS, 0, "socks_start(%d): Connecting to %s", cl, + cldata[cl].itsip)); + fd= tcp_connect(cldata[cl].ourip, cldata[cl].itsip, SOCKSPORT, &error); + if (fd < 0) + { + DebugLog((ALOG_DSOCKS, 0, + "socks_start(%d): tcp_connect() reported %s", cl,error)); + socks_add_cache(cl, PROXY_NONE, 0); + return -1; + } + + cldata[cl].wfd = fd; /*so that socks_work() is called when connected*/ + + return 0; +} + +/* + * socks_work + * + * This procedure is called whenever there's new data in the buffer. + * Returns 0 if everything went fine, and there is more work to be done, + * Returns -1 if the module has finished its work (and cleaned up). + * + * It is responsible for sending error messages where appropriate. + */ +int +socks_work(cl) +u_int cl; +{ + char *strver = "4"; + struct socks_private *mydata = cldata[cl].instance->data; + + if (cldata[cl].mod_status == 0) + if (mydata->options & OPT_V5ONLY) + cldata[cl].mod_status = ST_V5; + else + cldata[cl].mod_status = ST_V4; + + if (cldata[cl].mod_status & ST_V5) + strver = "5"; + else if (cldata[cl].mod_status & ST_V5b) + strver = "5b"; + + DebugLog((ALOG_DSOCKS, 0, "socks%s_work(%d): %d %d buflen=%d", strver, + cl, cldata[cl].rfd, cldata[cl].wfd, cldata[cl].buflen)); + + if (cldata[cl].wfd > 0) + /* + ** We haven't sent the query yet, the connection was just + ** established. + */ + return socks_write(cl, strver); + else + return socks_read(cl, strver); +} + +/* + * socks_clean + * + * This procedure is called whenever the module should interrupt its work. + * It is responsible for cleaning up any allocated data, and in particular + * closing file descriptors. + */ +void +socks_clean(cl) +u_int cl; +{ + DebugLog((ALOG_DSOCKS, 0, "socks_clean(%d): cleaning up", cl)); + /* + ** only one of rfd and wfd may be set at the same time, + ** in any case, they would be the same fd, so only close() once + */ + if (cldata[cl].rfd) + close(cldata[cl].rfd); + else if (cldata[cl].wfd) + close(cldata[cl].wfd); + cldata[cl].rfd = cldata[cl].wfd = 0; +} + +/* + * socks_timeout + * + * This procedure is called whenever the timeout set by the module is + * reached. + * + * Returns 0 if things are okay, -1 if check was aborted. + */ +int +socks_timeout(cl) +u_int cl; +{ + DebugLog((ALOG_DSOCKS, 0, "socks_timeout(%d): calling socks_clean ", cl)); + socks_clean(cl); + return -1; +} + +aModule Module_socks = + { "socks", socks_init, socks_release, socks_stats, + socks_start, socks_work, socks_timeout, socks_clean }; diff --git a/iauth/mod_socks_ext.h b/iauth/mod_socks_ext.h new file mode 100644 index 0000000..9f4df51 --- /dev/null +++ b/iauth/mod_socks_ext.h @@ -0,0 +1,28 @@ +/************************************************************************ + * IRC - Internet Relay Chat, iauth/mod_socks_ext.h + * Copyright (C) 1998 Christophe Kalt + * + * 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 contains external definitions for global variables and functions + defined in iauth/mod_socks.c. + */ + +/* External definitions for global variables. + */ +#ifndef MOD_SOCKS_C +extern aModule Module_socks; +#endif /* MOD_SOCKS_C */ diff --git a/irc/c_bsd.c b/irc/c_bsd.c new file mode 100644 index 0000000..25bbd83 --- /dev/null +++ b/irc/c_bsd.c @@ -0,0 +1,149 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_bsd.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 rcsid[] = "@(#)$Id: c_bsd.c,v 1.5 1998/12/13 00:02:35 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define C_BSD_C +#include "c_externs.h" +#undef C_BSD_C + +#ifdef AUTOMATON +#ifdef DOCURSES +#undef DOCURSES +#endif +#ifdef DOTERMCAP +#undef DOTERMCAP +#endif +#endif /* AUTOMATON */ + +#define STDINBUFSIZE (0x80) + +int client_init(host, portnum, cptr) +char *host; +int portnum; +aClient *cptr; +{ + int sock; + static struct hostent *hp; + static struct SOCKADDR_IN server; + + sock = socket(AFINET, SOCK_STREAM, 0); + if (sock < 0) { + perror("opening stream socket"); + exit(1); + } + server.SIN_FAMILY = AFINET; + + if (isdigit(*host)) +#ifdef INET6 + { + if(!inet_pton(AF_INET6, host, server.sin6_addr.s6_addr)) + bcopy(minus_one, server.sin6_addr.s6_addr, IN6ADDRSZ); + } +#else + server.sin_addr.s_addr = inetaddr(host); +#endif + else { +#ifdef INET6 + res_init(); + _res.options|=RES_USE_INET6; +#endif + hp = gethostbyname(host); + if (hp == 0) { + fprintf(stderr, "%s: unknown host\n", host); + exit(2); + } + bcopy(hp->h_addr, (char *)&server.SIN_ADDR, hp->h_length); + } + server.SIN_PORT = htons(portnum); + if (connect(sock, (SAP)&server, sizeof(server)) == -1) { + perror("irc"); + exit(1); + } + + cptr->acpt = cptr; + cptr->port = server.SIN_PORT; +#ifdef INET6 + bcopy(server.sin6_addr.s6_addr, cptr->ip.s6_addr, IN6ADDRSZ); +#else + cptr->ip.s_addr = server.sin_addr.s_addr; +#endif + return(sock); +} + +void client_loop(sock) +int sock; +{ + int i = 0, size, pos; + char apubuf[STDINBUFSIZE+1]; + fd_set ready; + + do { + if (sock < 0 || QuitFlag) + return; + FD_ZERO(&ready); + FD_SET(sock, &ready); + FD_SET(0, &ready); +#ifdef DOCURSES + if (termtype == CURSES_TERM) + move(LINES-1,i); refresh(); +#endif +#ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) + tcap_move (-1, i); +#endif + if (select(32, (SELECT_FDSET_TYPE *)&ready, 0, 0, NULL) < 0) { +/* perror("select"); */ + continue; + } + if (FD_ISSET(sock, &ready)) { + if ((size = read(sock, apubuf, STDINBUFSIZE)) < 0) + perror("receiving stream packet"); + if (size <= 0) { + close(sock); + return; + } + dopacket(&me, apubuf, size); + } +#ifndef AUTOMATON + if (FD_ISSET(0, &ready)) { + if ((size = read(0, apubuf, STDINBUFSIZE)) < 0) { + putline("FATAL ERROR: End of stdin file !"); + return; + } + for (pos = 0; pos < size; pos++) { + i=do_char(apubuf[pos]); +#ifdef DOCURSES + if (termtype == CURSES_TERM) + move(LINES-1, i); +#endif +#ifdef DOTERMCAP + if (termtype == CURSES_TERM) + tcap_move(-1, i); +#endif + } + } +#endif /* AUTOMATON */ + } while (1); +} diff --git a/irc/c_bsd_ext.h b/irc/c_bsd_ext.h new file mode 100644 index 0000000..fdd3500 --- /dev/null +++ b/irc/c_bsd_ext.h @@ -0,0 +1,39 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_bsd_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/c_bsd.c. + */ + +/* External definitions for global variables. + */ +#ifndef C_BSD_C +extern char c_bsd_id[]; +#endif /* C_BSD_C */ + +/* External definitions for global functions. + */ +#ifndef C_BSD_C +#define EXTERN extern +#else /* C_BSD_C */ +#define EXTERN +#endif /* C_BSD_C */ +EXTERN int client_init __P((char *host, int portnum, aClient *cptr)); +EXTERN void client_loop __P((int sock)); +#undef EXTERN diff --git a/irc/c_conf.c b/irc/c_conf.c new file mode 100644 index 0000000..ee980f2 --- /dev/null +++ b/irc/c_conf.c @@ -0,0 +1,95 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_conf.c + * Copyright (C) 1990 Jarkko Oikarinen and + * University of Oulu, Computing Center + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: c_conf.c,v 1.3 1999/02/21 00:33:45 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define C_CONF_C +#include "c_externs.h" +#undef C_CONF_C + +initconf(host, passwd, myname, port) +char *host, *passwd, *myname; +int *port; +{ + FILE *fd; + char line[256], *tmp; + + if ((fd = fopen(IRCDCONF_PATH, "r")) == NULL) + return /* (-1) */ ; + while (fgets(line,255,fd)) { + if (line[0] == '#' || line[0] == '\n' || + line[0] == ' ' || line[0] == '\t') + continue; + switch (*getfield(line)) + { + case 'C': /* Server where I should try to connect */ + case 'c': /* in case of link failures */ + case 'I': /* Just plain normal irc client trying */ + case 'i': /* to connect me */ + case 'N': /* Server where I should NOT try to */ + case 'n': /* connect in case of link failures */ + /* but which tries to connect ME */ + case 'O': /* Operator. Line should contain at least */ + case 'o': /* password and host where connection is */ + /* allowed from */ + case 'M': /* Me. Host field is name used for this host */ + case 'm': /* and port number is the number of the port */ + case 'a': + case 'A': + case 'k': + case 'K': + case 'q': + case 'Q': + case 'l': + case 'L': + case 'y': + case 'Y': + case 'h': + case 'H': + case 'p': + case 'P': + break; + case 'U': /* Uphost, ie. host where client reading */ + case 'u': /* this should connect. */ + if (!(tmp = getfield(NULL))) + break; + strncpyzt(host, tmp, HOSTLEN); + if (!(tmp = getfield(NULL))) + break; + strncpyzt(passwd, tmp, PASSWDLEN); + if (!(tmp = getfield(NULL))) + break; + strncpyzt(myname, tmp, HOSTLEN); + if (!(tmp = getfield(NULL))) + break; + if ((*port = atoi(tmp)) == 0) + debug(DEBUG_ERROR, + "Error in config file, bad port field"); + break; + default: +/* debug(DEBUG_ERROR, "Error in config file: %s", line); */ + break; + } + } +} diff --git a/irc/c_conf_ext.h b/irc/c_conf_ext.h new file mode 100644 index 0000000..a46e39b --- /dev/null +++ b/irc/c_conf_ext.h @@ -0,0 +1,38 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_conf_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/c_conf.c. + */ + +/* External definitions for global variables. + */ +#ifndef C_CONF_C +extern char conf_id[]; +#endif /* C_CONF_C */ + +/* External definitions for global functions. + */ +#ifndef C_CONF_C +#define EXTERN extern +#else /* C_CONF_C */ +#define EXTERN +#endif /* C_CONF_C */ +EXTERN initconf __P((char *host, char *passwd, char *myname, int *port)); +#undef EXTERN diff --git a/irc/c_debug.c b/irc/c_debug.c new file mode 100644 index 0000000..4cf9156 --- /dev/null +++ b/irc/c_debug.c @@ -0,0 +1,61 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_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 rcsid[] = "@(#)$Id: c_debug.c,v 1.3 1998/05/12 16:55:49 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define C_DEBUG_C +#include "c_externs.h" +#undef C_DEBUG_C + +struct stats ircst, *ircstp = &ircst; + +#ifdef DEBUGMODE +#if ! USE_STDARG +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; +#else +void debug(int level, char *form, ...) +#endif +{ + if (debuglevel >= 0) + if (level <= debuglevel) { + char buf[512]; +#if ! USE_STDARG + (void)sprintf(buf, form, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#else + va_list va; + va_start(va, form); + (void)vsprintf(buf, form, va); + va_end(va); +#endif + putline(buf); + } +} +#else /* do nothing */ +void debug() +{ +} +#endif diff --git a/irc/c_debug_ext.h b/irc/c_debug_ext.h new file mode 100644 index 0000000..bb7ef4a --- /dev/null +++ b/irc/c_debug_ext.h @@ -0,0 +1,49 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_debug_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/c_debug.c. + */ + +/* External definitions for global variables. + */ +#ifndef C_DEBUG_C +extern char debug_id[]; +extern struct stats ircst, *ircstp; +#endif /* C_DEBUG_C */ + +/* External definitions for global functions. + */ +#ifndef C_DEBUG_C +#define EXTERN extern +#else /* C_DEBUG_C */ +#define EXTERN +#endif /* C_DEBUG_C */ +#ifdef DEBUGMODE +#if ! USE_STDARG +EXTERN void debug __P((int level, char *form, char *p1, char *p2, char *p3, + char *p4, char *p5, char *p6, char *p7, char *p8, + char *p9, char *p10)); +#else +EXTERN void debug __P((int level, char *form, ...)); +#endif +#else +EXTERN void debug(); +#endif +#undef EXTERN diff --git a/irc/c_defines.h b/irc/c_defines.h new file mode 100644 index 0000000..f0982a0 --- /dev/null +++ b/irc/c_defines.h @@ -0,0 +1,35 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_defines.h + * Copyright (C) 1997 Alain Nissen + * + * 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 includes all files defining constants, macros and types + definitions used by the IRC client. + */ + +#include "config.h" +#include "patchlevel.h" + +#include "common_def.h" +#include "dbuf_def.h" +#include "class_def.h" +#include "struct_def.h" +#include "msg_def.h" +#include "numeric_def.h" +#include "support_def.h" +#include "irc_def.h" +#include "help_def.h" diff --git a/irc/c_externs.h b/irc/c_externs.h new file mode 100644 index 0000000..269efc8 --- /dev/null +++ b/irc/c_externs.h @@ -0,0 +1,44 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_externs.h + * Copyright (C) 1997 Alain Nissen + * + * 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 includes all *_ext.h files containing external declarations + * for the IRC client. + */ + +#include "bsd_ext.h" +#include "c_bsd_ext.h" +#include "c_conf_ext.h" +#include "c_debug_ext.h" +#include "c_msg_ext.h" +#include "c_numeric_ext.h" +#include "c_version_ext.h" +#include "ctcp_ext.h" +#include "dbuf_ext.h" +#include "edit_ext.h" +#include "help_ext.h" +#include "ignore_ext.h" +#include "irc_ext.h" +#include "match_ext.h" +#include "packet_ext.h" +#include "parse_ext.h" +#include "screen_ext.h" +#include "send_ext.h" +#include "str_ext.h" +#include "support_ext.h" +#include "swear_ext.h" diff --git a/irc/c_msg.c b/irc/c_msg.c new file mode 100644 index 0000000..b571b7d --- /dev/null +++ b/irc/c_msg.c @@ -0,0 +1,407 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_msg.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 rcsid[] = "@(#)$Id: c_msg.c,v 1.3 1999/02/21 00:14:59 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define C_MSG_C +#include "c_externs.h" +#undef C_MSG_C + +char mybuf[513]; + +void m_die() { + exit(-1); +} + +int m_mode(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + strcpy(mybuf, "*** Mode change "); + while (parc--) { + strcat(mybuf, parv[0]); + strcat(mybuf, " "); + parv++; + } + putline(mybuf); + return 0; +} + +int m_wall(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf, "*** #%s# %s", parv[0], parv[1]); + putline(mybuf); + return 0; +} + +int m_wallops(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf, "*** =%s= %s %s", parv[0], parv[1], + BadPtr(parv[2]) ? "" : parv[2]); + putline(mybuf); + return 0; +} + +int m_ping(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + if (parv[2] && *parv[2]) + sendto_one(client, "PONG %s@%s %s", client->user->username, + client->sockhost, parv[2]); + else + sendto_one(client, "PONG %s@%s", client->user->username, client->sockhost); + return 0; +} + +int m_pong(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf, "*** Received PONG message: %s %s from %s", + parv[1], (parv[2]) ? parv[2] : "", parv[0]); + putline(mybuf); + return 0; +} + +int m_nick(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** Change: %s is now known as %s", parv[0], parv[1]); + if (!mycmp(me.name, parv[0])) { + strcpy(me.name, parv[1]); + write_statusline(); + } + putline(mybuf); +#ifdef AUTOMATON + a_nick(parv[0], parv[1]); +#endif + return 0; +} + +void m_away(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** %s is away: \"%s\"",parv[0], parv[1]); + putline(mybuf); +} + +int m_server(sptr, cptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** New server: %s", parv[1]); + putline(mybuf); + return 0; +} + +int m_topic(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf, "*** %s changed the topic on %s to: %s", + parv[0], parv[1], parv[2]); + putline(mybuf); + return 0; +} + +int m_join(sptr, cptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + char *tmp = index(parv[1], '\007'); /* Find o/v mode in 2.9 */ + + if (tmp) + *tmp = ' '; + sprintf(mybuf,"*** %s <%s> joined channel %s", + parv[0], userhost, parv[1]); + putline(mybuf); + return 0; +} + +int m_part(sptr, cptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** Change: %s has left channel %s (%s)", + parv[0], parv[1], BadPtr(parv[2]) ? parv[1] : parv[2]); + putline(mybuf); + return 0; +} + +void m_version(sptr, cptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** Version: %s", parv[1]); + putline(mybuf); +} + +void m_bye() +{ +#if defined(DOCURSES) && !defined(AUTOMATON) && !defined(VMSP) + echo(); + nocrmode(); + clear(); + refresh(); +#endif + exit(-1); +} + +int m_quit(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** Signoff: %s (%s)", parv[0], parv[1]); + putline(mybuf); +#ifdef AUTOMATON + a_quit(sender); +#endif + return 0; +} + +int m_kill(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** Kill: %s (%s)", parv[0], parv[2]); + putline(mybuf); + return 0; +} + +void m_info(sptr, cptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** Info: %s", parv[1]); + putline(mybuf); +} + +void m_squit(sptr, cptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** Server %s has died. Snif.", parv[1]); + putline(mybuf); +} + +void m_newwhoreply(channel, username, host, nickname, away, realname) +char *channel, *username, *host, *nickname, *away, *realname; +{ + /* ...dirty hack, just assume all parameters present.. --msa */ + + if (*away == 'S') + sprintf(mybuf, " %-13s %s %-42s %s", + "Nickname", "Chan", "Name", "<User@Host>"); + else { + int i; + char uh[USERLEN + HOSTLEN + 1]; + if (!realname) + realname = ""; + if (!username) + username = ""; + i = 50-strlen(realname)-strlen(username); + + if (channel[0] == '*') + channel = ""; + + if (strlen(host) > (size_t) i) /* kludge --argv */ + host += strlen(host) - (size_t) i; + + sprintf(uh, "%s@%s", username, host); + + sprintf(mybuf, "%c %s%s %*s %s %*s", + away[0], nickname, away+1, + (int)(21-strlen(nickname)-strlen(away)), channel, + realname, + (int)(53-strlen(realname)), uh); + } +} + +void m_newnamreply(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + if (parv[2]) { + switch (parv[2][0]) { + case '*': + sprintf(mybuf,"Prv: %-3s %s", parv[3], parv[4]); + break; + case '=': + sprintf(mybuf,"Pub: %-3s %s", parv[3], parv[4]); + break; + case '@': + sprintf(mybuf,"Sec: %-3s %s", parv[3], parv[4]); + break; + default: + sprintf(mybuf,"???: %s %s %s", parv[3], parv[4], parv[5]); + break; + } + } else + sprintf(mybuf, "*** Internal Error: namreply"); +} + +void m_linreply(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** Server: %s (%s) %s", parv[2], parv[3], parv[4]); +} + +int m_private(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + anIgnore *iptr; + + iptr = find_ignore(parv[0], (anIgnore *)NULL, userhost); + if ((iptr != (anIgnore *)NULL) && + ((iptr->flags == IGNORE_TOTAL) || + (IsChannelName(parv[1]) && (iptr->flags & IGNORE_PUBLIC)) || + (!IsChannelName(parv[1]) && (iptr->flags & IGNORE_PRIVATE)))) + return 0; + check_ctcp(sptr, cptr, parc, parv); + + if (parv[0] && *parv[0]) { +#ifdef AUTOMATON + a_privmsg(sender, parv[2]); +#else + if (((*parv[1] >= '0') && (*parv[1] <= '9')) || + (*parv[1] == '-') || (*parv[1] == '+') || + IsChannelName(parv[1]) || (*parv[1] == '$')) { + sprintf(mybuf,"<%s:%s> %s", parv[0], parv[1], parv[2]); + } else { + sprintf(mybuf,"*%s* %s", parv[0], parv[2]); + last_to_me(parv[0]); + } + putline(mybuf); +#endif + } else + putline(parv[2]); /* parv[2] and no parv[0] ?! - avalon */ + return 0; +} + + +int m_kick(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** %s kicked %s off channel %s (%s)", + (parv[0]) ? parv[0] : "*Unknown*", + (parv[2]) ? parv[2] : "*Unknown*", + (parv[1]) ? parv[1] : "*Unknown*", + parv[3]); + if (!mycmp(me.name, parv[2])) { + free(querychannel); + querychannel = (char *)malloc(strlen(me.name) + 1); + strcpy(querychannel, me.name); /* Kludge? */ + } + putline(mybuf); + return 0; +} + +int m_notice(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + anIgnore *iptr; + + iptr = find_ignore(parv[0], (anIgnore *)NULL, userhost); + if ((iptr != (anIgnore *)NULL) && + ((iptr->flags == IGNORE_TOTAL) || + (IsChannelName(parv[1]) && (iptr->flags & IGNORE_PUBLIC)) || + (!IsChannelName(parv[1]) && (iptr->flags & IGNORE_PRIVATE)))) + return 0; + + if (parv[0] && parv[0][0] && parv[1]) { + if ((*parv[1] >= '0' && *parv[1] <= '9') || + *parv[1] == '-' || IsChannelName(parv[1]) || + *parv[1] == '$' || *parv[1] == '+') + sprintf(mybuf,"(%s:%s) %s",parv[0],parv[1],parv[2]); + else if (index(userhost, '@')) /* user */ + sprintf(mybuf, "-%s- %s", parv[0], parv[2]); + else /* service */ + sprintf(mybuf, "-%s@%s- %s", + parv[0], userhost, parv[2]); + putline(mybuf); + } else + putline(parv[2]); + return 0; +} + +int m_invite(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + anIgnore *iptr; + if ((iptr = find_ignore(parv[0], (anIgnore *)NULL, userhost)) && + (iptr->flags & IGNORE_PRIVATE)) + return 0; +#ifdef AUTOMATON + a_invite(parv[0], parv[2]); +#else + sprintf(mybuf,"*** %s Invites you to channel %s", parv[0], parv[2]); + putline(mybuf); +#endif + return 0; +} + +int m_error(sptr, cptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + sprintf(mybuf,"*** Error: %s %s", parv[1], (parv[2]) ? parv[2] : ""); + putline(mybuf); + return 0; +} + diff --git a/irc/c_msg_ext.h b/irc/c_msg_ext.h new file mode 100644 index 0000000..8c5949d --- /dev/null +++ b/irc/c_msg_ext.h @@ -0,0 +1,76 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_msg_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/c_msg.c. + */ + +/* External definitions for global variables. + */ +#ifndef C_MSG_C +#ifndef lint +extern char c_msg_id[]; +#endif +extern char mybuf[]; +#endif /* C_MSG_C */ + +/* External definitions for global functions. + */ +#ifndef C_MSG_C +#define EXTERN extern +#else /* C_MSG_C */ +#define EXTERN +#endif /* C_MSG_C */ +EXTERN void m_die(); +EXTERN int m_mode __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN int m_wall __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN int m_wallops __P((aClient *sptr, aClient *cptr, int parc, + char *parv[])); +EXTERN int m_ping __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN int m_pong __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN int m_nick __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN void m_away __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN int m_server __P((aClient *sptr, aClient *cptr, int parc, + char *parv[])); +EXTERN int m_topic __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN int m_join __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN int m_part __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN void m_version __P((aClient *sptr, aClient *cptr, int parc, + char *parv[])); +EXTERN void m_bye(); +EXTERN int m_quit __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN int m_kill __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN void m_info __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN void m_squit __P((aClient *sptr, aClient *cptr, int parc, + char *parv[])); +EXTERN void m_newwhoreply __P((char *channel, char *username, char *host, + char *nickname, char *away, char *realname)); +EXTERN void m_newnamreply __P((aClient *sptr, aClient *cptr, int parc, + char *parv[])); +EXTERN void m_linreply __P((aClient *sptr, aClient *cptr, int parc, + char *parv[])); +EXTERN int m_private __P((aClient *sptr, aClient *cptr, int parc, + char *parv[])); +EXTERN int m_kick __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +EXTERN int m_notice __P((aClient *sptr, aClient *cptr, int parc, + char *parv[])); +EXTERN int m_invite __P((aClient *sptr, aClient *cptr, int parc, + char *parv[])); +EXTERN int m_error __P((aClient *sptr, aClient *cptr, int parc, char *parv[])); +#undef EXTERN diff --git a/irc/c_numeric.c b/irc/c_numeric.c new file mode 100644 index 0000000..f124a05 --- /dev/null +++ b/irc/c_numeric.c @@ -0,0 +1,413 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_numeric.c + * 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. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: c_numeric.c,v 1.3 1997/09/03 17:45:35 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define C_NUMERIC_C +#include "c_externs.h" +#undef C_NUMERIC_C + +/* +** 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). +*/ + +int do_numeric(numeric, cptr, sptr, parc, parv) +int numeric; +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + char *tmp; + int i; + time_t l; /* ctime(&l) on STATS L */ + + /* ...make sure undefined parameters point to empty string */ + for (i = parc; i < MAXPARA; parv[i++] = ""); + + switch (numeric) + { + case ERR_NOSUCHNICK: + sprintf(mybuf, "*** Error: %s: %s (%s)", + parv[0], parv[3], parv[2]); + sendto_one(&me, "WHOWAS %s 1", parv[2]); + break; + case ERR_WASNOSUCHNICK: + mybuf[0] = '\0'; + break; + case ERR_NOSUCHSERVER: + sprintf(mybuf, "*** Error: %s: No such server (%s)", + parv[0], parv[2]); + break; + case ERR_NOSUCHCHANNEL: + sprintf(mybuf, "*** Error: %s: No such channel (%s)", + parv[0], parv[2]); + break; + case ERR_NOSUCHSERVICE: + sprintf(mybuf, "*** Error: %s: No such service (%s)", + parv[0], parv[2]); + break; + case ERR_TOOMANYCHANNELS: + sprintf(mybuf, "*** Error: %s: You have join max. channels", + parv[0]); + break; + case ERR_TOOMANYTARGETS: + sprintf(mybuf, "*** Error: %s: Too many targets given", + parv[0]); + break; + case ERR_NORECIPIENT: + sprintf(mybuf, "*** Error: %s: Message had no recipient", + parv[0]); + break; + case ERR_NOTEXTTOSEND: + sprintf(mybuf, "*** Error: %s: Empty messages cannot be sent", + parv[0]); + break; + case ERR_NOTOPLEVEL: + sprintf(mybuf, "*** Error: %s: No toplevel domainname given", + parv[0]); + break; + case ERR_WILDTOPLEVEL: + sprintf(mybuf, "*** Error: %s: Wildcard in toplevel name", + parv[0]); + break; + case ERR_UNKNOWNCOMMAND: + sprintf(mybuf, "*** Error: %s: Unknown command (%s)", + parv[0],parv[2]); + break; + case ERR_NONICKNAMEGIVEN: + sprintf(mybuf, "*** Error: %s: No nickname given", parv[0]); + break; + case ERR_ERRONEUSNICKNAME: + sprintf(mybuf, + "*** Error: %s: Some special characters cannot %s", + parv[0], "be used in nicknames"); + break; + case ERR_NICKNAMEINUSE: + sprintf(mybuf, + "*** Error: %s: Nickname %s is already in use. %s", + parv[0], parv[2], "Please choose another."); + break; + case ERR_SERVICENAMEINUSE: + sprintf(mybuf, "*** Error: %s: Service %s is already in use.", + parv[0], parv[2]); + break; + case ERR_SERVICECONFUSED: + sprintf(mybuf, "Error: %s: Your service name is confused", + parv[0]); + break; + case ERR_USERNOTINCHANNEL: + sprintf(mybuf, "*** Error: %s: %s", parv[0], + (parv[2][0]) ? parv[2] : + "You have not joined any channel"); + break; + case ERR_NOTONCHANNEL: + sprintf(mybuf, "*** Error: %s: %s %s", + parv[0], parv[3], parv[2]); + break; + case ERR_INVITEONLYCHAN: + sprintf(mybuf, "*** Error: %s: %s", parv[0], + "Magic locks open only with an invitation key"); + break; + case ERR_BANNEDFROMCHAN: + sprintf(mybuf,"*** Error: %s: %s %s", + parv[0], "You are banned from the channel", parv[2]); + break; + case ERR_NOTREGISTERED: + sprintf(mybuf, "*** Error: %s: %s", parv[0], + (parv[2][0]) ? parv[2] : + "You have not registered yourself yet"); + break; + case ERR_NEEDMOREPARAMS: + sprintf(mybuf, "*** Error: %s: %s: %s", parv[0], parv[2], + (parv[3][0]) ? parv[3] : "Not enough parameters"); + break; + case ERR_ALREADYREGISTRED: + sprintf(mybuf, "*** Error: %s: %s", parv[0], + (parv[2][0]) ? parv[2] : "Identity problems, eh ?"); + break; + case ERR_NOPERMFORHOST: + sprintf(mybuf, "*** Error: %s: %s", parv[0], + (parv[2][0]) ? parv[2] : + "Your host isn't among the privileged"); + break; + case ERR_PASSWDMISMATCH: + sprintf(mybuf, "*** Error: %s: %s", parv[0], + (parv[2][0]) ? parv[2] : "Incorrect password"); + break; + case ERR_YOUREBANNEDCREEP: + sprintf(mybuf, "*** %s: %s", parv[0], + (parv[2][0]) ? parv[2] : + "You're banned from irc..."); + break; + case ERR_YOUWILLBEBANNED: + sprintf(mybuf, "*** Warning: You will be banned in %d minutes", + atoi(parv[2])); + break; + case ERR_CHANNELISFULL: + sprintf(mybuf, "*** Error: %s: Channel %s is full", + parv[0], parv[2]); + break; + case ERR_CANNOTSENDTOCHAN: + sprintf(mybuf, "*** Error: Sending to channel is %s", + "forbidden from heathens"); + break; + case ERR_NOPRIVILEGES: + sprintf(mybuf, "*** Error: %s: %s", parv[0], + (parv[2][0]) ? parv[2] : + "Only few and chosen are granted privileges. You're not one."); + break; + case ERR_NOOPERHOST: + sprintf(mybuf, "*** Error: %s: %s", parv[0], + (parv[2][0]) ? parv[2] : + "Only few of mere mortals may try to enter the twilight zone.."); + break; + case ERR_UMODEUNKNOWNFLAG: + sprintf(mybuf, "*** Error: %s: Unknown User Mode Flag", + parv[0]); + break; + case ERR_USERSDONTMATCH: + sprintf(mybuf, "*** Error: %s: Can only change your own mode", + parv[0]); + break; + case RPL_AWAY: + sprintf(mybuf, "*** %s: %s is away: %s", parv[0], + (parv[2][0]) ? parv[2] : "*Unknown*", + (parv[3][0]) ? parv[3] : "*No message (strange)*"); + break; + case RPL_USERHOST: + sprintf(mybuf, "*** USERHOST reply: %s", parv[2]); + break; + case RPL_ISON: + sprintf(mybuf, "*** ISON reply: %s", parv[2]); + break; + case RPL_WHOISUSER: + sprintf(mybuf, "*** %s is %s@%s (%s)", + parv[2], parv[3], parv[4], parv[6]); + break; + case RPL_WHOWASUSER: + sprintf(mybuf, "*** %s was %s@%s (%s)", + parv[2], parv[3], parv[4], parv[6]); + break; + case RPL_WHOISSERVER: + if (parc == 4) + sprintf(mybuf, "*** On irc via server %s (%s)", + parv[2], parv[3]); + else + sprintf(mybuf, "*** On irc via server %s (%s)", + parv[3], parv[4]); + break; + case RPL_WHOISOPERATOR: + sprintf(mybuf, "*** %s has a connection to the twilight zone", + parv[2]); + break; + case RPL_WHOISCHANOP: + sprintf(mybuf, "*** %s has been touched by magic forces", + parv[2]); + break; + case RPL_WHOISIDLE: + sprintf(mybuf, "*** %s %s %s", + parv[2], parv[3], parv[4]); + break; + case RPL_WHOISCHANNELS: + sprintf(mybuf, "*** On Channels: %s", parv[3]); + break; + case RPL_LISTSTART: + sprintf(mybuf, "*** Chn Users Name"); + break; + case RPL_LIST: + sprintf(mybuf, "*** %3s %5s %s", + (parv[2][0] == '*') ? "Prv" : parv[2], + parv[3], parv[4]); + break; + case RPL_LISTEND: + mybuf[0] = '\0'; + break; + case RPL_NOTOPIC: + sprintf(mybuf, "*** %s: No Topic is set", parv[0]); + break; + case RPL_TOPIC: + sprintf(mybuf, "*** %s: Topic on %s is: %s", parv[0], parv[2], + parv[3]); + break; + case RPL_INVITING: + sprintf(mybuf, "*** %s: Inviting user %s into channel %s", + parv[0], parv[2], parv[3]); + break; + case RPL_VERSION: + /* sprintf(mybuf, "*** %s: Server %s runs ircd %s (%s)", parv[0], */ + sprintf(mybuf, "*** Server %s runs ircd %s (%s)", + parv[3], parv[2], parv[4]); + break; + case RPL_KILLDONE: + sprintf(mybuf, "*** %s: May %s rest in peace", + parv[0], parv[2]); + break; + case RPL_INFO: + sprintf(mybuf, "*** %s: Info: %s", parv[0], parv[2]); + break; +#if 1 + case RPL_MOTD: + sprintf(mybuf, "*** %s: Motd: %s", parv[0], parv[2]); + break; +#endif /* 0 Looks better this way! -Vesa */ + case RPL_YOUREOPER: + sprintf(mybuf, "*** %s: %s", parv[0], (parv[2][0] == '\0') ? + "You have operator privileges now. Be nice to mere mortal souls" : + parv[2]); + break; + case RPL_NOTOPERANYMORE: + sprintf(mybuf, "*** %s: You are No Longer Have Operator %s", + parv[0], "Privileges"); + break; + case RPL_REHASHING: + sprintf(mybuf, "*** %s: %s", parv[0], (parv[2][0] == '\0') ? + "Rereading configuration file.." : parv[2]); + break; + case RPL_MYPORTIS: + sprintf(mybuf, "*** %s: %s %s", parv[0], parv[2], parv[1]); + break; + case RPL_TIME: + sprintf(mybuf, "*** Time on host %s is %s", + parv[2], parv[3]); + break; + case RPL_CHANNELMODEIS: + sprintf(mybuf, "*** Mode is %s %s %s", + parv[2], parv[3], parv[4]); + break; + case RPL_LINKS: + m_linreply(cptr, sptr, parc, parv); + break; + case RPL_WHOREPLY: + m_newwhoreply(parv[2],parv[3],parv[4],parv[6],parv[7],parv[8]); + break; + case RPL_NAMREPLY: + m_newnamreply(cptr, sptr, parc, parv); + break; + case RPL_BANLIST: + sprintf(mybuf, "*** %s is banned on %s", + parv[3], parv[2]); + break; + case RPL_TRACELINK: + sprintf(mybuf,"%s<%s> Link %s> %s (%s up %s) bQ:%s fQ:%s", + parv[0], parv[3], parv[6], parv[4], parv[5], parv[7], + parv[8], parv[9]); + break; + case RPL_TRACESERVER: + if (parc <= 5) + sprintf(mybuf,"*** %s Class: %s %s: %s", + parv[0], parv[3], parv[2], parv[4]); + else + sprintf(mybuf,"*** %s %s Cl:%s %s/%s %s %s %s", + parv[0], parv[2], parv[3], parv[4], + parv[5], parv[6], parv[7], parv[8]); + break; + case RPL_TRACECONNECTING: + case RPL_TRACEHANDSHAKE: + case RPL_TRACEUNKNOWN: + case RPL_TRACEOPERATOR: + case RPL_TRACEUSER: + case RPL_TRACESERVICE: + case RPL_TRACENEWTYPE: + sprintf(mybuf,"*** %s %s Class: %s %s", + parv[0], parv[2], parv[3], parv[4]); + break; + case RPL_TRACELOG: + sprintf(mybuf,"*** %s File: %s level:%s ", + parv[0], parv[3], parv[4]); + break; + case RPL_TRACECLASS: + sprintf(mybuf,"*** %s Class: %s Links: %s", + parv[0], parv[3], parv[4]); + break; + case RPL_STATSLINKINFO: + l = time(NULL) - atol(parv[8]); /* count startup time */ + tmp = (char *) ctime(&l); + *((char *) index(tmp, '\n')) = (char) '\0'; /* remove '\n' */ + sprintf(mybuf,"*** %s: %s Q:%s sM:%s sB:%s rM:%s rB:%s D:%s", + parv[0], parv[2], parv[3], parv[4], parv[5], + parv[6], parv[7], tmp); + break; + case RPL_STATSCOMMANDS: + sprintf(mybuf, "*** %s: %s has been used %s times (%s bytes)", + parv[0], parv[2], parv[3], parv[4]); + break; + case RPL_STATSYLINE: + sprintf(mybuf, "*** %s: Cl:%s Pf:%s Cf:%s Max:%s Sq:%s", + parv[0], parv[3], parv[4], + parv[5], parv[6], parv[7]); + break; + case RPL_UMODEIS: + sprintf(mybuf, "*** %s: Mode for user %s is %s", + parv[0], parv[1], parv[2]); + break; +#ifdef HIDE_NUMERICS + case RPL_STATSCLINE: + case RPL_STATSNLINE: + case RPL_STATSILINE: + sprintf(mybuf, "*** %s: %s:%s:*:%s:%s:%s", + parv[0], parv[2], parv[3], parv[5], parv[6], parv[7]); + break; + case RPL_STATSKLINE: + case RPL_STATSQLINE: + sprintf(mybuf, "*** %s: %s:%s:%s:%s:%s:%s", + parv[0], parv[2], parv[3], parv[4], + parv[5], parv[6], parv[7]); + break; + case RPL_SERVICEINFO: + sprintf(mybuf, "*** %s: Info For Service %s: %s", + parv[0], parv[3], parv[4]); + break; + case RPL_ENDOFWHO: + case RPL_ENDOFWHOIS: + case RPL_ENDOFWHOWAS: + case RPL_ENDOFINFO: + case RPL_ENDOFMOTD: + case RPL_ENDOFUSERS: + case RPL_ENDOFLINKS: + case RPL_ENDOFNAMES: + case RPL_ENDOFSTATS: + case RPL_ENDOFBANLIST: + case RPL_ENDOFSERVICES: + mybuf[0] = '\0'; + break; +#endif /* !HIDE_NUMERICS */ + case RPL_WELCOME: + strcpy(me.name, parv[1]); + write_statusline(); + default: + sprintf(mybuf, "%03d %s %s %s %s %s %s %s %s %s", + numeric, parv[0], parv[2], + parv[3], parv[4], parv[5], parv[6], parv[7], + parv[8], parv[9]); + break; + } + if (mybuf[0]) + putline(mybuf); + return 0; +} diff --git a/irc/c_numeric_ext.h b/irc/c_numeric_ext.h new file mode 100644 index 0000000..087d058 --- /dev/null +++ b/irc/c_numeric_ext.h @@ -0,0 +1,39 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_numeric_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/c_numeric.c. + */ + +/* External definitions for global variables. + */ +#ifndef C_NUMERIC_C +extern char c_numeric_id[]; +#endif /* C_NUMERIC_C */ + +/* External definitions for global functions. + */ +#ifndef C_NUMERIC_C +#define EXTERN extern +#else /* C_NUMERIC_C */ +#define EXTERN +#endif /* C_NUMERIC_C */ +EXTERN int do_numeric __P((int numeric, aClient *cptr, aClient *sptr, int parc, + char *parv[])); +#undef EXTERN diff --git a/irc/c_version.c b/irc/c_version.c new file mode 100644 index 0000000..2060dce --- /dev/null +++ b/irc/c_version.c @@ -0,0 +1,46 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_version.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. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: c_version.c,v 1.3 1998/12/13 00:02:35 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define C_VERSION_C +#include "c_externs.h" +#undef C_VERSION_C + +char *intro = "Internet Relay Chat v%s"; +char *version; +char *infotext[] = + { + "Original code written by Jarkko Oikarinen <jto@tolsun.oulu.fi>", + "Copyright 1988,1989,1990 University of Oulu, Computing Center", + " and Jarkko Oikarinen", + 0, + }; + +char *HEADEROLD = +"*Internet Relay Chat* Type /help to get help * Client v%s * "; + +char *IRCHEADER = +" *IRC Client v%s* %10.10s on %10.10s */help for help* "; + diff --git a/irc/c_version_ext.h b/irc/c_version_ext.h new file mode 100644 index 0000000..34b5d6d --- /dev/null +++ b/irc/c_version_ext.h @@ -0,0 +1,32 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_version_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/c_version.c. + */ + +/* External definitions for global variables. + */ +#ifndef C_VERSION_C +extern char *intro; +extern char *version; +extern char *infotext[]; +extern char *HEADEROLD; +extern char *IRCHEADER; +#endif /* C_VERSION_C */ diff --git a/irc/ctcp.c b/irc/ctcp.c new file mode 100644 index 0000000..5c05a3d --- /dev/null +++ b/irc/ctcp.c @@ -0,0 +1,50 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/c_bsd.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. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: ctcp.c,v 1.2 1997/09/03 17:45:36 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define CTCP_C +#include "c_externs.h" +#undef CTCP_C + +#define CTCP_CHAR 0x1 + +void check_ctcp(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + char *front = NULL, *back = NULL; + + if (parc < 3) + return; + + if (!(front = index(parv[2], CTCP_CHAR))) + return; + if (!(back = index(++front, CTCP_CHAR))) + return; + *back = '\0'; + if (!strcmp(front, "VERSION")) + sendto_one(sptr, "NOTICE %s :%cVERSION %s%c", parv[0], + CTCP_CHAR, version, CTCP_CHAR); + *back = CTCP_CHAR; +} diff --git a/irc/ctcp_ext.h b/irc/ctcp_ext.h new file mode 100644 index 0000000..e5a8fc8 --- /dev/null +++ b/irc/ctcp_ext.h @@ -0,0 +1,33 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/ctcp_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/ctcp.c. + */ + +/* External definitions for global functions. + */ +#ifndef CTCP_C +#define EXTERN extern +#else /* CTCP_C */ +#define EXTERN +#endif /* CTCP_C */ +EXTERN void check_ctcp __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +#undef EXTERN diff --git a/irc/edit.c b/irc/edit.c new file mode 100644 index 0000000..3abe487 --- /dev/null +++ b/irc/edit.c @@ -0,0 +1,411 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/edit.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 rcsid[] = "@(#)$Id: edit.c,v 1.2 1997/09/03 17:45:37 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define EDIT_C +#include "c_externs.h" +#undef EDIT_C + +#define FROM_START 0 +#define FROM_END 1 +#define RELATIVE 2 + +static int esc=0; +static int literal=0; + +int do_char(ch) +char ch; +{ + static int first_time=0; + + if (!first_time) { + toggle_ins(); + toggle_ins(); + first_time=1; +#ifdef DOCURSES + if (termtype == CURSES_TERM) + refresh(); +#endif + } + if (esc == 1) { + do_after_esc(ch); + return tulosta_viimeinen_rivi(); + } + switch (ch) + { + case '\000': /* NULL */ + break; + case '\001': /* ^A */ + bol(); /* beginning of line */ + break; + case '\002': /* ^B */ + back_ch(); /* backward char */ + break; + case '\003': /* ^C */ + rev_line(); /* reverse line */ + break; + case '\004': /* ^D */ + del_ch_right(); /* delete char from right */ + break; + case '\005': /* ^E */ + eol(); /* end of line */ + break; + case '\006': /* ^F */ + forw_ch(); /* forward char */ + break; + case '\007': /* ^G */ + add_ch(ch); /* bell */ + break; + case '\010': /* ^H */ + del_ch_left(); /* delete char to left */ + break; + case '\011': /* TAB */ + toggle_ins(); /* toggle insert mode */ + break; + case '\012': /* ^J */ + send_this_line(); /* send this line */ + break; + case '\013': /* ^K */ + kill_eol(); /* kill to end of line */ + break; + case '\014': /* ^L */ + refresh_screen(); /* refresh screen */ + write_statusline(); + break; + case '\015': /* ^M */ + send_this_line(); /* send this line */ + break; + case '\016': /* ^N */ + next_in_history(); /* next in history */ + break; + case '\017': /* ^O */ + break; + case '\020': /* ^P */ + previous_in_history(); /* previous in history */ + break; + case '\021': /* ^Q */ + break; + case '\022': /* ^R */ + case '\023': /* ^S */ + case '\024': /* ^T */ + break; + case '\025': /* ^U */ + kill_whole_line(); /* kill whole line */ + break; + case '\026': /* ^V */ + literal_next(); /* literal next */ + break; + case '\027': /* ^W */ + del_word_left(); /* delete word left */ + break; + case '\030': /* ^X */ + break; + case '\031': /* ^Y */ + yank(); /* yank */ + break; + case '\032': /* ^Z */ + suspend_irc(0); /* suspend irc */ + break; + case '\033': /* ESC */ + got_esc(); + break; + case '\177': /* DEL */ + del_ch_left(); /* delete char to left */ + break; + default: + add_ch(ch); + break; + } + return tulosta_viimeinen_rivi(); +} + +void bol() +{ + set_position(0, FROM_START); +} + +void eol() +{ + set_position(0, FROM_END); + set_position(1, RELATIVE); +} + +void back_ch() +{ + set_position(-1, RELATIVE); +} + +void forw_ch() +{ + set_position(1, RELATIVE); +} + +void rev_line() +{ + int i1, i2, i3, i4; + + i4 = get_position(); + set_position(0, FROM_START); + i1 = get_position(); + set_position(0, FROM_END); + i1 = get_position()-i1; + set_position(i4, FROM_START); + + for (i2 = 0; i2 > i1/2; i2++) { + i3 = get_char(i2); + set_char(i2, get_char(i1-i2-1)); + set_char(i1-i2-1, i3); + } +} + +void del_ch_right() +{ + int i1, i2, i3; + + i1 = get_position(); + + if (!get_char(i1)) + return; /* last char in line */ + set_position(0, FROM_END); + i2 = get_position(); + for (i3 = i1; i3 < i2; i3++) + set_char(i3, get_char(i3+1)); + set_char(i3, 0); + set_position(i1, FROM_START); +} + +void del_ch_left() +{ + int i1, i2, i3; + + i1 = get_position(); + + if (!i1) + return; /* first pos in line */ + set_position(0, FROM_END); + i2 = get_position(); + for (i3 = i1-1; i3 < i2; i3++) + set_char(i3, get_char(i3+1)); + set_char(i3, 0); + set_position(i1, FROM_START); + set_position(-1, RELATIVE); +} + +RETSIGTYPE suspend_irc(s) +int s; +{ +#ifdef SIGTSTP + signal(SIGTSTP, suspend_irc); +# ifdef DOCURSES + if (termtype == CURSES_TERM) { + echo(); + nocrmode(); + } +# endif /* DOCURSES */ +# ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) + io_off(); +# endif /* DOTERMCAP */ +# ifdef SIGSTOP + kill(getpid(), SIGSTOP); +# endif /* SIGSTOP */ +# ifdef DOCURSES + if (termtype == CURSES_TERM) { + /* initscr(); */ + noecho(); + crmode(); + clear(); + refresh(); + } +# endif /* DOCURSES */ +# ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) { + io_on(1); + clearscreen(); + } +# endif /* DOTERMCAP */ + write_statusline(); +#else /* || */ +# if !defined(SVR3) + tstp(); +# endif +#endif /* || */ +} + +void got_esc() +{ + esc = 1; +} + +void do_after_esc(ch) +char ch; +{ + if (literal) { + literal = 0; + add_ch(ch); + return; + } + esc = 0; + switch (ch) + { + case 'b': + word_back(); + break; + case 'd': + del_word_right(); + break; + case 'f': + word_forw(); + break; + case 'y': + yank(); + break; + case '\177': + del_word_left(); + break; + default: + break; + } +} + +void refresh_screen() +{ +#ifdef DOCURSES + if (termtype == CURSES_TERM) { + clearok(curscr, TRUE); + refresh(); + } +#endif +} + +void add_ch(ch) +int ch; +{ + int i1, i2, i3; + + if (in_insert_mode()) { + i1 = get_position(); + set_position(0, FROM_END); + i2 = get_position(); + for (i3 = i2; i3 >= 0; i3--) + set_char(i1+i3+1, get_char(i3+i1)); + set_char(i1, ch); + set_position(i1, FROM_START); + set_position(1, RELATIVE); + } else { + i1 = get_position(); + set_char(i1, ch); + set_position(i1, FROM_START); + set_position(1, RELATIVE); + } +} + +void literal_next() +{ + got_esc(); + literal=1; +} + +void word_forw() +{ + int i1,i2; + + i1 = get_position(); + + while ((i2 = get_char(i1))) + if ((i2 == (int)' ') || (i2 == (int)'\t') || + (i2 == (int)'_') || (i2 == (int)'-')) + i1++; + else + break; + while ((i2 = get_char(i1))) + if ((i2 == (int)' ') || (i2 == (int)'\t') || + (i2 == (int)'_') || (i2 == (int)'-')) + break; + else + i1++; + set_position(i1, FROM_START); +} + +void word_back() +{ + int i1,i2; + + i1 = get_position(); + if (i1 != 0) + i1--; + + while ((i2 = get_char(i1))) + if ((i2 == (int)' ') || (i2 == (int)'\t') || + (i2 == (int)'_') || (i2 == (int)'-')) + i1--; + else + break; + while ((i2 = get_char(i1))) + if ((i2 == (int)' ') || (i2 == (int)'\t') || + (i2 == (int)'_') || (i2 == (int)'-')) + break; + else + i1--; + if (i1 <= 0) + i1 = 0; + else + i1++; + set_position(i1, FROM_START); +} + +void del_word_left() +{ + int i1, i2, i3, i4; + + i1 = get_position(); + word_back(); + i2 = get_position(); + set_position(0, FROM_END); + i3 = get_position(); + for(i4 = i2; i4 <= i3 - (i1 - i2); i4++) + set_char(i4, get_char(i4 + (i1 - i2))); + for(; i4 <= i3; i4++) + set_char(i4, (int)'\0'); + set_position(i2, FROM_START); +} + +void del_word_right() +{ + int i1, i2, i3, i4; + + i2 = get_position(); + word_forw(); + i1 = get_position(); + set_position(0, FROM_END); + i3 = get_position(); + for(i4 = i2; i4 <= i3 - (i1 - i2); i4++) + set_char(i4, get_char(i4 + (i1 - i2))); + for(; i4 <= i3; i4++) + set_char(i4, (int)'\0'); + set_position(i2, FROM_START); +} + + diff --git a/irc/edit_ext.h b/irc/edit_ext.h new file mode 100644 index 0000000..54a0963 --- /dev/null +++ b/irc/edit_ext.h @@ -0,0 +1,55 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/edit_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/edit.c. + */ + +/* External definitions for global variables. + */ +#ifndef EDIT_C +extern char edit_id[]; +#endif /* EDIT_C */ + +/* External definitions for global functions. + */ +#ifndef EDIT_C +#define EXTERN extern +#else /* EDIT_C */ +#define EXTERN +#endif /* EDIT_C */ +EXTERN int do_char __P((char ch)); +EXTERN void bol(); +EXTERN void eol(); +EXTERN void back_ch(); +EXTERN void forw_ch(); +EXTERN void rev_line(); +EXTERN void del_ch_right(); +EXTERN void del_ch_left(); +EXTERN RETSIGTYPE suspend_irc __P((int s)); +EXTERN void got_esc(); +EXTERN void do_after_esc __P((char ch)); +EXTERN void refresh_screen(); +EXTERN void add_ch __P((int ch)); +EXTERN void literal_next(); +EXTERN void word_forw(); +EXTERN void word_back(); +EXTERN void del_word_left(); +EXTERN void del_word_right(); +#undef EXTERN diff --git a/irc/help.c b/irc/help.c new file mode 100644 index 0000000..71d3dfe --- /dev/null +++ b/irc/help.c @@ -0,0 +1,228 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/help.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 rcsid[] = "@(#)$Id: help.c,v 1.2 1997/09/03 17:45:38 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define HELP_C +#include "c_externs.h" +#undef HELP_C + +struct Help helplist[] = { + { "ADMIN", "/ADMIN <server>", + { "Prints administrative information about an IRC server.", + "<server> defaults to your own IRC server.", "", "", "" } }, + { "AWAY", "/AWAY <message>", + { "<Mark yourself as being away. <message> is a message that will be", + "automatically sent to anyone who tries sending you a private message.", + "If you are already marked as being away, /AWAY will change your status", + "back to \"here.\"", "" } }, + { "BYE", "/BYE", + { "Exit from IRC. /BYE, /EXIT, /QUIT and /SIGNOFF are identical.", + "", "", "", "" } }, + { "CHANNEL", "/CHANNEL <channel>", + { "Leave the current channel and join a new one. Channel is any number", + "or a string beginning with a plus (+) sign. Numbered channels above 999", + "are private channels, you cannot see them by /LIST. Negative channels", + "are secret; they do not appear in /WHO at all. String channels are open", + "first, but the channel operators can change the mode with /MODE" } }, + { "CLEAR", "/CLEAR", + { "Clear your screen.", "", "", "", "" } }, + { "CMDCH", "/CMDCH <x>", + { "Changes your command prefix character to <x>. This is useful if you", + "often start lines with slashes. For example, after typing \"/cmdch #\"", + "your commands would look like #who or #links.", "", "" } }, + { "DATE", "/DATE <server>", + { "Prints the date and time local to a specific server. <server> defaults", + "to your own IRC server. /DATE and /TIME are identical.", "", "", "" } }, + { "EXIT", "/EXIT", + { "Exit from IRC. /BYE, /EXIT, /QUIT and /SIGNOFF are identical.", + "", "", "", "" } }, +#ifdef VMSP + { "EXEC", "/EXEC <CP/CMS command>", + { "Executes a CP/CMS command. If the command spends some time, you may", + "be signed off by the server. See UNKILL.", + "Warning: Screen is cleared after execcuting a command.", + "", "" } }, +#endif + { "HELP", "/HELP <command>", + { "/HELP without parameters lists all IRC commands.", + "/HELP followed by a command name prints a description of that command.", + "", "", "" } }, + { "IGNORE", "/IGNORE <+|-><nicknames>", + { "Allows you to automatically ignore messages from certain users. If", + "+ is specified before <nicknames>, only public messages are ignored.", + "Similarly, - ignores only private messages. If neither symbol is given", + "all messages are ignored. /IGNORE without parameters prints the current", + "list of ignored users." } }, + { "INFO", "/INFO", + { "Prints some information about IRC.", "", "", "", "" } }, + { "INVITE", "/INVITE <channel> <nickname>", + { "Invites a user to join your channel. The user must be currently using", + "IRC.", "", "", "" } }, + { "JOIN", "/JOIN <channel>{,<channel>} [<key>{,<key>}]", + { "Leave the current channel and join a new one. Channels above 999", + "are private channels; their numbers are not listed by /WHO. Negative", + "numbered channels are secret; they do not appear in /WHO at all.", + "/JOIN and /CHANNEL are identical.", "" } }, + { "KICK", "/KICK <channel> <user> [<comment>]", + { "Kicks specified user off given channel", + "Only channel operators are privileged to use this command", + "Channel operator privileges can be given to other users of channel", + "by command '/MODE <channel> +o <user>' and taken away by command", + "'/MODE <channel> -o <user>'" } }, + { "LINKS", "/LINKS [<pattern> [<server>]]", + { "Lists all active IRC servers.", + "If <pattern> is given, list all active irc links matching <pattern>", + "For example, /links *.fi lists all links in Finland", "", "" } }, + { "LIST", "/LIST", + { "Lists all active channels and, if set, their topics.", "", "", "", "" } }, + { "LUSERS", "/LUSERS", + { "Show the number of people and servers connected to the IRC network.", + "", "", "", "" } }, + { "LOG", "/LOG <filename>", + { "Sends a copy of your IRC session to a file.", + "/LOG followed by a filename begins logging in the given file.", + "/LOG with no parameters turns logging off.", "", "" } }, + { "MSG", "/MSG <nicknames> <message>", + { "Send a private message. <nicknames> should be one or more nicknames or", + "channel numbers separated by commas (no spaces). If <nicknames> is \",\"", + "your message is sent to the last person who sent you a private message.", + "If <nicknames> is \".\" it's sent to the last personyou sent one to.", + "Messages sent to , or . can (currently) contain no other recipients." } }, + { "MODE", "/MODE <channel> [+|-]<modechars> <parameters>", + { "Mode command is quite complicated and it allows channel operators to", + "change channel mode. <modechars> is one of m (moderated), s (secret),", + "p (private), l (limited), t (topiclimited), a (anonymous), o (oper)", + "i (inviteonly). + or - sign whether the specifies mode should be added", + "or deleted. Parameter for l is the maximum users allowed" } }, + { "MOTD", "/MOTD <server>", + { "Query for message-of-today in given server. If <server> parameter is", + "left out, query local server", "", "", "" } }, + { "NAMES", "/NAMES <channel>{,<channel>}", + { "/NAMES without a parameter lists the nicknames of users on all channels.", + "/NAMES followed by a channel number lists the names on that channel.", + "", "", "" } }, + { "NICK", "/NICK <nickname>", + { "Change your nickname. You cannot choose a nickname that is already in", + "use. Additionally, some characters cannot be used in nicknames.", + "", "", "" } }, + { "QUERY", "/QUERY <nicknames>", + { "Begin private chat with <nicknames>. All subsequent messages you type", + "will be automatically sent only to <nicknames>. /QUERY without", + "parameters ends any current chat. You can send a normal message to your", + "channel by prefixing it with a slash and a space, like \"/ hi\".", "" } }, + { "QUIT", "/QUIT [<comment>]", + { "Exit from IRC. /BYE, /EXIT, /QUIT and /SIGNOFF are identical.", + "", "", "", "" } }, + { "SERVER", "/SERVER <server>", + { "Disconnects from currect server and connects your client into a new", + "server specified in command line", "", "", "" } }, + { "SIGNOFF", "/SIGNOFF", + { "Exit from IRC. /BYE, /EXIT, /QUIT and /SIGNOFF are identical.", + "", "", "", "" } }, + { "STATS", "/STATS [<c|h|i|k|l|m|n|o|q|y>]", + { "Shows various IRC server statistics. This command is rather boring", + "", "", "", "" } }, + { "SUMMON", "/SUMMON <user> [<server>]", + { "Ask a user to enter IRC. <user> is of the form guest@tolsun.oulu.fi.", + "You can only summon users on machines where an IRC server is running.", + "Some servers may have disabled the /SUMMON command.", "", "" } }, + { "TIME", "/TIME <server>", + { "Prints the date and time local to a specific server. <server> defaults", + "to your own IRC server. /DATE and /TIME are identical.", "", "", "" } }, + { "TOPIC", "/TOPIC <channel> [<topic>]", + { "Sets the topic for the channel you're on.", "", "", "", "" } }, + { "UNKILL", "/UNKILL", + { "Orders to irc reconnect to server if you happen to become killed", + "accidentally or in purpose", "", "", "" } }, + { "USERS", "/USERS <host>", + { "List all users logged in to a host. The host must be running an IRC", + "server. Finger(1) usually works better.", "", "", "" } }, + { "VERSION", "/VERSION <server>", + { "Prints the version number of an IRC server. <server> defaults to your", + "own IRC server.", "", "", "" } }, + { "WHO", "/WHO <channel> [<o>]", + { "/WHO without parameters lists users on all channels.", + "/WHO followed by a channel number lists users on that channel.", + "/WHO * lists users that are on the same channel as you.", + "You cannot see users that are on negative-numbered channels.", "" } }, + { "WHOIS", "/WHOIS <nicknames>{,<nickname>}", + { "/WHOIS prints information about a particular user, including his or", + "her name, host name and IRC server. <nicknames> should be one of more", + "nicknames separated by commas.", "", "" } }, + { "WHOWAS", "/WHOWAS <nickname>{,<nickname>} [<count> [<server>]]", + { "/WHOWAS returns nickname history information for each of the given", + "nicknames.", "", "", "" } }, + { NULL, NULL, + { NULL, NULL, NULL, NULL, NULL } } +}; + +char helpbuf[80]; + +void do_help(ptr, temp) +char *ptr, *temp; +{ + struct Help *hptr; + int count; + + if (BadPtr(ptr)) { + sprintf(helpbuf, "*** Help: Internet Relay Chat v%s Commands:", version); + putline(helpbuf); + count = 0; + for (hptr = helplist; hptr->command; hptr++) { + sprintf(&helpbuf[count*10], "%10s", hptr->command); + if (++count >= 6) { + count = 0; + putline(helpbuf); + } + } + if (count) + putline(helpbuf); + putline("Type /HELP <command> to get help about a particular command."); + putline("For example \"/HELP signoff\" gives you help about the"); + putline("/SIGNOFF command. To use a command you must prefix it with a"); + putline("slash or whatever your current command character is (see"); + putline("\"/HELP cmdch\""); + putline("*** End Help"); + } else { + for (hptr = helplist; hptr->command; hptr++) + if (mycncmp(ptr, hptr->command)) + break; + + if (hptr->command == (char *) 0) { + putline("*** There is no help information for that command."); + putline("*** Type \"/HELP\" to get a list of commands."); + return; + } + sprintf(helpbuf, "*** Help: %s", hptr->syntax); + putline(helpbuf); + for (count = 0; count < 5; count++) + if (hptr->explanation[count] && *(hptr->explanation[count])) { + sprintf(helpbuf, " %s", hptr->explanation[count]); + putline(helpbuf); + } + putline("*** End Help"); + } +} + diff --git a/irc/help_def.h b/irc/help_def.h new file mode 100644 index 0000000..82a6769 --- /dev/null +++ b/irc/help_def.h @@ -0,0 +1,23 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/help_def.h + * 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. + */ + +struct Help { + char *command, *syntax, *explanation[5]; +}; diff --git a/irc/help_ext.h b/irc/help_ext.h new file mode 100644 index 0000000..6a85893 --- /dev/null +++ b/irc/help_ext.h @@ -0,0 +1,40 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/help_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/help.c. + */ + +/* External definitions for global variables. + */ +#ifndef HELP_C +extern struct Help helplist[]; +extern char help_id[]; +extern char helpbuf[]; +#endif /* HELP_C */ + +/* External definitions for global functions. + */ +#ifndef HELP_C +#define EXTERN extern +#else /* HELP_C */ +#define EXTERN +#endif /* HELP_C */ +EXTERN void do_help __P((char *ptr, char *temp)); +#undef EXTERN diff --git a/irc/ignore.c b/irc/ignore.c new file mode 100644 index 0000000..23bc5db --- /dev/null +++ b/irc/ignore.c @@ -0,0 +1,141 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/ignore.c + * 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. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: ignore.c,v 1.2 1997/09/03 17:45:39 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define IGNORE_C +#include "c_externs.h" +#undef IGNORE_C + +anIgnore *ignore = (anIgnore *) 0; +char ibuf[80]; + +void do_ignore(user, temp) +char *user, *temp; +{ + char *ch, *wild = "*"; + anIgnore *iptr; + char *apu = user, *uh; + int status; + if ((user == (char *) 0) || (*user == '\0')) { + + putline("*** Current ignore list entries:"); + for (iptr = ignore; iptr; iptr = iptr->next) { + sprintf(ibuf," Ignoring %s messages from user %s!%s", + (iptr->flags == IGNORE_TOTAL) ? "all" : + (iptr->flags == IGNORE_PRIVATE) ? "private" : "public", + iptr->user, iptr->from); + putline(ibuf); + } + putline("*** End of ignore list entries"); + return; + } + while (apu && *apu) { + ch = apu; + if (*ch == '+') { + ch++; + status = IGNORE_PUBLIC; + } + else if (*ch == '-') { + ch++; + status = IGNORE_PRIVATE; + } + else + status = IGNORE_TOTAL; + if ((apu = index(ch, ','))) + *(apu++) = '\0'; + if ((uh = index(ch, '!'))) + *uh++ = '\0'; + else if ((uh = index(ch, '@'))) + *uh++ = '\0'; + else + uh = wild; + if (!*ch) + ch = wild; + if ((iptr = find_ignore(ch, (anIgnore *)NULL, uh))) { + sprintf(ibuf,"*** Ignore removed: user %s!%s", + iptr->user, iptr->from); + putline(ibuf); + kill_ignore(iptr); + } else { + if (strlen(ch) > (size_t) NICKLEN) + ch[NICKLEN] = '\0'; + if (add_ignore(ch, status, uh) >= 0) { + sprintf(ibuf,"*** Ignore %s messages from user %s!%s", + (status == IGNORE_TOTAL) ? "all" : + (status == IGNORE_PRIVATE) ? "private" : "public", ch, uh); + putline(ibuf); + } else + putline("Fatal Error: Cannot allocate memory for ignore buffer"); + } + } +} + +anIgnore *find_ignore(user, para, fromhost) +char *user, *fromhost; +anIgnore *para; +{ + anIgnore *iptr; + for (iptr = ignore; iptr; iptr=iptr->next) + if ((match(iptr->user, user) == 0) && + (match(iptr->from, fromhost)==0)) + break; + + return iptr ? iptr : para; +} + +int kill_ignore(iptr) +anIgnore *iptr; +{ + anIgnore *i2ptr, *i3ptr = (anIgnore *) 0; + for (i2ptr = ignore; i2ptr; i2ptr = i2ptr->next) { + if (i2ptr == iptr) + break; + i3ptr = i2ptr; + } + if (i2ptr) { + if (i3ptr) + i3ptr->next = i2ptr->next; + else + ignore = i2ptr->next; + free(i2ptr); + return (1); + } + return (-1); +} + +int add_ignore(ch, status, fromhost) +char *ch, *fromhost; +int status; +{ + anIgnore *iptr; + iptr = (anIgnore *) malloc(sizeof (anIgnore)); + if (iptr == (anIgnore *) 0) + return(-1); + strncpyzt(iptr->user, ch, sizeof(iptr->user)); + strncpyzt(iptr->from, fromhost, sizeof(iptr->from)); + iptr->next = ignore; + ignore = iptr; + iptr->flags = status; + return(1); +} diff --git a/irc/ignore_ext.h b/irc/ignore_ext.h new file mode 100644 index 0000000..f2e3d16 --- /dev/null +++ b/irc/ignore_ext.h @@ -0,0 +1,43 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/ignore_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/ignore.c. + */ + +/* External definitions for global variables. + */ +#ifndef IGNORE_C +extern char ignore_id[]; +extern anIgnore *ignore; +extern char ibuf[]; +#endif /* IGNORE_C */ + +/* External definitions for global functions. + */ +#ifndef IGNORE_C +#define EXTERN extern +#else /* IGNORE_C */ +#define EXTERN +#endif /* IGNORE_C */ +EXTERN void do_ignore __P((char *user, char *temp)); +EXTERN anIgnore *find_ignore __P((char *user, anIgnore *para, char *fromhost)); +EXTERN int kill_ignore __P((anIgnore *iptr)); +EXTERN int add_ignore __P((char *ch, int status, char *fromhost)); +#undef EXTERN diff --git a/irc/irc.c b/irc/irc.c new file mode 100644 index 0000000..7246f21 --- /dev/null +++ b/irc/irc.c @@ -0,0 +1,908 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/irc.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 rcsid[] = "@(#)$Id: irc.c,v 1.6 1998/12/13 00:02:35 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define IRC_C +#include "c_externs.h" +#undef IRC_C + +#define DEPTH 10 +#define KILLMAX 2 /* Number of kills to accept to really die */ + /* this is to prevent looping with /unkill */ + +#ifdef AUTOMATON +#ifdef DOCURSES +#undef DOCURSES +#endif +#ifdef DOTERMCAP +#undef DOTERMCAP +#endif +#endif /* AUTOMATON */ + +struct Command commands[] = { + { (void (*)()) 0, "SIGNOFF", SERVER_CMD, "\0\0", MSG_QUIT }, + { do_bye, "QUIT", LOCAL_FUNC, "\0\0", MSG_QUIT }, + { do_bye, "EXIT", LOCAL_FUNC, "\0\0", MSG_QUIT }, + { do_bye, "BYE", LOCAL_FUNC, "\0\0", MSG_QUIT }, + { do_kill, "KILL", LOCAL_FUNC, "\0\0", MSG_KILL }, + { (void (*)()) 0, "SUMMON", SERVER_CMD, "\0\0", MSG_SUMMON }, + { (void (*)()) 0, "STATS", SERVER_CMD, "\0\0", MSG_STATS }, + { (void (*)()) 0, "USERS", SERVER_CMD, "\0\0", MSG_USERS }, + { (void (*)()) 0, "TIME", SERVER_CMD, "\0\0", MSG_TIME }, + { (void (*)()) 0, "DATE", SERVER_CMD, "\0\0", MSG_TIME }, + { (void (*)()) 0, "NAMES", SERVER_CMD, "\0\0", MSG_NAMES }, + { (void (*)()) 0, "NICK", SERVER_CMD, "\0\0", MSG_NICK }, + { (void (*)()) 0, "WHO", SERVER_CMD, "\0\0", MSG_WHO }, + { (void (*)()) 0, "WHOIS", SERVER_CMD, "\0\0", MSG_WHOIS }, + { (void (*)()) 0, "WHOWAS", SERVER_CMD, "\0\0", MSG_WHOWAS }, + { do_kill, "LEAVE", LOCAL_FUNC, "\0\0", MSG_PART }, + { do_kill, "PART", LOCAL_FUNC, "\0\0", MSG_PART }, + { (void (*)()) 0, "WOPS", SERVER_CMD, "\0\0", MSG_WALLOPS }, + { do_channel, "JOIN", LOCAL_FUNC, "\0\0", MSG_JOIN }, + { do_channel, "CHANNEL", LOCAL_FUNC, "\0\0", MSG_JOIN }, +#ifdef VMSP + { do_exec, "EXEC", LOCAL_FUNC, "\0\0", "EXEC" }, + { do_oper, "OPER", LOCAL_FUNC, "\0\0", "OPER" }, +#endif +#ifdef GETPASS + { do_oper, "OPER", LOCAL_FUNC, "\0\0", "OPER" }, +#else + { (void (*)()) 0, "OPER", SERVER_CMD, "\0\0", MSG_OPER }, +#endif + { do_away, "AWAY", LOCAL_FUNC, "\0\0", MSG_AWAY }, + { do_mypriv, "MSG", LOCAL_FUNC, "\0\0", MSG_PRIVATE }, + { do_kill, "TOPIC", LOCAL_FUNC, "\0\0", MSG_TOPIC }, + { do_cmdch, "CMDCH", LOCAL_FUNC, "\0\0", "CMDCH" }, + { (void (*)()) 0, "INVITE", SERVER_CMD, "\0\0", MSG_INVITE }, + { (void (*)()) 0, "INFO", SERVER_CMD, "\0\0", MSG_INFO }, + { (void (*)()) 0, "LIST", SERVER_CMD, "\0\0", MSG_LIST }, + { (void (*)()) 0, "KILL", SERVER_CMD, "\0\0", MSG_KILL }, + { do_quote, "QUOTE", LOCAL_FUNC, "\0\0", "QUOTE" }, + { (void (*)()) 0, "LINKS", SERVER_CMD, "\0\0", MSG_LINKS }, + { (void (*)()) 0, "ADMIN", SERVER_CMD, "\0\0", MSG_ADMIN }, + { do_ignore, "IGNORE", LOCAL_FUNC, "\0\0", "IGNORE" }, + { (void (*)()) 0, "TRACE", SERVER_CMD, "\0\0", MSG_TRACE }, + { do_help, "HELP", LOCAL_FUNC, "\0\0", "HELP" }, + { do_log, "LOG", LOCAL_FUNC, "\0\0", "LOG" }, + { (void (*)()) 0, "VERSION", SERVER_CMD, "\0\0", MSG_VERSION }, + { do_clear, "CLEAR", LOCAL_FUNC, "\0\0", "CLEAR" }, + { (void (*)()) 0, "REHASH", SERVER_CMD, "\0\0", MSG_REHASH }, + { do_query, "QUERY", LOCAL_FUNC, "\0\0", "QUERY" }, + { (void (*)()) 0, "LUSERS", SERVER_CMD, "\0\0", MSG_LUSERS }, + { (void (*)()) 0, "MOTD", SERVER_CMD, "\0\0", MSG_MOTD }, + { do_unkill, "UNKILL", LOCAL_FUNC, "\0\0", "UNKILL" }, + { do_server, "SERVER", LOCAL_FUNC, "\0\0", "SERVER" }, + { (void (*)()) 0, "MODE", SERVER_CMD, "\0\0", MSG_MODE }, +#ifdef MSG_MAIL + { (void (*)()) 0, "MAIL", SERVER_CMD, "\0\0", MSG_MAIL }, +#endif + { do_kick, "KICK", LOCAL_FUNC, "\0\0", MSG_KICK }, + { (void (*)()) 0, "USERHOST",SERVER_CMD, "\0\0", MSG_USERHOST }, + { (void (*)()) 0, "ISON", SERVER_CMD, "\0\0", MSG_ISON }, + { (void (*)()) 0, "CONNECT", SERVER_CMD, "\0\0", MSG_CONNECT }, + { do_kill, "SQUIT", LOCAL_FUNC, "\0\0", MSG_SQUIT }, + { (void (*)()) 0, "SERVLIST",SERVER_CMD, "\0\0", MSG_SERVLIST }, + { do_kill, "SQUERY", LOCAL_FUNC, "\0\0", MSG_SQUERY }, + { do_kill, "NOTICE", LOCAL_FUNC, "\0\0", MSG_NOTICE }, + { (void (*)()) 0, (char *) 0, 0, "\0\0", (char *) 0 } +}; + +aChannel *channel = NULL; +aClient me, *client = &me; +anUser meUser; /* User block for 'me' --msa */ +FILE *logfile = NULL; +char buf[BUFSIZE]; +char *querychannel; +int portnum, termtype = CURSES_TERM; +int debuglevel = DEBUG_ERROR; +int unkill_flag = 0, cchannel = 0; +int QuitFlag = 0; + +static int KillCount = 0; +static int apu = 0; /* Line number we're currently on screen */ +static int sock; /* Server socket fd */ +static char currserver[HOSTLEN + 1]; + +#if defined(HPUX) || defined(SVR3) || defined(SVR4) +char logbuf[BUFSIZ]; +#endif + +#ifdef MAIL50 +int ucontext = 0, perslength; +char persname[81]; + +struct itmlst + null_list[] = {{0,0,0,0}}, + gplist[] = {{80, MAIL$_USER_PERSONAL_NAME, + &persname, &perslength}}; +#endif + +int main(argc, argv) +int argc; +char *argv[]; +{ + static char usage[] = + "Usage: %s [-c channel] [-k passwd] [-p port] [-i] [-w] [-s] [nickname [server]]\n"; + char channel[BUFSIZE+1]; + int length, mode = 0; + struct passwd *userdata; + char *cp, *argv0=argv[0], *nickptr, *servptr, *getenv(), ch; + + if ((cp = rindex(argv0, '/')) != NULL) + argv0 = ++cp; + portnum = PORTNUM; + *buf = *currserver = '\0'; + channel[0] = '\0'; + me.user = &meUser; + me.from = &me; + me.info = (char *) malloc(REALLEN); + setuid(getuid()); + version = make_version(); + + while (argc > 1 && argv[1][0] == '-') { + switch(ch = argv[1][1]) + { + case 'h': + printf(usage, argv0); + exit(1); + break; + case 'p': + length = 0; + if (argv[1][2] != '\0') + length = atoi(&argv[1][2]); + else if (argc > 2) { + length = atoi(argv[2]); + argv++; + argc--; + } + if (length <= 0) { + printf(usage, argv0); + exit(1); + } + cchannel = length; + break; + case 'c': + if (argv[1][2] != '\0') + strncpy(channel, &argv[1][2], BUFSIZE); + else if (argc > 2) { + strncpy(channel, argv[2], BUFSIZE); + argv++; + argc--; + } + if (!channel[0]) { + printf(usage, argv0); + exit(1); + } + break; + case 'i': + mode |= FLAGS_INVISIBLE; + break; + case 'w': + mode |= FLAGS_WALLOP; + break; + case 'k': + if (argv[1][2] != '\0') + strncpy(me.passwd, &argv[1][2], PASSWDLEN); + else if (argc > 2) { + strncpy(me.passwd, argv[2], PASSWDLEN); + argv++; + argc--; + } + if (!me.passwd[0]) { + printf(usage, argv0); + exit(1); + } + break; +#ifdef DOTERMCAP + case 's': + termtype = TERMCAP_TERM; + break; +#endif + case 'v': + (void)printf("irc %s\n", version); + exit(0); + } + argv++; + argc--; + } + + me.name[0] = me.buffer[0] = '\0'; + me.next = NULL; + me.status = STAT_ME; + if ((servptr = getenv("IRCSERVER"))) + strncpyzt(currserver, servptr, HOSTLEN); + if (argc > 2) + strncpyzt(currserver, argv[2], HOSTLEN); + + do { + QuitFlag = 0; + if (unkill_flag < 0) + unkill_flag += 2; +#ifdef UPHOST + if (!*currserver) + strncpyzt(currserver, UPHOST, HOSTLEN); +#else + if (!*currserver) + strncpyzt(currserver, me.sockhost, HOSTLEN); +#endif + if (cchannel > 0) + portnum = cchannel; + + sock = client_init(currserver, portnum, &me); + if (sock < 0) { + printf("sock < 0\n"); + exit(1); + } + userdata = getpwuid(getuid()); + if (strlen(userdata->pw_name) >= (size_t) USERLEN) { + userdata->pw_name[USERLEN-1] = '\0'; + } + if (strlen(userdata->pw_gecos) >= (size_t) REALLEN) { + userdata->pw_gecos[REALLEN-1] = '\0'; + } + /* FIX: jtrim@orion.cair.du.edu -- 3/14/88 + & jto@tolsun.oulu.fi */ + if (!*me.name) { + if (argc >= 2) { + strncpy(me.name, argv[1], NICKLEN); + } else if ((nickptr = getenv("IRCNICK"))) { + strncpy(me.name, nickptr, NICKLEN); + } else +#ifdef AUTOMATON + strncpy(me.name, a_myname(), NICKLEN); +#else + strncpy(me.name, userdata->pw_name ,NICKLEN); +#endif + } + me.name[NICKLEN] = '\0'; + /* END FIX */ + + if (argv0[0] == ':') { + strcpy(me.sockhost, "OuluBox"); + strncpy(me.info, &argv0[1], REALLEN); + strncpy(meUser.username, argv[1], USERLEN); + } else { + sprintf(me.sockhost, "%d", mode); + if ((cp = getenv("IRCNAME"))) + strncpy(me.info, cp, REALLEN); + else if ((cp = getenv("NAME"))) + strncpy(me.info, cp, REALLEN); + else { +#ifdef AUTOMATON + strncpy(me.info, a_myreal(), REALLEN); +#else + strncpy(me.info,real_name(userdata),REALLEN); +#endif + if (me.info[0] == '\0') + strcpy(me.info, "*real name unknown*"); + } +#ifdef AUTOMATON + strncpy(meUser.username, a_myuser(), USERLEN); +#else + strncpy(meUser.username,userdata->pw_name,USERLEN); +#endif + } + meUser.server = mystrdup(me.sockhost); + meUser.username[USERLEN] = '\0'; + me.info[REALLEN] = '\0'; + me.fd = sock; +#ifdef AUTOMATON + a_init(); +#endif +#ifdef DOCURSES + if (termtype == CURSES_TERM) { + initscr(); + signal(SIGINT, quit_intr); + signal(SIGTSTP, suspend_irc); + noecho(); + crmode(); + clear(); + refresh(); + } +#endif +#ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) { + printf("Io on !\n"); + io_on(1); + clearscreen(); + } +#endif + if (me.passwd[0]) + sendto_one(&me, "PASS %s", me.passwd); + sendto_one(&me, "NICK %s", me.name); + sendto_one(&me, "USER %s %s %s :%s", meUser.username, + me.sockhost, meUser.server, me.info); + querychannel = (char *)malloc(strlen(me.name) + 1); + strcpy(querychannel, me.name); /* Kludge? */ + if (channel[0]) + do_channel(channel, "JOIN"); + myloop(sock); + if (logfile) + do_log(NULL, NULL); + printf("Press any key."); + refresh(); + getchar(); + printf("\n"); +#ifdef DOCURSES + if (termtype == CURSES_TERM) { + echo(); + nocrmode(); + endwin(); + } +#endif +#ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) + io_off(); +#endif + apu = 0; + } while (unkill_flag && KillCount++ < KILLMAX); + exit(0); +} + +void intr() +{ + if (logfile) + do_log(NULL, NULL); + +#ifdef DOCURSES + if (termtype == CURSES_TERM) { + echo(); + nocrmode(); + endwin(); + } +#endif +#ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) + io_off(); +#endif + exit(0); +} + +void myloop(sock) +int sock; +{ + write_statusline(); +#ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) + put_statusline(); +#endif + client_loop(sock); +} + +#define QUERYLEN 50 + +static char cmdch = '/'; +static char queryuser[QUERYLEN+2] = ""; + +void do_cmdch(ptr, temp) +char *ptr, *temp; +{ + if (BadPtr(ptr)) { + putline("Error: Command character not changed"); + return; + } + cmdch = *ptr; +} + +void do_quote(ptr, temp) +char *ptr, *temp; +{ + if (BadPtr(ptr)) { + putline("*** Error: Empty command"); + return; + } + sendto_one(&me,"%s", ptr); +} + +void do_query(ptr, temp) +char *ptr, *temp; +{ + if (BadPtr(ptr)) { + sprintf(buf, "*** Ending a private chat with %s", queryuser); + putline(buf); + queryuser[0] = '\0'; + } else { + strncpyzt(queryuser, ptr, QUERYLEN); + sprintf(buf, "*** Beginning a private chat with %s", + queryuser); + putline(buf); + } +} + +void do_mypriv(buf1, buf2) +char *buf1, *buf2; +{ + char *tmp = index(buf1, ' '); + + if (tmp == NULL) { + putline("*** Error: Empty message not sent"); + return; + } + if (buf1[0] == ',' && buf1[1] == ' ') { + sendto_one(&me, "PRIVMSG %s :%s", last_to_me(NULL), &buf1[2]); + last_from_me(last_to_me(NULL)); + *(tmp++) = '\0'; + sprintf(buf,"-> !!*%s* %s", last_to_me(NULL), tmp); + putline(buf); + } else if (buf1[0] == '.' && buf1[1] == ' ') { + sendto_one(&me, "PRIVMSG %s :%s", last_from_me(NULL), &buf1[2]); + *(tmp++) = '\0'; + sprintf(buf,"-> ##*%s* %s", last_from_me(NULL), tmp); + putline(buf); + } else { + *(tmp++) = '\0'; + sendto_one(&me, "PRIVMSG %s :%s", buf1, tmp); + last_from_me(buf1); + if (*buf1 == '#' || *buf1 == '&' || *buf1 == '+' || atoi(buf1)) + sprintf(buf, "%s> %s", buf1, tmp); + else + sprintf(buf,"->%s> %s", buf1, tmp); + putline(buf); + } +} + +void do_myqpriv(buf1, buf2) +char *buf1, *buf2; +{ + if (BadPtr(buf1)) { + putline("*** Error: Empty message not sent"); + return; + } + sendto_one(&me, "PRIVMSG %s :%s", queryuser, buf1); + + sprintf(buf,"-> *%s* %s", queryuser, buf1); + putline(buf); +} + +void do_mytext(buf1, temp) +char *buf1, *temp; +{ + sendto_one(&me, "PRIVMSG %s :%s", querychannel, buf1); + sprintf(buf,"%s> %s", querychannel, buf1); + putline(buf); +} + +void do_unkill(buf, temp) +char *buf, *temp; +{ + if (unkill_flag) + unkill_flag = 0; + else + unkill_flag = 1; + + sprintf(buf, "*** Unkill feature turned %s", + (unkill_flag) ? "on" : "off"); + putline(buf); +} + +void do_bye(buf, tmp) +char *buf, *tmp; +{ + unkill_flag = 0; + sendto_one(&me, "%s :%s", tmp, buf); +} + +/* KILL, PART, SQUIT, TOPIC "CMD PARA1 [:PARA2]" */ +void do_kill(buf1, tmp) +char *buf1, *tmp; +{ + char *b2; + + b2 = index(buf1, SPACE); /* find end of servername */ + if (b2) /* comment */ + { + *b2 = 0; + sendto_one(&me, "%s %s :%s", tmp, buf1, b2 + 1); + } + else + sendto_one(&me, "%s %s", tmp, buf1); + if (*tmp == 'P') { /* PART */ + free(querychannel); + querychannel = (char *)malloc(strlen(me.name) + 1); + strcpy(querychannel, me.name); /* Kludge? */ + } +} + +/* "CMD PARA1 PARA2 [:PARA3]" */ +void do_kick(buf1, tmp) +char *buf1, *tmp; +{ + char *b2, *b3 = NULL; + + b2 = index(buf1, SPACE); /* find end of channel name */ + if (b2) + b3 = index(b2 + 1, SPACE); /* find end of victim name */ + if (b3) + { + *b3 = 0; + sendto_one(&me, "%s %s :%s", tmp, buf1, b3 + 1); + } + else + sendto_one(&me, "%s %s :No comment", tmp, buf1); +} + +/* "CMD :PARA1" */ +void do_away(buf1, tmp) +char *buf1, *tmp; +{ + sendto_one(&me, "%s :%s", tmp, buf1); +} + +void do_server(buf, tmp) +char *buf, *tmp; +{ + strncpyzt(currserver, buf, HOSTLEN); + unkill_flag -= 2; + sendto_one(&me,"QUIT"); + close(sock); + QuitFlag = 1; +} + +void sendit(line) +char *line; +{ + char *ptr = NULL; + struct Command *cmd = commands; + + KillCount = 0; + if (line[0] != cmdch) { + if (*queryuser) + do_myqpriv(line, NULL); + else + do_mytext(line, NULL); + return /* 0 */ ; + } + if (line[1] == ' ') + do_mytext(&line[2], NULL); + else if (line[1]) { + for ( ; cmd->name; cmd++) + if ((ptr = mycncmp(&line[1], cmd->name))) + break; + if (!cmd->name) + putline("*** Error: Unknown command"); + else { + switch (cmd->type) + { + case SERVER_CMD: + sendto_one(&me, "%s %s", cmd->extra, ptr); + break; + case LOCAL_FUNC: + (*cmd->func)(ptr, cmd->extra); + return; + break; + default: + putline("*** Error: Data error in irc.h"); + break; + } + } + } +} + +char *mycncmp(str1, str2) +char *str1, *str2; +{ + int flag = 0; + char *s1; + + for (s1 = str1; *s1 != ' ' && *s1 && *str2; s1++, str2++) { + /* if (!isascii(*s1)) */ + if (*s1 & 0x80) + return 0; + *s1 = toupper(*s1); + if (*s1 != *str2) + flag = 1; + } + if (*s1 && *s1 != ' ' && *str2 == '\0') + return 0; + if (flag) + return 0; + if (*s1) + return s1 + 1; + else + return s1; +} + +void do_clear(buf, temp) +char *buf, *temp; +{ +#ifdef DOCURSES + char header[HEADERLEN]; + + if (termtype == CURSES_TERM) { + apu = 0; + sprintf(header, IRCHEADER ,version, me.name, currserver); + clear(); + standout(); + mvaddstr(LINES - 2, 0, header); + standend(); + refresh(); + } +#endif +#ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) + clearscreen(); +#endif +} + +void putline(line) +char *line; + +{ + char *ptr, *ptr2; + +#ifdef DOCURSES + char ch='\0'; + /* int pagelen = LINES - 3; not used -Armin */ + int rmargin = COLS - 1; +#endif + + /* + ** This is a *safe* client--filter out all possibly dangerous + ** codes from the messages (this sets them as "_"). + */ + if (line) + for (ptr = line; *ptr; ptr++) + if ((*ptr < 32 && *ptr != 7 && *ptr != 9) || + (*ptr > 126)) + *ptr = '_'; + + ptr = line; + +#ifdef DOCURSES + if (termtype == CURSES_TERM) { + while (ptr) { + +/* first, see if we have to chop the string into pieces */ + + if (strlen(ptr) > (size_t) rmargin) { + ch = ptr[rmargin]; + ptr[rmargin] = '\0'; + ptr2 = &ptr[rmargin - 1]; + } + else + ptr2 = NULL; + +/* move cursor to correct position and place line */ + + move(apu,0); + addstr(ptr); + if (logfile) + fprintf(logfile, "%s\n", ptr); + +/* now see if we are at the end of the page, and take action */ + +#ifndef SCROLLINGCLIENT + /* clear one line. */ + addstr("\n\n"); + if (++apu > LINES - 4) { + apu = 0; + move(0,0); + clrtoeol(); + } + +#else /* doesn't work, dumps core :-( */ + + if(++apu > LINES - 4) { + char header[HEADERLEN]; + /* erase status line */ + move(LINES - 2, 0 ); + clrtobot(); + refresh(); + /* scroll screen */ + scrollok(stdscr,TRUE); + move(LINES - 1, 0 ); + addstr("\n\n\n\n"); + refresh(); + apu -= 4; + /* redraw status line */ + sprintf(header, IRCHEADER, version, + me.name, currserver); + standout(); + mvaddstr(LINES - 2, 0, header); + standend(); + tulosta_viimeinen_rivi(); + } else + addstr( "\n\n" ); +#endif + +/* finally, if this is a multiple-line line, munge things up so that + we print the next line. overwrites the end of the previous line. */ + + ptr = ptr2; + if (ptr2) { + *ptr2++ = '+'; + *ptr2 = ch; + } + } + refresh(); + } +#endif +#ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) + tcap_putline(line); +#endif +#ifdef AUTOMATON + puts(line); +#endif +} + +int unixuser() +{ + return(!StrEq(me.sockhost,"OuluBox")); +} + +void do_log(ptr, temp) +char *ptr, *temp; +{ + time_t tloc; + char buf[150]; + char *ptr2; + + if (!unixuser()) + return; + if (!logfile) { /* logging currently off */ + if (BadPtr(ptr)) + putline("*** You must specify a filename to log to."); + else { + if (!(logfile = fopen(ptr, "a"))) { + sprintf(buf, + "*** Error: Can't open log file %s.\n", + ptr); + putline(buf); + } else { +#if defined(HPUX) || defined(SVR3) || defined(SVR4) + setvbuf(logfile,logbuf,_IOLBF,sizeof(logbuf)); +#else +# if !defined(_SEQUENT_) && !defined(SVR4) + setlinebuf(logfile); +# endif +#endif + time(&tloc); + sprintf(buf, + "*** IRC session log started at %s", + ctime(&tloc)); + ptr2 = rindex(buf, '\n'); + *ptr2 = '.'; + putline(buf); + } + } + } else { /* logging currently on */ + if (BadPtr(ptr)) { + + time(&tloc); + sprintf(buf, "*** IRC session log ended at %s", + ctime(&tloc)); + ptr2 = rindex(buf, '\n'); + *ptr2 = '.'; + putline(buf); + fclose(logfile); + logfile = NULL; + } else + putline("*** Your session is already being logged."); + } +} + +/* remember the commas */ +#define LASTKEEPLEN (MAXRECIPIENTS * (NICKLEN+1)) + +char *last_to_me(sender) +char *sender; +{ + static char name[LASTKEEPLEN+1] = ","; + + if (sender) + strncpyzt(name, sender, sizeof(name)); + + return (name); +} + +char *last_from_me(recipient) +char *recipient; +{ + static char name[LASTKEEPLEN+1] = "."; + + if (recipient) + strncpyzt(name, recipient, sizeof(name)); + + return (name); +} + +/* + * Left out until it works with VMS as well.. + */ + +#ifdef GETPASS +do_oper(ptr, xtra) +char *ptr, *xtra; +{ + extern char *getmypass(); + + if (BadPtr(ptr)) + ptr = getmypass("Enter nick & password: "); + + sendto_one(&me, "%s %s", xtra, ptr); +} +#endif + +/* Fake routine (it's only in server...) */ + +void do_channel(ptr, xtra) +char *ptr, *xtra; +{ + char *p1; + + if (BadPtr(ptr)) { + putline("*** Which channel do you want to join?"); + return; + } + + free((char *)querychannel); + + if ((querychannel = (char *)malloc(strlen(ptr) + 1))) + { + /* Copy only channel name from *ptr -Vesa */ + strcpy(buf, ptr); + if ((p1 = index(buf, ' '))) + *p1 = '\0'; + if ((p1 = rindex(buf, ','))) /* The last channel */ + strcpy(querychannel, p1 + 1); + else /* The only channel */ + strcpy(querychannel, buf); + } + else + printf("Blah! Out of memory?\n"); + + sendto_one(&me, "%s %s", xtra, ptr); +} + +void write_statusline() +{ +#ifdef DOCURSES + char header[HEADERLEN]; + + if (termtype == CURSES_TERM) { + sprintf(header, IRCHEADER, version, me.name, currserver); + standout(); + mvaddstr(LINES - 2, 0, header); + standend(); + } +#endif +} + +RETSIGTYPE quit_intr(s) +int s; +{ + signal(SIGINT, SIG_IGN); +#ifdef DOCURSES + if (termtype == CURSES_TERM) { + clear(); + refresh(); + echo(); + nocrmode(); + endwin(); + } +#endif + exit(0); +} diff --git a/irc/irc_def.h b/irc/irc_def.h new file mode 100644 index 0000000..26f7a6c --- /dev/null +++ b/irc/irc_def.h @@ -0,0 +1,29 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/irc_def.h + * 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. + */ + +struct Command { + void (*func)(); + char *name; + int type; + char keybinding[3]; + char *extra; /* Normally contains the command to send to irc daemon */ +}; + +#define SERVER_CMD 0 +#define LOCAL_FUNC 1 diff --git a/irc/irc_ext.h b/irc/irc_ext.h new file mode 100644 index 0000000..4ef47a8 --- /dev/null +++ b/irc/irc_ext.h @@ -0,0 +1,84 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/irc_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/irc.c. + */ + +/* External definitions for global variables. + */ +#ifndef IRC_C +extern struct Command commands[]; +extern char irc_id[]; +extern aChannel *channel; +extern aClient me, *client; +extern anUser meUser; +extern FILE *logfile; +extern char buf[]; +extern char *querychannel; +extern int portnum, termtype; +extern int debuglevel; +extern int unkill_flag, cchannel; +extern int QuitFlag; +#if defined(HPUX) || defined(SVR3) || defined(SVR4) +extern char logbuf[]; +#endif +#ifdef MAIL50 +extern int ucontext, perslength; +extern char persname[]; +extern struct itmlst null_list[]; +#endif +#endif /* IRC_C */ + +/* External definitions for global functions. + */ +#ifndef IRC_C +#define EXTERN extern +#else /* IRC_C */ +#define EXTERN +#endif /* IRC_C */ +EXTERN void intr(); +EXTERN void myloop __P((int sock)); +EXTERN void do_cmdch __P((char *ptr, char *temp)); +EXTERN void do_quote __P((char *ptr, char *temp)); +EXTERN void do_query __P((char *ptr, char *temp)); +EXTERN void do_mypriv __P((char *buf1, char *buf2)); +EXTERN void do_myqpriv __P((char *buf1, char *buf2)); +EXTERN void do_mytext __P((char *buf1, char *temp)); +EXTERN void do_unkill __P((char *buf, char *temp)); +EXTERN void do_bye __P((char *buf, char *tmp)); +EXTERN void do_kill __P((char *buf1, char *tmp)); +EXTERN void do_kick __P((char *buf1, char *tmp)); +EXTERN void do_away __P((char *buf1, char *tmp)); +EXTERN void do_server __P((char *buf, char *tmp)); +EXTERN void sendit __P((char *line)); +EXTERN char *mycncmp __P((char *str1, char *str2)); +EXTERN void do_clear __P((char *buf, char *temp)); +EXTERN void putline __P((char *line)); +EXTERN int unixuser(); +EXTERN void do_log __P((char *ptr, char *temp)); +EXTERN char *last_to_me __P((char *sender)); +EXTERN char *last_from_me __P((char *recipient)); +#ifdef GETPASS +EXTERN do_oper __P((char *ptr, char *xtra)); +#endif +EXTERN void do_channel __P((char *ptr, char *xtra)); +EXTERN void write_statusline(); +EXTERN RETSIGTYPE quit_intr __P((int s)); +#undef EXTERN diff --git a/irc/screen.c b/irc/screen.c new file mode 100644 index 0000000..01afa11 --- /dev/null +++ b/irc/screen.c @@ -0,0 +1,287 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/screen.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 rcsid[] = "@(#)$Id: screen.c,v 1.2 1997/09/03 17:45:42 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define SCREEN_C +#include "c_externs.h" +#undef SCREEN_C + +#define SBUFSIZ 240 + +#define FROM_START 0 +#define FROM_END 1 +#define RELATIVE 2 + +#define HIST_SIZ 1000 + +static char last_line[SBUFSIZ+1]; +static char yank_buffer[SBUFSIZ+1]; +static char history[HIST_SIZ][SBUFSIZ+1]; +static int position = 0; +static int pos_in_history = 0; + +int insert = 1; /* default to insert mode */ + /* I want insert mode, thazwhat emacs does ! //jkp */ + +int get_char(pos) +int pos; +{ + if (pos>=SBUFSIZ || pos<0) + return 0; + return (int)last_line[pos]; +} + +void set_char(pos, ch) +int pos, ch; +{ + if (pos<0 || pos>=SBUFSIZ) + return; + if (ch<0) + ch=0; + last_line[pos]=(char)ch; +} + +int get_yank_char(pos) +int pos; +{ + if (pos>=SBUFSIZ || pos<0) + return 0; + return (int)yank_buffer[pos]; +} + +void set_yank_char(pos, ch) +int pos, ch; +{ + if (pos<0 || pos>=SBUFSIZ) + return; + if (ch<0) + ch=0; + yank_buffer[pos]=(char)ch; +} + +void set_position(disp, from) +int disp, from; +{ + int i1; + + switch (from) { + case FROM_START: + position=disp; + break; + case RELATIVE: + position+=disp; + break; + case FROM_END: + for (i1=0; get_char(i1); i1++); + position=i1-1; + break; + default: + position=0; + break; + } +} + +int get_position() +{ + return position; +} + +void toggle_ins() +{ + insert = !insert; +#ifdef DOCURSES + if (termtype == CURSES_TERM) { + standout(); + if (insert) + mvaddstr(LINES-2, 75, "INS"); + else + mvaddstr(LINES-2, 75, "OWR"); + standend(); + } +#endif +#ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) + put_insflag(insert); +#endif +} + +int in_insert_mode() +{ + return insert; +} + +void send_this_line() +{ + record_line(); + sendit(last_line); + clear_last_line(); + bol(); + tulosta_viimeinen_rivi(); +#ifdef DOCURSES + if (termtype == CURSES_TERM) + refresh(); +#endif +} + +void record_line() +{ + static int place=0; + int i1; + + for(i1=0; i1<SBUFSIZ; i1++) + history[place][i1]=get_char(i1); + place++; + if (place==HIST_SIZ) + place=0; + pos_in_history=place; +} + +void clear_last_line() +{ + int i1; + + for(i1=0; i1<SBUFSIZ; i1++) + set_char(i1,(int)'\0'); +} + +void kill_eol() +{ + int i1, i2, i3; + + i1=get_position(); + set_position(0, FROM_END); + i2=get_position(); + for(i3=0; i3<SBUFSIZ; i3++) + set_yank_char(i3,(int)'\0'); + for(i3=0; i3<=(i2-i1); i3++) { + set_yank_char(i3,get_char(i1+i3)); + set_char(i1+i3, 0); + } + set_position(i1, FROM_START); +} + +void next_in_history() +{ + int i1; + + pos_in_history++; + if (pos_in_history==HIST_SIZ) + pos_in_history=0; + clear_last_line(); + + for (i1 = 0; history[pos_in_history][i1]; i1++) + set_char(i1, history[pos_in_history][i1]); + + set_position(0, FROM_START); +} + +void previous_in_history() +{ + int i1; + + pos_in_history--; + if (pos_in_history<0) + pos_in_history=HIST_SIZ-1; + clear_last_line(); + for (i1=0; history[pos_in_history][i1]; i1++) + set_char(i1, history[pos_in_history][i1]); + + set_position(0, FROM_START); +} + +void kill_whole_line() +{ + clear_last_line(); + set_position(0, FROM_START); +} + +void yank() +{ + int i1, i2, i3; + + i1=get_position(); + i2=0; + while (get_yank_char(i2)) + i2++; + + for(i3=SBUFSIZ-1; i3>=i1+i2; i3--) + set_char(i3, get_char(i3-i2)); + for(i3=0; i3<i2; i3++) + set_char(i1+i3, get_yank_char(i3)); +} + +int tulosta_viimeinen_rivi() +{ + static int paikka=0; + int i1, i2, i3; + + i1=get_position(); + /* taytyyko siirtaa puskuria */ + if (i1<(get_disp(paikka)+10) && paikka) { + paikka--; + i2=get_disp(paikka); + } else if (i1>(get_disp(paikka)+70)) { + paikka++; + i2=get_disp(paikka); + } else { + i2=get_disp(paikka); + } + +#ifdef DOCURSES + if (termtype == CURSES_TERM) { + move(LINES-1,0); + for(i3=0; i3<78; i3++) + if (get_char(i2+i3)) + mvaddch(LINES-1, i3, get_char(i2+i3)); + clrtoeol(); + move(LINES-1, i1-get_disp(paikka)); + refresh(); + } +#endif +#ifdef DOTERMCAP + if (termtype == TERMCAP_TERM) { + tcap_move(-1, 0); + for(i3=0; i3<78; i3++) + if (get_char(i2+i3)) +/* tcap_putch(LINES-1, i3, get_char(i2+i3)); */ + tcap_putch(-1, i3, get_char(i2+i3)); +/* clear_to_eol(); */ + clear_to_eol(-1, 78); + tcap_move(-1, i1-get_disp(paikka)); +/* refresh(); */ + } +#endif + return (i1-get_disp(paikka)); +} + +int get_disp(paikka) +int paikka; +{ + static int place[]={0,55,110,165,220}; + + if (paikka>4 || paikka<0) + return 0; + return place[paikka]; +} diff --git a/irc/screen_ext.h b/irc/screen_ext.h new file mode 100644 index 0000000..5dfd792 --- /dev/null +++ b/irc/screen_ext.h @@ -0,0 +1,56 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/screen_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/screen.c. + */ + +/* External definitions for global variables. + */ +#ifndef SCREEN_C +extern char screen_id[]; +extern int insert; +#endif /* SCREEN_C */ + +/* External definitions for global functions. + */ +#ifndef SCREEN_C +#define EXTERN extern +#else /* SCREEN_C */ +#define EXTERN +#endif /* SCREEN_C */ +EXTERN int get_char __P((int pos)); +EXTERN void set_char __P((int pos, int ch)); +EXTERN int get_yank_char __P((int pos)); +EXTERN void set_yank_char __P((int pos, int ch)); +EXTERN void set_position __P((int disp, int from)); +EXTERN int get_position(); +EXTERN void toggle_ins(); +EXTERN int in_insert_mode(); +EXTERN void send_this_line(); +EXTERN void record_line(); +EXTERN void clear_last_line(); +EXTERN void kill_eol(); +EXTERN void next_in_history(); +EXTERN void previous_in_history(); +EXTERN void kill_whole_line(); +EXTERN void yank(); +EXTERN int tulosta_viimeinen_rivi(); +EXTERN int get_disp __P((int paikka)); +#undef EXTERN diff --git a/irc/str.c b/irc/str.c new file mode 100644 index 0000000..aaff546 --- /dev/null +++ b/irc/str.c @@ -0,0 +1,84 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/str.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 rcsid[] = "@(#)$Id: str.c,v 1.2 1997/09/03 17:45:43 kalt Exp $"; +#endif + +#include "os.h" +#include "c_defines.h" +#define STR_C +#include "c_externs.h" +#undef STR_C + +char * center(buf,str,len) +char *buf, *str; +int len; +{ + char i,j,k; + if ((i = strlen(str)) > len) { + buf[len-1] = '\0'; + for(len--; len > 0; len--) buf[len-1] = str[len-1]; + return(buf); + } + j = (len-i)/2; + for (k=0; k<j; k++) buf[k] = ' '; + buf[k] = '\0'; + strcat(buf,str); + for (k=j+i; k<len; k++) buf[k] = ' '; + buf[len] = '\0'; + return (buf); +} + +/* William Wisner <wisner@b.cc.umich.edu>, 16 March 1989 */ +char * +real_name(user) + struct passwd *user; +{ + char *bp, *cp; + static char name[REALLEN+1]; + + bp = user->pw_gecos; + cp = name; + + name[REALLEN] = '\0'; + do { + switch(*bp) { + case '&': + *cp = '\0'; + strncat(name, user->pw_name, REALLEN-strlen(name)); + name[REALLEN] = '\0'; + *cp = toupper(*cp); + cp = index(name, '\0'); + bp++; + break; + case ',': + *bp = *cp = '\0'; + break; + case '\0': + *cp = *bp; + break; + default: + *cp++ = *bp++; + } + } while (*bp != '\0' && strlen(name) < (size_t) REALLEN); + return(name); +} + diff --git a/irc/str_ext.h b/irc/str_ext.h new file mode 100644 index 0000000..6198141 --- /dev/null +++ b/irc/str_ext.h @@ -0,0 +1,39 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/str_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/str.c. + */ + +/* External definitions for global variables. + */ +#ifndef STR_C +extern char str_id[]; +#endif /* STR_C */ + +/* External definitions for global functions. + */ +#ifndef STR_C +#define EXTERN extern +#else /* STR_C */ +#define EXTERN +#endif /* STR_C */ +EXTERN char *center __P((char *buf, char *str, int len)); +EXTERN char *real_name __P((struct passwd *user)); +#undef EXTERN diff --git a/irc/swear.c b/irc/swear.c new file mode 100644 index 0000000..9c8b2a6 --- /dev/null +++ b/irc/swear.c @@ -0,0 +1,216 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/swear.c + * 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. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: swear.c,v 1.4 1998/12/13 00:02:35 kalt Exp $"; +#endif + +/* Curses replacement routines. Uses termcap */ + +#include "os.h" +#include "c_defines.h" +#define SWEAR_C +#include "c_externs.h" +#undef SWEAR_C + +#define LLEN 60 + +#ifdef DOTERMCAP + +static struct sgttyb oldtty, newtty; +static char termcapentry[1024]; +static char codes[1024], *cls; + +static char *irc_termname; + +static int currow = 0; +int irc_lines, irc_columns, scroll_ok = 0, scroll_status = 0; + +void tcap_putch(row, col, ch) +int row, col; +char ch; +{ + tcap_move(row, col); + putchar(ch); + fflush(stdout); +} + +void tcap_move(row, col) +int row, col; +{ + cls = codes; + tgetstr("cm",&cls); + if (row < 0) + row = irc_lines - row; + cls = tgoto(codes, col, row); + printf("%s",cls); + fflush(stdout); +} + +void clear_to_eol(row, col) +int row, col; +{ + tcap_move(row, col); + cls = codes; + tgetstr("ce", &cls); + printf("%s",codes); + fflush(stdout); +} + +void clearscreen() +{ + cls = codes; + tgetstr("cl",&cls); + printf("%s",codes); + fflush(stdout); + currow = 0; +} + +int +io_on(flag) +int flag; +{ +/* if (ioctl(0, TIOCGETP, &oldtty) == -1) { + perror("ioctl"); + return(-1); + } + newtty = oldtty; + newtty.sg_flags &= ~ECHO; + newtty.sg_flags |= CBREAK; + ioctl(0, TIOCSETP, &newtty); */ + system("stty -echo cbreak"); + if (tgetent(termcapentry,irc_termname=getenv("TERM")) != 1) { + printf("Cannot find termcap entry !\n"); + fflush(stdout); + } + printf("TERMCAP=%s\n",termcapentry); + irc_lines = tgetnum("li"); + irc_columns = tgetnum("co"); + return(0); +} + +int +io_off() +{ + if (scroll_ok) + scroll_ok_off(); + if (ioctl(0, TIOCSETP, &oldtty) < 0) + return(-1); + return(0); +} + +void scroll_ok_off() +{ + cls = codes; + tgetstr("cs",&cls); + cls = tgoto(codes, irc_lines-1, 0); + printf("%s",cls); + scroll_ok = 0; +} + +void scroll_ok_on() +{ + cls = codes; + tgetstr("cm",&cls); + cls = tgoto(codes, 0, 0); + printf("%s",cls); + cls = codes; + tgetstr("cs",&cls); + cls = tgoto(codes, irc_lines-3, 0); + printf("%s",cls); + fflush(stdout); + scroll_ok = scroll_status = 1; +} + +void put_insflag(flag) +int flag; +{ + flag = insert; + tcap_move(-2, irc_columns - 5); + cls = codes; + tgetstr("mr",&cls); + printf("%s",codes); + printf((flag) ? "INS" : "OWR"); + cls = codes; + tgetstr("me",&cls); + printf("%s",codes); + fflush(stdout); +} + +void put_statusline() +{ + tcap_move (-2, 0); + cls = codes; + tgetstr("mr",&cls); + printf("%s",codes); + printf(IRCHEADER, version); + cls = codes; + tgetstr("me",&cls); + printf("%s",codes); + fflush(stdout); +} + +void tcap_putline(line) +char *line; +{ + char *ptr = line, *ptr2, *newl; + char ch='\0'; + while (ptr) { + if (strlen(ptr) > irc_columns-1) { + ch = ptr[irc_columns-1]; + ptr[irc_columns-1] = '\0'; + ptr2 = &ptr[irc_columns-2]; + } + else + ptr2 = NULL; + if (scroll_ok) { + tcap_move(irc_lines-3, 0); + } else { + tcap_move(currow++,0); + if (currow > irc_lines - 4) currow = 0; + } + while (newl = index(ptr,'\n')) + *newl = '\0'; + printf("%s",ptr); + if (scroll_ok) + printf("\n",ptr); + else { + if (currow == 0) { + clear_to_eol(1,0); + clear_to_eol(2,0); + } + else if (currow == irc_lines - 4) { + clear_to_eol(irc_lines-4,0); + clear_to_eol(0,0); + } + else { + clear_to_eol(currow+1,0); + clear_to_eol(currow+2,0); + } + } + ptr = ptr2; + if (ptr2) { + *ptr2++ = '+'; + *ptr2 = ch; + } + } + fflush(stdout); +} + +#endif /* DO_TERMCAP */ diff --git a/irc/swear_ext.h b/irc/swear_ext.h new file mode 100644 index 0000000..ce1c85e --- /dev/null +++ b/irc/swear_ext.h @@ -0,0 +1,53 @@ +/************************************************************************ + * IRC - Internet Relay Chat, irc/swear_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in irc/swear.c. + */ + +/* External definitions for global variables. + */ +#ifndef SWEAR_C +#ifdef DOTERMCAP +extern char swear_id[]; +extern int irc_lines, irc_columns, scroll_ok, scroll_status; +#endif +#endif /* SWEAR_C */ + +/* External definitions for global functions. + */ +#ifndef SWEAR_C +#define EXTERN extern +#else /* SWEAR_C */ +#define EXTERN +#endif /* SWEAR_C */ +#ifdef DOTERMCAP +EXTERN void tcap_putch __P((int row, int col, char ch)); +EXTERN void tcap_move __P((int row, int col)); +EXTERN void clear_to_eol __P((int row, int col)); +EXTERN void clearscreen(); +EXTERN int io_on __P((int flag)); +EXTERN int io_off(); +EXTERN void scroll_ok_off(); +EXTERN void scroll_ok_on(); +EXTERN void put_insflag __P((int flag)); +EXTERN void put_statusline(); +EXTERN void tcap_putline __P((char *line)); +#endif +#undef EXTERN diff --git a/ircd/buildm4 b/ircd/buildm4 new file mode 100755 index 0000000..bba769c --- /dev/null +++ b/ircd/buildm4 @@ -0,0 +1,98 @@ +#! /bin/sh +# IRC - Internet Relay Chat, ircd/buildm4 +# Copyright (C) 1993, 1994 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. +# +# $Id: buildm4,v 1.11 1999/02/21 00:33:45 kalt Exp $ +# + +# +# If only this was a perl script...*sigh* +# +INCLUDE=`../support/config.guess` +# Installation with absolute path now (Kratz) +M4=$1 +/bin/rm -f $M4 +egrep "^#def[^P]*PATCHLEVEL" ../common/patchlevel.h | \ +sed -e 's/[^\"]*\"\([^\"]*\)\"/define(VERSION,\1)/' >>$M4 +DEBUG=`egrep "^#define[ ]*DEBUGMODE" config.h` +if [ -n "$DEBUG" ] ; then + echo "define(DEBUGMODE,1)" >>$M4 +else + echo "undefine(DEBUGMODE)" >>$M4 +fi +HOST="`hostname | sed -e 's/\([a-zA-Z0-9\-]*\).*/\1/'`" +echo "define(HOSTNAME,$HOST)" >> $M4 + +echo "define(USER,$USER)" >>$M4 + +PORT=`egrep '^#define[ ]*PORT[ ]*[0-9]*' ../$INCLUDE/config.h | \ + sed -e 's/[^0-9]*\([0-9]*\).*/\1/'` +echo "define(PORT,$PORT)" >> $M4 + +PING=`egrep '^#define[ ]*PINGFREQUENCY[ ]*[0-9]*' ../$INCLUDE/config.h\ + | sed -e 's/[^0-9]*\([0-9]*\).*/\1/'` +echo "define(PFREQ,$PING)" >> $M4 + +CONT=`egrep '^#define[ ]*CONNECTFREQUENCY[ ]*[0-9]*' ../$INCLUDE/config.h\ + | sed -e 's/[^0-9]*\([0-9]*\).*/\1/'` +echo "define(CFREQ,$CONT)" >> $M4 + +MAXL=`egrep '^#define[ ]*MAXIMUM_LINKS[ ]*[0-9]* | head -1' \ + ../$INCLUDE/config.h | sed -e 's/[^0-9]*\([0-9]*\).*/\1/'` +echo "define(MAXLINKS,$MAXL)" >> $M4 + +DOM=`egrep '^domain' /etc/resolv.conf | \ + sed -e 's/^domain[ ]*\([^ ]*\).*/\1/'` +echo "define(DOMAIN,$DOM)" >> $M4 + +cat >>$M4 <<_EOF_ +define(CL,\`ifelse(len(\$1),0,0,\$1)') +define(MAXSENDQ,0) +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(UID,\`ifelse(len(\$1),0,unknown,\$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:\$4:) +define(BANIDENT,k:\$1:\$2:\`UID(\$3)':\$4:) +define(CLASS,Y:\$1:\`PING(\$2)':\$3:\`MAX(\$4)':\`SENDQ(\$5)':\$6:\$7) +define(CLIENT,I:\`HOST(\$1)':\`PASS(\$2)':\`ifelse(len(HOST(\$3)),0,\$1,\$3)':\ +\`APORT(\$4)':\`CL(\$5)') +define(RESTRICTED,I:\`HOST(\$1)':\`PASS(\$2)':\ +\`ifelse(len(HOST(\$3)),0,\$1,\$3)':\`APORT(\$4)':\`CL(\$5)') +define(BOUNCE,B:\$1::\$2:\$3:) +define(CONNECT,C:\`HOST(\$1)':\`PASS(\$2)':\`SERV(\$3)':\ +\`CPORT(\$4)':\`CL(\$5)') +define(EXCLUDEVERSION,V:\$1:\$2:\`ifelse(len(\$3),0,*,\$3)'::) +define(ME,M:\$1:\$2:\$3:\$4:\$5 +P:*:*:*:\$4) +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_ diff --git a/ircd/channel.c b/ircd/channel.c new file mode 100644 index 0000000..752f9ee --- /dev/null +++ b/ircd/channel.c @@ -0,0 +1,3396 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/channel.c + * Copyright (C) 1990 Jarkko Oikarinen and + * University of Oulu, Co 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. + */ + +/* -- Jto -- 09 Jul 1990 + * Bug fix + */ + +/* -- Jto -- 03 Jun 1990 + * Moved m_channel() and related functions from s_msg.c to here + * Many changes to start changing into string channels... + */ + +/* -- Jto -- 24 May 1990 + * Moved is_full() from list.c + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: channel.c,v 1.109 1999/08/13 17:30:16 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define CHANNEL_C +#include "s_externs.h" +#undef CHANNEL_C + +aChannel *channel = NullChn; + +static void add_invite __P((aClient *, aChannel *)); +static int can_join __P((aClient *, aChannel *, char *)); +void channel_modes __P((aClient *, char *, char *, aChannel *)); +static int check_channelmask __P((aClient *, aClient *, char *)); +static aChannel *get_channel __P((aClient *, char *, int)); +static int set_mode __P((aClient *, aClient *, aChannel *, int *, int,\ + char **, char *,char *)); +static void free_channel __P((aChannel *)); + +static int add_modeid __P((int, aClient *, aChannel *, char *)); +static int del_modeid __P((int, aChannel *, char *)); +static Link *match_modeid __P((int, aClient *, aChannel *)); + +static char *PartFmt = ":%s PART %s :%s"; + +/* + * some buffers for rebuilding channel/nick lists with ,'s + */ +static char nickbuf[BUFSIZE], buf[BUFSIZE]; +static char modebuf[MODEBUFLEN], parabuf[MODEBUFLEN]; + +/* + * return the length (>=0) of a chain of links. + */ +static int list_length(lp) +Reg Link *lp; +{ + Reg int count = 0; + + for (; lp; lp = lp->next) + count++; + return count; +} + +/* +** find_chasing +** Find the client structure for a nick name (user) using history +** mechanism if necessary. If the client is not found, an error +** message (NO SUCH NICK) is generated. If the client was found +** through the history, chasing will be 1 and otherwise 0. +*/ +static aClient *find_chasing(sptr, user, chasing) +aClient *sptr; +char *user; +Reg int *chasing; +{ + Reg aClient *who = find_client(user, (aClient *)NULL); + + if (chasing) + *chasing = 0; + if (who) + return who; + if (!(who = get_history(user, (long)KILLCHASETIMELIMIT))) + { + sendto_one(sptr, err_str(ERR_NOSUCHNICK, sptr->name), user); + return NULL; + } + if (chasing) + *chasing = 1; + return who; +} + +/* + * Fixes a string so that the first white space found becomes an end of + * string marker (`\-`). returns the 'fixed' string or "*" if the string + * was NULL length or a NULL pointer. + */ +static char *check_string(s) +Reg char *s; +{ + static char star[2] = "*"; + char *str = s; + + if (BadPtr(s)) + return star; + + for ( ;*s; s++) + if (isspace(*s)) + { + *s = '\0'; + break; + } + + return (BadPtr(str)) ? star : str; +} + +/* + * create a string of form "foo!bar@fubar" given foo, bar and fubar + * as the parameters. If NULL, they become "*". + */ +static char *make_nick_user_host(nick, name, host) +Reg char *nick, *name, *host; +{ + static char namebuf[NICKLEN+USERLEN+HOSTLEN+6]; + Reg char *s = namebuf; + + bzero(namebuf, sizeof(namebuf)); + nick = check_string(nick); + strncpyzt(namebuf, nick, NICKLEN + 1); + s += strlen(s); + *s++ = '!'; + name = check_string(name); + strncpyzt(s, name, USERLEN + 1); + s += strlen(s); + *s++ = '@'; + host = check_string(host); + strncpyzt(s, host, HOSTLEN + 1); + s += strlen(s); + *s = '\0'; + return (namebuf); +} + +/* + * Ban functions to work with mode +b/+e/+I + */ +/* add_modeid - add an id to the list of modes "type" for chptr + * (belongs to cptr) + */ + +static int add_modeid(type, cptr, chptr, modeid) +int type; +aClient *cptr; +aChannel *chptr; +char *modeid; +{ + Reg Link *mode; + Reg int cnt = 0, len = 0; + + if (MyClient(cptr)) + (void) collapse(modeid); + for (mode = chptr->mlist; mode; mode = mode->next) + { + len += strlen(mode->value.cp); + if (MyClient(cptr)) + { + if ((len > MAXBANLENGTH) || (++cnt >= MAXBANS)) + { + sendto_one(cptr, err_str(ERR_BANLISTFULL, + cptr->name), + chptr->chname, modeid); + return -1; + } + if (type == mode->flags && + (!match(mode->value.cp, modeid) || + !match(modeid, mode->value.cp))) + { + int rpl; + + if (type == CHFL_BAN) + rpl = RPL_BANLIST; + else if (type == CHFL_EXCEPTION) + rpl = RPL_EXCEPTLIST; + else + rpl = RPL_INVITELIST; + + sendto_one(cptr, rpl_str(rpl, cptr->name), + chptr->chname, mode->value.cp); + return -1; + } + } + else if (type == mode->flags && !mycmp(mode->value.cp, modeid)) + return -1; + + } + mode = make_link(); + istat.is_bans++; + bzero((char *)mode, sizeof(Link)); + mode->flags = type; + mode->next = chptr->mlist; + mode->value.cp = (char *)MyMalloc(len = strlen(modeid)+1); + istat.is_banmem += len; + (void)strcpy(mode->value.cp, modeid); + chptr->mlist = mode; + return 0; +} + +/* + * del_modeid - delete an id belonging to chptr + * if modeid is null, delete all ids belonging to chptr. + */ +static int del_modeid(type, chptr, modeid) +int type; +aChannel *chptr; +char *modeid; +{ + Reg Link **mode; + Reg Link *tmp; + + if (modeid == NULL) + { + for (mode = &(chptr->mlist); *mode; mode = &((*mode)->next)) + if (type == (*mode)->flags) + { + tmp = *mode; + *mode = tmp->next; + istat.is_banmem -= (strlen(tmp->value.cp) + 1); + istat.is_bans--; + MyFree(tmp->value.cp); + free_link(tmp); + break; + } + } + else for (mode = &(chptr->mlist); *mode; mode = &((*mode)->next)) + if (type == (*mode)->flags && + mycmp(modeid, (*mode)->value.cp)==0) + { + tmp = *mode; + *mode = tmp->next; + istat.is_banmem -= (strlen(modeid) + 1); + istat.is_bans--; + MyFree(tmp->value.cp); + free_link(tmp); + break; + } + return 0; +} + +/* + * match_modeid - returns a pointer to the mode structure if matching else NULL + */ +static Link *match_modeid(type, cptr, chptr) +int type; +aClient *cptr; +aChannel *chptr; +{ + Reg Link *tmp; + char *s; + + if (!IsPerson(cptr)) + return NULL; + + s = make_nick_user_host(cptr->name, cptr->user->username, + cptr->user->host); + + for (tmp = chptr->mlist; tmp; tmp = tmp->next) + if (tmp->flags == type && match(tmp->value.cp, s) == 0) + break; + + if (!tmp && MyConnect(cptr)) + { + char *ip = NULL; + +#ifdef INET6 + ip = (char *) inetntop(AF_INET6, (char *)&cptr->ip, + mydummy, MYDUMMY_SIZE); +#else + ip = (char *) inetntoa((char *)&cptr->ip); +#endif + + if (strcmp(ip, cptr->user->host)) + { + s = make_nick_user_host(cptr->name, + cptr->user->username, ip); + + for (tmp = chptr->mlist; tmp; tmp = tmp->next) + if (tmp->flags == type && + match(tmp->value.cp, s) == 0) + break; + } + } + + return (tmp); +} + +/* + * adds a user to a channel by adding another link to the channels member + * chain. + */ +static void add_user_to_channel(chptr, who, flags) +aChannel *chptr; +aClient *who; +int flags; +{ + Reg Link *ptr; + Reg int sz = sizeof(aChannel) + strlen(chptr->chname); + + if (who->user) + { + ptr = make_link(); + ptr->flags = flags; + ptr->value.cptr = who; + ptr->next = chptr->members; + chptr->members = ptr; + istat.is_chanusers++; + if (chptr->users++ == 0) + { + istat.is_chan++; + istat.is_chanmem += sz; + } + if (chptr->users == 1 && chptr->history) + { + /* Locked channel */ + istat.is_hchan--; + istat.is_hchanmem -= sz; + /* + ** The modes had been kept, but now someone is joining, + ** they should be reset to avoid desynchs + ** (you wouldn't want to join a +i channel, either) + ** + ** This can be wrong in some cases such as a netjoin + ** which will not complete, or on a mixed net (with + ** servers that don't do channel delay) - kalt + */ + if (*chptr->chname != '!') + bzero((char *)&chptr->mode, sizeof(Mode)); + } + +#ifdef USE_SERVICES + if (chptr->users == 1) + check_services_butone(SERVICE_WANT_CHANNEL| + SERVICE_WANT_VCHANNEL, + NULL, &me, "CHANNEL %s %d", + chptr->chname, chptr->users); + else + check_services_butone(SERVICE_WANT_VCHANNEL, + NULL, &me, "CHANNEL %s %d", + chptr->chname, chptr->users); +#endif + ptr = make_link(); + ptr->flags = flags; + ptr->value.chptr = chptr; + ptr->next = who->user->channel; + who->user->channel = ptr; + if (!IsQuiet(chptr)) + { + who->user->joined++; + istat.is_userc++; + } + + if (!(ptr = find_user_link(chptr->clist, who->from))) + { + ptr = make_link(); + ptr->value.cptr = who->from; + ptr->next = chptr->clist; + chptr->clist = ptr; + } + ptr->flags++; + } +} + +void remove_user_from_channel(sptr, chptr) +aClient *sptr; +aChannel *chptr; +{ + Reg Link **curr; + Reg Link *tmp, *tmp2; + + for (curr = &chptr->members; (tmp = *curr); curr = &tmp->next) + if (tmp->value.cptr == sptr) + { + /* + * if a chanop leaves (no matter how), record + * the time to be able to later massreop if + * necessary. + */ + if (*chptr->chname == '!' && + (tmp->flags & CHFL_CHANOP)) + chptr->reop = timeofday + LDELAYCHASETIMELIMIT; + + *curr = tmp->next; + free_link(tmp); + break; + } + for (curr = &sptr->user->channel; (tmp = *curr); curr = &tmp->next) + if (tmp->value.chptr == chptr) + { + *curr = tmp->next; + free_link(tmp); + break; + } + if (sptr->from) + tmp2 = find_user_link(chptr->clist, sptr->from); + else + tmp2 = find_user_link(chptr->clist, sptr); + if (tmp2 && !--tmp2->flags) + for (curr = &chptr->clist; (tmp = *curr); curr = &tmp->next) + if (tmp2 == tmp) + { + *curr = tmp->next; + free_link(tmp); + break; + } + if (!IsQuiet(chptr)) + { + sptr->user->joined--; + istat.is_userc--; + } +#ifdef USE_SERVICES + if (chptr->users == 1) + check_services_butone(SERVICE_WANT_CHANNEL| + SERVICE_WANT_VCHANNEL, NULL, &me, + "CHANNEL %s %d", chptr->chname, + chptr->users-1); + else + check_services_butone(SERVICE_WANT_VCHANNEL, NULL, &me, + "CHANNEL %s %d", chptr->chname, + chptr->users-1); +#endif + if (--chptr->users <= 0) + { + u_int sz = sizeof(aChannel) + strlen(chptr->chname); + + istat.is_chan--; + istat.is_chanmem -= sz; + istat.is_hchan++; + istat.is_hchanmem += sz; + free_channel(chptr); + } + istat.is_chanusers--; +} + +static void change_chan_flag(lp, chptr) +Link *lp; +aChannel *chptr; +{ + Reg Link *tmp; + aClient *cptr = lp->value.cptr; + + /* + * Set the channel members flags... + */ + tmp = find_user_link(chptr->members, cptr); + if (lp->flags & MODE_ADD) + tmp->flags |= lp->flags & MODE_FLAGS; + else + { + tmp->flags &= ~lp->flags & MODE_FLAGS; + if (lp->flags & CHFL_CHANOP) + tmp->flags &= ~CHFL_UNIQOP; + } + /* + * and make sure client membership mirrors channel + */ + tmp = find_user_link(cptr->user->channel, (aClient *)chptr); + if (lp->flags & MODE_ADD) + tmp->flags |= lp->flags & MODE_FLAGS; + else + { + tmp->flags &= ~lp->flags & MODE_FLAGS; + if (lp->flags & CHFL_CHANOP) + tmp->flags &= ~CHFL_UNIQOP; + } +} + +int is_chan_op(cptr, chptr) +aClient *cptr; +aChannel *chptr; +{ + Reg Link *lp; + int chanop = 0; + + if (MyConnect(cptr) && IsPerson(cptr) && IsRestricted(cptr) && + *chptr->chname != '&') + return 0; + if (chptr) + if ((lp = find_user_link(chptr->members, cptr))) + chanop = (lp->flags & (CHFL_CHANOP|CHFL_UNIQOP)); + if (chanop) + chptr->reop = 0; + return chanop; +} + +int has_voice(cptr, chptr) +aClient *cptr; +aChannel *chptr; +{ + Reg Link *lp; + + if (chptr) + if ((lp = find_user_link(chptr->members, cptr))) + return (lp->flags & CHFL_VOICE); + + return 0; +} + +int can_send(cptr, chptr) +aClient *cptr; +aChannel *chptr; +{ + Reg Link *lp; + Reg int member; + + member = IsMember(cptr, chptr); + lp = find_user_link(chptr->members, cptr); + + if ((!lp || !(lp->flags & (CHFL_CHANOP | CHFL_VOICE))) && + !match_modeid(CHFL_EXCEPTION, cptr, chptr) && + match_modeid(CHFL_BAN, cptr, chptr)) + return (MODE_BAN); + + if (chptr->mode.mode & MODE_MODERATED && + (!lp || !(lp->flags & (CHFL_CHANOP|CHFL_VOICE)))) + return (MODE_MODERATED); + + if (chptr->mode.mode & MODE_NOPRIVMSGS && !member) + return (MODE_NOPRIVMSGS); + + return 0; +} + +aChannel *find_channel(chname, chptr) +Reg char *chname; +Reg aChannel *chptr; +{ + aChannel *achptr = chptr; + + if (chname && *chname) + achptr = hash_find_channel(chname, chptr); + return achptr; +} + +void setup_server_channels(mp) +aClient *mp; +{ + aChannel *chptr; + int smode; + + smode = MODE_MODERATED|MODE_TOPICLIMIT|MODE_NOPRIVMSGS|MODE_ANONYMOUS| + MODE_QUIET; + + chptr = get_channel(mp, "&ERRORS", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: server errors"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; + chptr = get_channel(mp, "&NOTICES", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: warnings and notices"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; + chptr = get_channel(mp, "&KILLS", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: operator and server kills"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; + chptr = get_channel(mp, "&CHANNEL", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: fake modes"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; + chptr = get_channel(mp, "&NUMERICS", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: numerics received"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; + chptr = get_channel(mp, "&SERVERS", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: servers joining and leaving"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; + chptr = get_channel(mp, "&HASH", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: hash tables growth"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; + chptr = get_channel(mp, "&LOCAL", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: notices about local connections"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; + chptr = get_channel(mp, "&SERVICES", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: services joining and leaving"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; +#if defined(USE_IAUTH) + chptr = get_channel(mp, "&AUTH", CREATE); + strcpy(chptr->topic, + "SERVER MESSAGES: messages from the authentication slave"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode; +#endif + chptr = get_channel(mp, "&DEBUG", CREATE); + strcpy(chptr->topic, "SERVER MESSAGES: debug messages [you shouldn't be here! ;)]"); + add_user_to_channel(chptr, mp, CHFL_CHANOP); + chptr->mode.mode = smode|MODE_SECRET; + + setup_svchans(); +} + +/* + * write the "simple" list of channel modes for channel chptr onto buffer mbuf + * with the parameters in pbuf. + */ +void channel_modes(cptr, mbuf, pbuf, chptr) +aClient *cptr; +Reg char *mbuf, *pbuf; +aChannel *chptr; +{ + *mbuf++ = '+'; + if (chptr->mode.mode & MODE_SECRET) + *mbuf++ = 's'; + else if (chptr->mode.mode & MODE_PRIVATE) + *mbuf++ = 'p'; + if (chptr->mode.mode & MODE_MODERATED) + *mbuf++ = 'm'; + if (chptr->mode.mode & MODE_TOPICLIMIT) + *mbuf++ = 't'; + if (chptr->mode.mode & MODE_INVITEONLY) + *mbuf++ = 'i'; + if (chptr->mode.mode & MODE_NOPRIVMSGS) + *mbuf++ = 'n'; + if (chptr->mode.mode & MODE_ANONYMOUS) + *mbuf++ = 'a'; + if (chptr->mode.mode & MODE_QUIET) + *mbuf++ = 'q'; + if (chptr->mode.mode & MODE_REOP) + *mbuf++ = 'r'; + if (chptr->mode.limit) + { + *mbuf++ = 'l'; + if (IsMember(cptr, chptr) || IsServer(cptr)) + SPRINTF(pbuf, "%d ", chptr->mode.limit); + } + if (*chptr->mode.key) + { + *mbuf++ = 'k'; + if (IsMember(cptr, chptr) || IsServer(cptr)) + (void)strcat(pbuf, chptr->mode.key); + } + *mbuf++ = '\0'; + return; +} + +static void send_mode_list(cptr, chname, top, mask, flag) +aClient *cptr; +Link *top; +int mask; +char flag, *chname; +{ + Reg Link *lp; + Reg char *cp, *name; + int count = 0, send = 0; + + cp = modebuf + strlen(modebuf); + if (*parabuf) /* mode +l or +k xx */ + count = strlen(modebuf)-1; + for (lp = top; lp; lp = lp->next) + { + if (!(lp->flags & mask)) + continue; + if (mask == CHFL_BAN || mask == CHFL_EXCEPTION || + mask == CHFL_INVITE) + name = lp->value.cp; + else + name = lp->value.cptr->name; + if (strlen(parabuf) + strlen(name) + 10 < (size_t) MODEBUFLEN) + { + (void)strcat(parabuf, " "); + (void)strcat(parabuf, name); + count++; + *cp++ = flag; + *cp = '\0'; + } + else if (*parabuf) + send = 1; + if (count == 3) + send = 1; + if (send) + { + sendto_one(cptr, ":%s MODE %s %s %s", + ME, chname, modebuf, parabuf); + send = 0; + *parabuf = '\0'; + cp = modebuf; + *cp++ = '+'; + if (count != 3) + { + (void)strcpy(parabuf, name); + *cp++ = flag; + } + count = 0; + *cp = '\0'; + } + } +} + +/* + * send "cptr" a full list of the modes for channel chptr. + */ +void send_channel_modes(cptr, chptr) +aClient *cptr; +aChannel *chptr; +{ +#if 0 +this is probably going to be very annoying, but leaving the following code +uncommented may just lead to desynchs.. + if ((*chptr->chname != '#' && *chptr->chname != '!') + || chptr->users == 0) /* channel is empty (locked), thus no mode */ + return; +#endif + + if (check_channelmask(&me, cptr, chptr->chname)) + return; + + *modebuf = *parabuf = '\0'; + channel_modes(cptr, modebuf, parabuf, chptr); + + if (modebuf[1] || *parabuf) + sendto_one(cptr, ":%s MODE %s %s %s", + ME, chptr->chname, modebuf, parabuf); + + *parabuf = '\0'; + *modebuf = '+'; + modebuf[1] = '\0'; + send_mode_list(cptr, chptr->chname, chptr->mlist, CHFL_BAN, 'b'); + if (cptr->serv->version & SV_NMODE) + { + if (modebuf[1] || *parabuf) + { + /* only needed to help compatibility */ + sendto_one(cptr, ":%s MODE %s %s %s", + ME, chptr->chname, modebuf, parabuf); + *parabuf = '\0'; + *modebuf = '+'; + modebuf[1] = '\0'; + } + send_mode_list(cptr, chptr->chname, chptr->mlist, + CHFL_EXCEPTION, 'e'); + send_mode_list(cptr, chptr->chname, chptr->mlist, + CHFL_INVITE, 'I'); + } + if (modebuf[1] || *parabuf) + sendto_one(cptr, ":%s MODE %s %s %s", + ME, chptr->chname, modebuf, parabuf); +} + +/* + * send "cptr" a full list of the channel "chptr" members and their + * +ov status, using NJOIN + */ +void send_channel_members(cptr, chptr) +aClient *cptr; +aChannel *chptr; +{ + Reg Link *lp; + Reg aClient *c2ptr; + Reg int cnt = 0, len = 0, nlen; + + if (check_channelmask(&me, cptr, chptr->chname) == -1) + return; + if (*chptr->chname == '!' && !(cptr->serv->version & SV_NCHAN)) + return; + + sprintf(buf, ":%s NJOIN %s :", ME, chptr->chname); + len = strlen(buf); + + for (lp = chptr->members; lp; lp = lp->next) + { + c2ptr = lp->value.cptr; + nlen = strlen(c2ptr->name); + if ((len + nlen) > (size_t) (BUFSIZE - 9)) /* ,@+ \r\n\0 */ + { + sendto_one(cptr, "%s", buf); + sprintf(buf, ":%s NJOIN %s :", ME, chptr->chname); + len = strlen(buf); + cnt = 0; + } + if (cnt) + { + buf[len++] = ','; + buf[len] = '\0'; + } + if (lp->flags & (CHFL_UNIQOP|CHFL_CHANOP|CHFL_VOICE)) + { + if (lp->flags & CHFL_UNIQOP) + { + buf[len++] = '@'; + buf[len++] = '@'; + } + else + { + if (lp->flags & CHFL_CHANOP) + buf[len++] = '@'; + } + if (lp->flags & CHFL_VOICE) + buf[len++] = '+'; + buf[len] = '\0'; + } + (void)strcpy(buf + len, c2ptr->name); + len += nlen; + cnt++; + } + if (*buf && cnt) + sendto_one(cptr, "%s", buf); + + return; +} + +/* + * m_mode + * parv[0] - sender + * parv[1] - target; channels and/or user + * parv[2] - optional modes + * parv[n] - optional parameters + */ + +int m_mode(cptr, sptr, parc, parv) +aClient *cptr; +aClient *sptr; +int parc; +char *parv[]; +{ + int mcount = 0, chanop; + int penalty = 0; + aChannel *chptr; + char *name, *p = NULL; + + if (parc < 1) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "MODE"); + return 1; + } + + parv[1] = canonize(parv[1]); + + for (name = strtoken(&p, parv[1], ","); name; + name = strtoken(&p, NULL, ",")) + { + clean_channelname(name); + chptr = find_channel(name, NullChn); + if (chptr == NullChn) + { + parv[1] = name; + penalty += m_umode(cptr, sptr, parc, parv); + continue; + } + if (check_channelmask(sptr, cptr, name)) + { + penalty += 1; + continue; + } + if (!UseModes(name)) + { + sendto_one(sptr, err_str(ERR_NOCHANMODES, parv[0]), + name); + penalty += 1; + continue; + } + chanop = is_chan_op(sptr, chptr) || IsServer(sptr); + + if (parc < 3) /* Only a query */ + { + *modebuf = *parabuf = '\0'; + modebuf[1] = '\0'; + channel_modes(sptr, modebuf, parabuf, chptr); + sendto_one(sptr, rpl_str(RPL_CHANNELMODEIS, parv[0]), + name, modebuf, parabuf); + penalty += 1; + } + else /* Check parameters for the channel */ + { + if(!(mcount = set_mode(cptr, sptr, chptr, &penalty, + parc - 2, parv + 2, + modebuf, parabuf))) + continue; /* no valid mode change */ + if ((mcount < 0) && MyConnect(sptr) && !IsServer(sptr)) + { /* rejected mode change */ + int num = ERR_CHANOPRIVSNEEDED; + + if (IsClient(sptr) && IsRestricted(sptr)) + num = ERR_RESTRICTED; + sendto_one(sptr, err_str(num, parv[0]), name); + continue; + } + if (strlen(modebuf) > (size_t)1) + { /* got new mode to pass on */ + if (modebuf[1] == 'e' || modebuf[1] == 'I') + /* 2.9.x compatibility */ + sendto_match_servs_v(chptr, cptr, + SV_NMODE, + ":%s MODE %s %s %s", + parv[0], name, + modebuf, parabuf); + else + sendto_match_servs(chptr, cptr, + ":%s MODE %s %s %s", + parv[0], name, + modebuf, parabuf); + if ((IsServer(cptr) && !IsServer(sptr) && + !chanop) || mcount < 0) + { + sendto_flag(SCH_CHAN, + "Fake: %s MODE %s %s %s", + parv[0], name, modebuf, + parabuf); + ircstp->is_fake++; + } + else + { + sendto_channel_butserv(chptr, sptr, + ":%s MODE %s %s %s", + parv[0], name, + modebuf, parabuf); +#ifdef USE_SERVICES + *modebuf = *parabuf = '\0'; + modebuf[1] = '\0'; + channel_modes(&me, modebuf, parabuf, + chptr); + check_services_butone(SERVICE_WANT_MODE, + NULL, sptr, + "MODE %s %s", + name, modebuf); +#endif + } + } /* if(modebuf) */ + } /* else(parc>2) */ + } /* for (parv1) */ + return penalty; +} + +/* + * Check and try to apply the channel modes passed in the parv array for + * the client cptr to channel chptr. The resultant changes are printed + * into mbuf and pbuf (if any) and applied to the channel. + */ +static int set_mode(cptr, sptr, chptr, penalty, parc, parv, mbuf, pbuf) +Reg aClient *cptr, *sptr; +aChannel *chptr; +int parc, *penalty; +char *parv[], *mbuf, *pbuf; +{ + static Link chops[MAXMODEPARAMS+3]; + static int flags[] = { + MODE_PRIVATE, 'p', MODE_SECRET, 's', + MODE_MODERATED, 'm', MODE_NOPRIVMSGS, 'n', + MODE_TOPICLIMIT, 't', MODE_INVITEONLY, 'i', + MODE_ANONYMOUS, 'a', MODE_REOP, 'r', + 0x0, 0x0 }; + + Reg Link *lp = NULL; + Reg char *curr = parv[0], *cp = NULL; + Reg int *ip; + u_int whatt = MODE_ADD; + int limitset = 0, count = 0, chasing = 0; + int nusers = 0, ischop, new, len, keychange = 0, opcnt = 0; + aClient *who; + Mode *mode, oldm; + Link *plp = NULL; + int compat = -1; /* to prevent mixing old/new modes */ + + *mbuf = *pbuf = '\0'; + if (parc < 1) + return 0; + + mode = &(chptr->mode); + bcopy((char *)mode, (char *)&oldm, sizeof(Mode)); + ischop = IsServer(sptr) || is_chan_op(sptr, chptr); + new = mode->mode; + + while (curr && *curr && count >= 0) + { + if (compat == -1 && *curr != '-' && *curr != '+') + if (*curr == 'e' || *curr == 'I') + compat = 1; + else + compat = 0; + switch (*curr) + { + case '+': + whatt = MODE_ADD; + break; + case '-': + whatt = MODE_DEL; + break; + case 'O': + if (parc > 0) + { + if (*chptr->chname == '!') + { + if (IsMember(sptr, chptr)) + { + *penalty += 1; + parc--; + /* Feature: no other modes after this query */ + *(curr+1) = '\0'; + for (lp = chptr->members; lp; lp = lp->next) + if (lp->flags & CHFL_UNIQOP) + { + sendto_one(sptr, + rpl_str(RPL_UNIQOPIS, + sptr->name), + chptr->chname, + lp->value.cptr->name); + break; + } + if (!lp) + sendto_one(sptr, + err_str(ERR_NOSUCHNICK, + sptr->name), + chptr->chname); + break; + } + else /* not IsMember() */ + { + if (!IsServer(sptr)) + { + sendto_one(sptr, err_str(ERR_NOTONCHANNEL, sptr->name), + chptr->chname); + *(curr+1) = '\0'; + break; + } + } + } + else /* *chptr->chname != '!' */ + sendto_one(cptr, err_str(ERR_UNKNOWNMODE, + sptr->name), *curr, chptr->chname); + *(curr+1) = '\0'; + break; + } + /* + * is this really ever used ? + * or do ^G & NJOIN do the trick? + */ + if (*chptr->chname != '!' || whatt == MODE_DEL || + !IsServer(sptr)) + { + *penalty += 1; + --parc; + parv++; + break; + } + case 'o' : + case 'v' : + *penalty += 1; + if (--parc <= 0) + break; + parv++; + *parv = check_string(*parv); + if (opcnt >= MAXMODEPARAMS) +#ifndef V29PlusOnly + if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1) +#endif + break; + if (!IsServer(sptr) && !IsMember(sptr, chptr)) + { + sendto_one(sptr, err_str(ERR_NOTONCHANNEL, + sptr->name), + chptr->chname); + break; + } + /* + * Check for nickname changes and try to follow these + * to make sure the right client is affected by the + * mode change. + */ + if (!(who = find_chasing(sptr, parv[0], &chasing))) + break; + if (!IsMember(who, chptr)) + { + sendto_one(sptr, err_str(ERR_USERNOTINCHANNEL, + sptr->name), + parv[0], chptr->chname); + break; + } + if (who == cptr && whatt == MODE_ADD && *curr == 'o') + break; + + if (whatt == MODE_ADD) + { + lp = &chops[opcnt++]; + lp->value.cptr = who; + lp->flags = (*curr == 'O') ? MODE_UNIQOP: + (*curr == 'o') ? MODE_CHANOP: + MODE_VOICE; + lp->flags |= MODE_ADD; + } + else if (whatt == MODE_DEL) + { + lp = &chops[opcnt++]; + lp->value.cptr = who; + lp->flags = (*curr == 'o') ? MODE_CHANOP: + MODE_VOICE; + lp->flags |= MODE_DEL; + } + if (plp && plp->flags == lp->flags && + plp->value.cptr == lp->value.cptr) + { + opcnt--; + break; + } + plp = lp; + /* + ** If this server noticed the nick change, the + ** information must be propagated back upstream. + ** This is a bit early, but at most this will generate + ** just some extra messages if nick appeared more than + ** once in the MODE message... --msa + */ +/* nobody can figure this part of the code anymore.. -kalt + if (chasing && ischop) + sendto_one(cptr, ":%s MODE %s %c%c %s", + ME, chptr->chname, + whatt == MODE_ADD ? '+' : '-', + *curr, who->name); +*/ + count++; + *penalty += 2; + break; + case 'k': + *penalty += 1; + if (--parc <= 0) + break; + parv++; + /* check now so we eat the parameter if present */ + if (keychange) + break; + { + Reg u_char *s; + + for (s = (u_char *)*parv; *s; ) + if (*s > 0x7f) + if (*s > 0xa0) + *s++ &= 0x7f; + else + *s = '\0'; + else + s++; + } + + if (!**parv) + break; + *parv = check_string(*parv); + if (opcnt >= MAXMODEPARAMS) +#ifndef V29PlusOnly + if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1) +#endif + break; + if (whatt == MODE_ADD) + { + if (*mode->key && !IsServer(cptr)) + sendto_one(cptr, err_str(ERR_KEYSET, + cptr->name), chptr->chname); + else if (ischop && + (!*mode->key || IsServer(cptr))) + { + if (**parv == ':') + /* this won't propagate right*/ + break; + lp = &chops[opcnt++]; + lp->value.cp = *parv; + if (strlen(lp->value.cp) > + (size_t) KEYLEN) + lp->value.cp[KEYLEN] = '\0'; + lp->flags = MODE_KEY|MODE_ADD; + keychange = 1; + } + } + else if (whatt == MODE_DEL) + { + if (ischop && (mycmp(mode->key, *parv) == 0 || + IsServer(cptr))) + { + lp = &chops[opcnt++]; + lp->value.cp = mode->key; + lp->flags = MODE_KEY|MODE_DEL; + keychange = 1; + } + } + count++; + *penalty += 2; + break; + case 'b': + *penalty += 1; + if (--parc <= 0) /* ban list query */ + { + /* Feature: no other modes after ban query */ + *(curr+1) = '\0'; /* Stop MODE # bb.. */ + for (lp = chptr->mlist; lp; lp = lp->next) + if (lp->flags == CHFL_BAN) + sendto_one(cptr, + rpl_str(RPL_BANLIST, + cptr->name), + chptr->chname, + lp->value.cp); + sendto_one(cptr, rpl_str(RPL_ENDOFBANLIST, + cptr->name), chptr->chname); + break; + } + parv++; + if (BadPtr(*parv)) + break; + if (opcnt >= MAXMODEPARAMS) +#ifndef V29PlusOnly + if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1) +#endif + break; + if (whatt == MODE_ADD) + { + if (**parv == ':') + /* this won't propagate right */ + break; + lp = &chops[opcnt++]; + lp->value.cp = *parv; + lp->flags = MODE_ADD|MODE_BAN; + } + else if (whatt == MODE_DEL) + { + lp = &chops[opcnt++]; + lp->value.cp = *parv; + lp->flags = MODE_DEL|MODE_BAN; + } + count++; + *penalty += 2; + break; + case 'e': + *penalty += 1; + if (--parc <= 0) /* exception list query */ + { + /* Feature: no other modes after query */ + *(curr+1) = '\0'; /* Stop MODE # bb.. */ + for (lp = chptr->mlist; lp; lp = lp->next) + if (lp->flags == CHFL_EXCEPTION) + sendto_one(cptr, + rpl_str(RPL_EXCEPTLIST, + cptr->name), + chptr->chname, + lp->value.cp); + sendto_one(cptr, rpl_str(RPL_ENDOFEXCEPTLIST, + cptr->name), chptr->chname); + break; + } + parv++; + if (BadPtr(*parv)) + break; + if (opcnt >= MAXMODEPARAMS) +#ifndef V29PlusOnly + if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1) +#endif + break; + if (whatt == MODE_ADD) + { + if (**parv == ':') + /* this won't propagate right */ + break; + lp = &chops[opcnt++]; + lp->value.cp = *parv; + lp->flags = MODE_ADD|MODE_EXCEPTION; + } + else if (whatt == MODE_DEL) + { + lp = &chops[opcnt++]; + lp->value.cp = *parv; + lp->flags = MODE_DEL|MODE_EXCEPTION; + } + count++; + *penalty += 2; + break; + case 'I': + *penalty += 1; + if (--parc <= 0) /* invite list query */ + { + /* Feature: no other modes after query */ + *(curr+1) = '\0'; /* Stop MODE # bb.. */ + for (lp = chptr->mlist; lp; lp = lp->next) + if (lp->flags == CHFL_INVITE) + sendto_one(cptr, + rpl_str(RPL_INVITELIST, + cptr->name), + chptr->chname, + lp->value.cp); + sendto_one(cptr, rpl_str(RPL_ENDOFINVITELIST, + cptr->name), chptr->chname); + break; + } + parv++; + if (BadPtr(*parv)) + break; + if (opcnt >= MAXMODEPARAMS) +#ifndef V29PlusOnly + if (MyClient(sptr) || opcnt >= MAXMODEPARAMS + 1) +#endif + break; + if (whatt == MODE_ADD) + { + if (**parv == ':') + /* this won't propagate right */ + break; + lp = &chops[opcnt++]; + lp->value.cp = *parv; + lp->flags = MODE_ADD|MODE_INVITE; + } + else if (whatt == MODE_DEL) + { + lp = &chops[opcnt++]; + lp->value.cp = *parv; + lp->flags = MODE_DEL|MODE_INVITE; + } + count++; + *penalty += 2; + break; + case 'l': + *penalty += 1; + /* + * limit 'l' to only *1* change per mode command but + * eat up others. + */ + if (limitset || !ischop) + { + if (whatt == MODE_ADD && --parc > 0) + parv++; + break; + } + if (whatt == MODE_DEL) + { + limitset = 1; + nusers = 0; + count++; + break; + } + if (--parc > 0) + { + if (BadPtr(*parv)) + break; + if (opcnt >= MAXMODEPARAMS) +#ifndef V29PlusOnly + if (MyClient(sptr) || + opcnt >= MAXMODEPARAMS + 1) +#endif + break; + if (!(nusers = atoi(*++parv))) + break; + lp = &chops[opcnt++]; + lp->flags = MODE_ADD|MODE_LIMIT; + limitset = 1; + count++; + *penalty += 2; + break; + } + sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS, + cptr->name), "MODE +l"); + break; + case 'i' : /* falls through for default case */ + if (whatt == MODE_DEL) + while ((lp = chptr->invites)) + del_invite(lp->value.cptr, chptr); + default: + *penalty += 1; + for (ip = flags; *ip; ip += 2) + if (*(ip+1) == *curr) + break; + + if (*ip) + { + if (*ip == MODE_ANONYMOUS && + whatt == MODE_DEL && *chptr->chname == '!') + sendto_one(sptr, + err_str(ERR_UNIQOPRIVSNEEDED, + sptr->name), chptr->chname); + else if (((*ip == MODE_ANONYMOUS && + whatt == MODE_ADD && + *chptr->chname == '#') || + (*ip == MODE_REOP && + *chptr->chname != '!')) && + !IsServer(sptr)) + sendto_one(cptr, + err_str(ERR_UNKNOWNMODE, + sptr->name), *curr, + chptr->chname); + else if ((*ip == MODE_REOP || + *ip == MODE_ANONYMOUS) && + !IsServer(sptr) && + !(is_chan_op(sptr,chptr) &CHFL_UNIQOP) + && *chptr->chname == '!') + /* 2 modes restricted to UNIQOP */ + sendto_one(sptr, + err_str(ERR_UNIQOPRIVSNEEDED, + sptr->name), chptr->chname); + else + { + /* + ** If the channel is +s, ignore +p + ** modes coming from a server. + ** (Otherwise, it's desynch'ed) -kalt + */ + if (whatt == MODE_ADD && + *ip == MODE_PRIVATE && + IsServer(sptr) && + (new & MODE_SECRET)) + break; + if (whatt == MODE_ADD) + { + if (*ip == MODE_PRIVATE) + new &= ~MODE_SECRET; + else if (*ip == MODE_SECRET) + new &= ~MODE_PRIVATE; + new |= *ip; + } + else + new &= ~*ip; + count++; + *penalty += 2; + } + } + else if (!IsServer(cptr)) + sendto_one(cptr, err_str(ERR_UNKNOWNMODE, + cptr->name), *curr, chptr->chname); + break; + } + curr++; + /* + * Make sure modes strings such as "+m +t +p +i" are parsed + * fully. + */ + if (!*curr && parc > 0) + { + curr = *++parv; + parc--; + } + /* + * Make sure old and new (+e/+I) modes won't get mixed + * together on the same line + */ + if (MyClient(sptr) && curr && *curr != '-' && *curr != '+') + if (*curr == 'e' || *curr == 'I') + { + if (compat == 0) + *curr = '\0'; + } + else if (compat == 1) + *curr = '\0'; + } /* end of while loop for MODE processing */ + + whatt = 0; + + for (ip = flags; *ip; ip += 2) + if ((*ip & new) && !(*ip & oldm.mode)) + { + if (whatt == 0) + { + *mbuf++ = '+'; + whatt = 1; + } + if (ischop) + { + mode->mode |= *ip; + if (*ip == MODE_ANONYMOUS && MyPerson(sptr)) + { + sendto_channel_butone(NULL, &me, chptr, ":%s NOTICE %s :The anonymous flag is being set on channel %s.", ME, chptr->chname, chptr->chname); + sendto_channel_butone(NULL, &me, chptr, ":%s NOTICE %s :Be aware that anonymity on IRC is NOT securely enforced!", ME, chptr->chname); + } + } + *mbuf++ = *(ip+1); + } + + for (ip = flags; *ip; ip += 2) + if ((*ip & oldm.mode) && !(*ip & new)) + { + if (whatt != -1) + { + *mbuf++ = '-'; + whatt = -1; + } + if (ischop) + mode->mode &= ~*ip; + *mbuf++ = *(ip+1); + } + + if (limitset && !nusers && mode->limit) + { + if (whatt != -1) + { + *mbuf++ = '-'; + whatt = -1; + } + mode->mode &= ~MODE_LIMIT; + mode->limit = 0; + *mbuf++ = 'l'; + } + + /* + * Reconstruct "+beIkOov" chain. + */ + if (opcnt) + { + Reg int i = 0; + Reg char c = '\0'; + char *user, *host, numeric[16]; + +/* if (opcnt > MAXMODEPARAMS) + opcnt = MAXMODEPARAMS; +*/ + for (; i < opcnt; i++) + { + lp = &chops[i]; + /* + * make sure we have correct mode change sign + */ + if (whatt != (lp->flags & (MODE_ADD|MODE_DEL))) + if (lp->flags & MODE_ADD) + { + *mbuf++ = '+'; + whatt = MODE_ADD; + } + else + { + *mbuf++ = '-'; + whatt = MODE_DEL; + } + len = strlen(pbuf); + /* + * get c as the mode char and tmp as a pointer to + * the paramter for this mode change. + */ + switch(lp->flags & MODE_WPARAS) + { + case MODE_CHANOP : + c = 'o'; + cp = lp->value.cptr->name; + break; + case MODE_UNIQOP : + c = 'O'; + cp = lp->value.cptr->name; + break; + case MODE_VOICE : + c = 'v'; + cp = lp->value.cptr->name; + break; + case MODE_BAN : + c = 'b'; + cp = lp->value.cp; + if ((user = index(cp, '!'))) + *user++ = '\0'; + if ((host = rindex(user ? user : cp, '@'))) + *host++ = '\0'; + cp = make_nick_user_host(cp, user, host); + if (user) + *(--user) = '!'; + if (host) + *(--host) = '@'; + break; + case MODE_EXCEPTION : + c = 'e'; + cp = lp->value.cp; + if ((user = index(cp, '!'))) + *user++ = '\0'; + if ((host = rindex(user ? user : cp, '@'))) + *host++ = '\0'; + cp = make_nick_user_host(cp, user, host); + if (user) + *(--user) = '!'; + if (host) + *(--host) = '@'; + break; + case MODE_INVITE : + c = 'I'; + cp = lp->value.cp; + if ((user = index(cp, '!'))) + *user++ = '\0'; + if ((host = rindex(user ? user : cp, '@'))) + *host++ = '\0'; + cp = make_nick_user_host(cp, user, host); + if (user) + *(--user) = '!'; + if (host) + *(--host) = '@'; + break; + case MODE_KEY : + c = 'k'; + cp = lp->value.cp; + break; + case MODE_LIMIT : + c = 'l'; + (void)sprintf(numeric, "%-15d", nusers); + if ((cp = index(numeric, ' '))) + *cp = '\0'; + cp = numeric; + break; + } + + if (len + strlen(cp) + 2 > (size_t) MODEBUFLEN) + break; + /* + * pass on +/-o/v regardless of whether they are + * redundant or effective but check +b's to see if + * it existed before we created it. + */ + switch(lp->flags & MODE_WPARAS) + { + case MODE_KEY : + *mbuf++ = c; + (void)strcat(pbuf, cp); + len += strlen(cp); + (void)strcat(pbuf, " "); + len++; + if (!ischop) + break; + if (strlen(cp) > (size_t) KEYLEN) + *(cp+KEYLEN) = '\0'; + if (whatt == MODE_ADD) + strncpyzt(mode->key, cp, + sizeof(mode->key)); + else + *mode->key = '\0'; + break; + case MODE_LIMIT : + *mbuf++ = c; + (void)strcat(pbuf, cp); + len += strlen(cp); + (void)strcat(pbuf, " "); + len++; + if (!ischop) + break; + mode->limit = nusers; + break; + case MODE_CHANOP : /* fall through case */ + if (ischop && lp->value.cptr == sptr && + lp->flags == MODE_CHANOP|MODE_DEL) + chptr->reop = timeofday + + LDELAYCHASETIMELIMIT; + case MODE_UNIQOP : + case MODE_VOICE : + *mbuf++ = c; + (void)strcat(pbuf, cp); + len += strlen(cp); + (void)strcat(pbuf, " "); + len++; + if (ischop) + change_chan_flag(lp, chptr); + break; + case MODE_BAN : + if (ischop && + (((whatt & MODE_ADD) && + !add_modeid(CHFL_BAN, sptr, chptr, cp))|| + ((whatt & MODE_DEL) && + !del_modeid(CHFL_BAN, chptr, cp)))) + { + *mbuf++ = c; + (void)strcat(pbuf, cp); + len += strlen(cp); + (void)strcat(pbuf, " "); + len++; + } + break; + case MODE_EXCEPTION : + if (ischop && + (((whatt & MODE_ADD) && + !add_modeid(CHFL_EXCEPTION, sptr, chptr, cp))|| + ((whatt & MODE_DEL) && + !del_modeid(CHFL_EXCEPTION, chptr, cp)))) + { + *mbuf++ = c; + (void)strcat(pbuf, cp); + len += strlen(cp); + (void)strcat(pbuf, " "); + len++; + } + break; + case MODE_INVITE : + if (ischop && + (((whatt & MODE_ADD) && + !add_modeid(CHFL_INVITE, sptr, chptr, cp))|| + ((whatt & MODE_DEL) && + !del_modeid(CHFL_INVITE, chptr, cp)))) + { + *mbuf++ = c; + (void)strcat(pbuf, cp); + len += strlen(cp); + (void)strcat(pbuf, " "); + len++; + } + break; + } + } /* for (; i < opcnt; i++) */ + } /* if (opcnt) */ + + *mbuf++ = '\0'; + + return ischop ? count : -count; +} + +static int can_join(sptr, chptr, key) +aClient *sptr; +Reg aChannel *chptr; +char *key; +{ + Link *lp = NULL, *banned; + + if (chptr->users == 0 && (bootopt & BOOT_PROT) && + chptr->history != 0 && *chptr->chname != '!') + return (timeofday > chptr->history) ? 0 : ERR_UNAVAILRESOURCE; + + for (lp = sptr->user->invited; lp; lp = lp->next) + if (lp->value.chptr == chptr) + break; + + if (banned = match_modeid(CHFL_BAN, sptr, chptr)) + if (match_modeid(CHFL_EXCEPTION, sptr, chptr)) + banned = NULL; + else if (lp == NULL) + return (ERR_BANNEDFROMCHAN); + + if ((chptr->mode.mode & MODE_INVITEONLY) + && !match_modeid(CHFL_INVITE, sptr, chptr) + && (lp == NULL)) + return (ERR_INVITEONLYCHAN); + + if (*chptr->mode.key && (BadPtr(key) || mycmp(chptr->mode.key, key))) + return (ERR_BADCHANNELKEY); + + if (chptr->mode.limit && (chptr->users >= chptr->mode.limit) && + (lp == NULL)) + return (ERR_CHANNELISFULL); + + if (banned) + sendto_channel_butone(&me, &me, chptr, + ":%s NOTICE %s :%s carries an invitation (overriding ban on %s).", + ME, chptr->chname, sptr->name, + banned->value.cp); + return 0; +} + +/* +** Remove bells and commas from channel name +*/ + +void clean_channelname(cn) +Reg char *cn; +{ + for (; *cn; cn++) + if (*cn == '\007' || *cn == ' ' || *cn == ',') + { + *cn = '\0'; + return; + } +} + +/* +** Return -1 if mask is present and doesnt match our server name. +*/ +static int check_channelmask(sptr, cptr, chname) +aClient *sptr, *cptr; +char *chname; +{ + Reg char *s, *t; + + if (*chname == '&' && IsServer(cptr)) + return -1; + s = rindex(chname, ':'); + if (!s) + return 0; + if ((t = index(s, '\007'))) + *t = '\0'; + + s++; + if (match(s, ME) || (IsServer(cptr) && match(s, cptr->name))) + { + if (MyClient(sptr)) + sendto_one(sptr, err_str(ERR_BADCHANMASK, sptr->name), + chname); + if (t) + *t = '\007'; + return -1; + } + if (t) + *t = '\007'; + return 0; +} + +/* +** Get Channel block for i (and allocate a new channel +** block, if it didn't exists before). +*/ +static aChannel *get_channel(cptr, chname, flag) +aClient *cptr; +char *chname; +int flag; + { + Reg aChannel *chptr; + int len; + + if (BadPtr(chname)) + return NULL; + + len = strlen(chname); + if (MyClient(cptr) && len > CHANNELLEN) + { + len = CHANNELLEN; + *(chname+CHANNELLEN) = '\0'; + } + if ((chptr = find_channel(chname, (aChannel *)NULL))) + return (chptr); + if (flag == CREATE) + { + chptr = (aChannel *)MyMalloc(sizeof(aChannel) + len); + bzero((char *)chptr, sizeof(aChannel)); + strncpyzt(chptr->chname, chname, len+1); + if (channel) + channel->prevch = chptr; + chptr->prevch = NULL; + chptr->nextch = channel; + chptr->history = 0; + channel = chptr; + (void)add_to_channel_hash_table(chname, chptr); + } + return chptr; + } + +static void add_invite(cptr, chptr) +aClient *cptr; +aChannel *chptr; +{ + Reg Link *inv, **tmp; + + del_invite(cptr, chptr); + /* + * delete last link in chain if the list is max length + */ + if (list_length(cptr->user->invited) >= MAXCHANNELSPERUSER) + { +/* This forgets the channel side of invitation -Vesa + inv = cptr->user->invited; + cptr->user->invited = inv->next; + free_link(inv); +*/ + del_invite(cptr, cptr->user->invited->value.chptr); + } + /* + * add client to channel invite list + */ + inv = make_link(); + inv->value.cptr = cptr; + inv->next = chptr->invites; + chptr->invites = inv; + istat.is_useri++; + /* + * add channel to the end of the client invite list + */ + for (tmp = &(cptr->user->invited); *tmp; tmp = &((*tmp)->next)) + ; + inv = make_link(); + inv->value.chptr = chptr; + inv->next = NULL; + (*tmp) = inv; + istat.is_invite++; +} + +/* + * Delete Invite block from channel invite list and client invite list + */ +void del_invite(cptr, chptr) +aClient *cptr; +aChannel *chptr; +{ + Reg Link **inv, *tmp; + + for (inv = &(chptr->invites); (tmp = *inv); inv = &tmp->next) + if (tmp->value.cptr == cptr) + { + *inv = tmp->next; + free_link(tmp); + istat.is_invite--; + break; + } + + for (inv = &(cptr->user->invited); (tmp = *inv); inv = &tmp->next) + if (tmp->value.chptr == chptr) + { + *inv = tmp->next; + free_link(tmp); + istat.is_useri--; + break; + } +} + +/* +** The last user has left the channel, free data in the channel block, +** and eventually the channel block itself. +*/ +static void free_channel(chptr) +aChannel *chptr; +{ + Reg Link *tmp; + Link *obtmp; + int len = sizeof(aChannel) + strlen(chptr->chname), now = 0; + + if (chptr->history == 0 || timeofday >= chptr->history) + /* no lock, nor expired lock, channel is no more, free it */ + now = 1; + + if (*chptr->chname != '!' || now) + { + while ((tmp = chptr->invites)) + del_invite(tmp->value.cptr, chptr); + + tmp = chptr->mlist; + while (tmp) + { + obtmp = tmp; + tmp = tmp->next; + istat.is_banmem -= (strlen(obtmp->value.cp) + 1); + istat.is_bans--; + MyFree(obtmp->value.cp); + free_link(obtmp); + } + chptr->mlist = NULL; + } + + if (now) + { + istat.is_hchan--; + istat.is_hchanmem -= len; + if (chptr->prevch) + chptr->prevch->nextch = chptr->nextch; + else + channel = chptr->nextch; + if (chptr->nextch) + chptr->nextch->prevch = chptr->prevch; + del_from_channel_hash_table(chptr->chname, chptr); + + if (*chptr->chname == '!' && close_chid(chptr->chname+1)) + cache_chid(chptr); + else + MyFree((char *)chptr); + } +} + +/* +** m_join +** parv[0] = sender prefix +** parv[1] = channel +** parv[2] = channel password (key) +*/ +int m_join(cptr, sptr, parc, parv) +Reg aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + static char jbuf[BUFSIZE], cbuf[BUFSIZE]; + Reg Link *lp; + Reg aChannel *chptr; + Reg char *name, *key = NULL; + int i, flags = 0; + char *p = NULL, *p2 = NULL, *s, chop[5]; + + if (parc < 2 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "JOIN"); + return 1; + } + + *jbuf = '\0'; + *cbuf = '\0'; + /* + ** Rebuild list of channels joined to be the actual result of the + ** JOIN. Note that "JOIN 0" is the destructive problem. + ** Also note that this can easily trash the correspondance between + ** parv[1] and parv[2] lists. + */ + for (i = 0, name = strtoken(&p, parv[1], ","); name; + name = strtoken(&p, NULL, ",")) + { + if (check_channelmask(sptr, cptr, name)==-1) + continue; + if (*name == '&' && !MyConnect(sptr)) + continue; + if (*name == '0' && !atoi(name)) + { + (void)strcpy(jbuf, "0"); + continue; + } + if (*name == '!') + { + chptr = NULL; + /* + ** !channels are special: + ** !!channel is supposed to be a new channel, + ** and requires a unique name to be built. + ** ( !#channel is obsolete ) + ** !channel cannot be created, and must already + ** exist. + */ + if (*(name+1) == '\0' || + (*(name+1) == '#' && *(name+2) == '\0') || + (*(name+1) == '!' && *(name+2) == '\0')) + { + if (MyClient(sptr)) + sendto_one(sptr, + err_str(ERR_NOSUCHCHANNEL, + parv[0]), name); + continue; + } + if (*name == '!' && (*(name+1) == '#' || + *(name+1) == '!')) + { + if (!MyClient(sptr)) + { + sendto_flag(SCH_NOTICE, + "Invalid !%c channel from %s for %s", + *(name+1), + get_client_name(cptr,TRUE), + sptr->name); + continue; + } +#if 0 + /* + ** Note: creating !!!foo, e.g. !<ID>!foo is + ** a stupid thing to do because /join !!foo + ** will not join !<ID>!foo but create !<ID>foo + ** Some logic here could be reversed, but only + ** to find that !<ID>foo would be impossible to + ** create if !<ID>!foo exists. + ** which is better? it's hard to say -kalt + */ + if (*(name+3) == '!') + { + sendto_one(sptr, + err_str(ERR_NOSUCHCHANNEL, + parv[0]), name); + continue; + } +#endif + chptr = hash_find_channels(name+2, NULL); + if (chptr) + { + sendto_one(sptr, + err_str(ERR_TOOMANYTARGETS, + parv[0]), + "Duplicate", name, + "Join aborted."); + continue; + } + if (check_chid(name+2)) + { + /* + * This is a bit wrong: if a channel + * rightfully ceases to exist, it + * can still be *locked* for up to + * 2*CHIDNB^3 seconds (~24h) + * Is it a reasonnable price to pay to + * ensure shortname uniqueness? -kalt + */ + sendto_one(sptr, + err_str(ERR_UNAVAILRESOURCE, + parv[0]), name); + continue; + } + sprintf(buf, "!%.*s%s", CHIDLEN, get_chid(), + name+2); + name = buf; + } + else if (!find_channel(name, NullChn) && + !(*name == '!' && *name != 0 && + (chptr = hash_find_channels(name+1, NULL)))) + { + if (MyClient(sptr)) + sendto_one(sptr, + err_str(ERR_NOSUCHCHANNEL, + parv[0]), name); + if (!IsServer(cptr)) + continue; + /* from a server, it is legitimate */ + } + else if (chptr) + { + /* joining a !channel using the short name */ + if (MyConnect(sptr) && + hash_find_channels(name+1, chptr)) + { + sendto_one(sptr, + err_str(ERR_TOOMANYTARGETS, + parv[0]), + "Duplicate", name, + "Join aborted."); + continue; + } + name = chptr->chname; + } + } + if (!IsChannelName(name) || + (*name == '!' && IsChannelName(name+1))) + { + if (MyClient(sptr)) + sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL, + parv[0]), name); + continue; + } + if (*jbuf) + (void)strcat(jbuf, ","); + (void)strncat(jbuf, name, sizeof(jbuf) - i - 1); + i += strlen(name)+1; + } + + p = NULL; + if (parv[2]) + key = strtoken(&p2, parv[2], ","); + parv[2] = NULL; /* for m_names call later, parv[parc] must == NULL */ + for (name = strtoken(&p, jbuf, ","); name; + key = (key) ? strtoken(&p2, NULL, ",") : NULL, + name = strtoken(&p, NULL, ",")) + { + /* + ** JOIN 0 sends out a part for all channels a user + ** has joined. + */ + if (*name == '0' && !atoi(name)) + { + if (sptr->user->channel == NULL) + continue; + while ((lp = sptr->user->channel)) + { + chptr = lp->value.chptr; + sendto_channel_butserv(chptr, sptr, + PartFmt, + parv[0], chptr->chname, + IsAnonymous(chptr) ? "None" : + (key ? key : parv[0])); + remove_user_from_channel(sptr, chptr); + } + sendto_match_servs(NULL, cptr, ":%s JOIN 0 :%s", + parv[0], key ? key : parv[0]); + continue; + } + + if (cptr->serv && (s = index(name, '\007'))) + *s++ = '\0'; + else + clean_channelname(name), s = NULL; + + if (MyConnect(sptr) && + sptr->user->joined >= MAXCHANNELSPERUSER) { + /* Feature: Cannot join &flagchannels either + if already joined MAXCHANNELSPERUSER times. */ + sendto_one(sptr, err_str(ERR_TOOMANYCHANNELS, + parv[0]), name); + /* can't return, need to send the info everywhere */ + continue; + } + + chptr = get_channel(sptr, name, CREATE); + + if (IsMember(sptr, chptr)) + continue; + if (!chptr || + (MyConnect(sptr) && (i = can_join(sptr, chptr, key)))) + { + sendto_one(sptr, err_str(i, parv[0]), name); + continue; + } + + /* + ** local client is first to enter previously nonexistant + ** channel so make them (rightfully) the Channel + ** Operator. + */ + flags = 0; + chop[0] = '\0'; + if (MyConnect(sptr) && UseModes(name) && + (!IsRestricted(sptr) || (*name == '&')) && !chptr->users && + !(chptr->history && *chptr->chname == '!')) + { + if (*name == '!') + strcpy(chop, "\007O"); + else + strcpy(chop, "\007o"); + s = chop+1; /* tricky */ + } + /* + ** Complete user entry to the new channel (if any) + */ + if (s && UseModes(name)) + { + if (*s == 'O') + /* + * there can never be another mode here, + * because we use NJOIN for netjoins. + * here, it *must* be a channel creation. -kalt + */ + flags |= CHFL_UNIQOP|CHFL_CHANOP; + else if (*s == 'o') + { + flags |= CHFL_CHANOP; + if (*(s+1) == 'v') + flags |= CHFL_VOICE; + } + else if (*s == 'v') + flags |= CHFL_VOICE; + } + add_user_to_channel(chptr, sptr, flags); + /* + ** notify all users on the channel + */ + sendto_channel_butserv(chptr, sptr, ":%s JOIN :%s", + parv[0], name); + if (s && UseModes(name)) + { + /* no need if user is creating the channel */ + if (chptr->users != 1) + sendto_channel_butserv(chptr, sptr, + ":%s MODE %s +%s %s %s", + cptr->name, name, s, + parv[0], + *(s+1)=='v'?parv[0]:""); + *--s = '\007'; + } + /* + ** If s wasn't set to chop+1 above, name is now #chname^Gov + ** again (if coming from a server, and user is +o and/or +v + ** of course ;-) + ** This explains the weird use of name and chop.. + ** Is this insane or subtle? -krys + */ + if (MyClient(sptr)) + { + del_invite(sptr, chptr); + if (chptr->topic[0] != '\0') + sendto_one(sptr, rpl_str(RPL_TOPIC, parv[0]), + name, chptr->topic); + parv[1] = name; + (void)m_names(cptr, sptr, 2, parv); + if (IsAnonymous(chptr) && !IsQuiet(chptr)) + { + sendto_one(sptr, ":%s NOTICE %s :Channel %s has the anonymous flag set.", ME, chptr->chname, chptr->chname); + sendto_one(sptr, ":%s NOTICE %s :Be aware that anonymity on IRC is NOT securely enforced!", ME, chptr->chname); + } + } + /* + ** notify other servers + */ + if (index(name, ':') || *chptr->chname == '!') /* compat */ + sendto_match_servs(chptr, cptr, ":%s JOIN :%s%s", + parv[0], name, chop); + else if (*chptr->chname != '&') + { + if (*cbuf) + strcat(cbuf, ","); + strcat(cbuf, name); + if (chop) + strcat(cbuf, chop); + } + } + if (*cbuf) + sendto_serv_butone(cptr, ":%s JOIN :%s", parv[0], cbuf); + return 2; +} + +/* +** m_njoin +** parv[0] = sender prefix +** parv[1] = channel +** parv[2] = channel members and modes +*/ +int m_njoin(cptr, sptr, parc, parv) +Reg aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + char nbuf[BUFSIZE], *q, *name, *target, *p, mbuf[4]; + int chop, cnt = 0, nj = 0; + aChannel *chptr = NULL; + aClient *acptr; + + if (parc < 3 || *parv[2] == '\0') + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]),"NJOIN"); + return 1; + } + *nbuf = '\0'; q = nbuf; + for (target = strtoken(&p, parv[2], ","); target; + target = strtoken(&p, NULL, ",")) + { + /* check for modes */ + chop = 0; + mbuf[0] = '\0'; + if (*target == '@') + { + if (*(target+1) == '@') + { + /* actually never sends in a JOIN ^G */ + if (*(target+2) == '+') + { + strcpy(mbuf, "\007Ov"); + chop = CHFL_UNIQOP|CHFL_CHANOP| \ + CHFL_VOICE; + name = target + 3; + } + else + { + strcpy(mbuf, "\007O"); + chop = CHFL_UNIQOP|CHFL_CHANOP; + name = target + 2; + } + } + else + { + if (*(target+1) == '+') + { + strcpy(mbuf, "\007ov"); + chop = CHFL_CHANOP|CHFL_VOICE; + name = target+2; + } + else + { + strcpy(mbuf, "\007o"); + chop = CHFL_CHANOP; + name = target+1; + } + } + } + else if (*target == '+') + { + strcpy(mbuf, "\007v"); + chop = CHFL_VOICE; + name = target+1; + } + else + name = target; + /* find user */ + if (!(acptr = find_person(name, (aClient *)NULL))) + continue; + /* is user who we think? */ + if (acptr->from != cptr) + continue; + /* get channel pointer */ + if (!chptr) + { + if (check_channelmask(sptr, cptr, parv[1]) == -1) + { + sendto_flag(SCH_DEBUG, + "received NJOIN for %s from %s", + parv[1], + get_client_name(cptr, TRUE)); + return 0; + } + chptr = get_channel(acptr, parv[1], CREATE); + if (!IsChannelName(parv[1]) || chptr == NULL) + { + sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL, + parv[0]), parv[1]); + return 0; + } + } + /* make sure user isn't already on channel */ + if (IsMember(acptr, chptr)) + { + sendto_flag(SCH_ERROR, "NJOIN protocol error from %s", + get_client_name(cptr, TRUE)); + sendto_one(cptr, "ERROR :NJOIN protocol error"); + continue; + } + /* add user to channel */ + add_user_to_channel(chptr, acptr, UseModes(parv[1]) ? chop :0); + /* build buffer for NJOIN capable servers */ + if (q != nbuf) + *q++ = ','; + while (*target) + *q++ = *target++; + /* send 2.9 style join to other servers */ + if (*chptr->chname != '!') + nj = sendto_match_servs_notv(chptr, cptr, SV_NJOIN, + ":%s JOIN %s%s", name, + parv[1], + UseModes(parv[1]) ? mbuf : + ""); + /* send join to local users on channel */ + sendto_channel_butserv(chptr, acptr, ":%s JOIN %s", name, + parv[1]); + /* build MODE for local users on channel, eventually send it */ + if (*mbuf) + { + if (!UseModes(parv[1])) + { + sendto_one(cptr, err_str(ERR_NOCHANMODES, + parv[0]), parv[1]); + continue; + } + switch (cnt) + { + case 0: + *parabuf = '\0'; *modebuf = '\0'; + /* fall through */ + case 1: + strcat(modebuf, mbuf+1); + cnt += strlen(mbuf+1); + if (*parabuf) + { + strcat(parabuf, " "); + } + strcat(parabuf, name); + if (mbuf[2]) + { + strcat(parabuf, " "); + strcat(parabuf, name); + } + break; + case 2: + sendto_channel_butserv(chptr, &me, + ":%s MODE %s +%s%c %s %s", + sptr->name, parv[1], + modebuf, mbuf[1], + parabuf, name); + if (mbuf[2]) + { + strcpy(modebuf, mbuf+2); + strcpy(parabuf, name); + cnt = 1; + } + else + cnt = 0; + break; + } + if (cnt == 3) + { + sendto_channel_butserv(chptr, &me, + ":%s MODE %s +%s %s", + sptr->name, parv[1], + modebuf, parabuf); + cnt = 0; + } + } + } + /* send eventual MODE leftover */ + if (cnt) + sendto_channel_butserv(chptr, &me, ":%s MODE %s +%s %s", + sptr->name, parv[1], modebuf, parabuf); + + /* send NJOIN to capable servers */ + *q = '\0'; + if (nbuf[0]) + sendto_match_servs_v(chptr, cptr, SV_NJOIN, ":%s NJOIN %s :%s", + parv[0], parv[1], nbuf); + return 0; +} + +/* +** m_part +** parv[0] = sender prefix +** parv[1] = channel +*/ +int m_part(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + Reg aChannel *chptr; + char *p = NULL, *name, *comment = ""; + + if (parc < 2 || parv[1][0] == '\0') + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "PART"); + return 1; + } + + *buf = '\0'; + + for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL) + { + chptr = get_channel(sptr, name, 0); + if (!chptr) + { + if (MyPerson(sptr)) + sendto_one(sptr, + err_str(ERR_NOSUCHCHANNEL, parv[0]), + name); + continue; + } + if (check_channelmask(sptr, cptr, name)) + continue; + if (!IsMember(sptr, chptr)) + { + sendto_one(sptr, err_str(ERR_NOTONCHANNEL, parv[0]), + name); + continue; + } + comment = (BadPtr(parv[2])) ? parv[0] : parv[2]; + if (IsAnonymous(chptr) && (comment == parv[0])) + comment = "None"; + if (strlen(comment) > (size_t) TOPICLEN) + comment[TOPICLEN] = '\0'; + + /* + ** Remove user from the old channel (if any) + */ + if (!index(name, ':') && (*chptr->chname != '!')) + { /* channel:*.mask */ + if (*name != '&') + { + if (*buf) + (void)strcat(buf, ","); + (void)strcat(buf, name); + } + } + else + sendto_match_servs(chptr, cptr, PartFmt, + parv[0], name, comment); + sendto_channel_butserv(chptr, sptr, PartFmt, + parv[0], name, comment); + remove_user_from_channel(sptr, chptr); + } + if (*buf) + sendto_serv_butone(cptr, PartFmt, parv[0], buf, comment); + return 4; + } + +/* +** m_kick +** parv[0] = sender prefix +** parv[1] = channel +** parv[2] = client to kick +** parv[3] = kick comment +*/ +int m_kick(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + aClient *who; + aChannel *chptr; + int chasing = 0, penalty = 0; + char *comment, *name, *p = NULL, *user, *p2 = NULL; + int mlen, len = 0, nlen; + + if (parc < 3 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "KICK"); + return 1; + } + if (IsServer(sptr)) + sendto_flag(SCH_NOTICE, "KICK from %s for %s %s", + parv[0], parv[1], parv[2]); + comment = (BadPtr(parv[3])) ? parv[0] : parv[3]; + if (strlen(comment) > (size_t) TOPICLEN) + comment[TOPICLEN] = '\0'; + + *nickbuf = *buf = '\0'; + mlen = 7 + strlen(parv[0]); + + for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL) + { + if (penalty++ >= MAXPENALTY && MyPerson(sptr)) + break; + chptr = get_channel(sptr, name, !CREATE); + if (!chptr) + { + if (MyPerson(sptr)) + sendto_one(sptr, + err_str(ERR_NOSUCHCHANNEL, parv[0]), + name); + continue; + } + if (check_channelmask(sptr, cptr, name)) + continue; + if (!UseModes(name)) + { + sendto_one(sptr, err_str(ERR_NOCHANMODES, parv[0]), + name); + continue; + } + if (!IsServer(sptr) && !is_chan_op(sptr, chptr)) + { + if (!IsMember(sptr, chptr)) + sendto_one(sptr, err_str(ERR_NOTONCHANNEL, + parv[0]), chptr->chname); + else + sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED, + parv[0]), chptr->chname); + continue; + } + if (len + mlen + strlen(name) < (size_t) BUFSIZE / 2) + { + if (*buf) + (void)strcat(buf, ","); + (void)strcat(buf, name); + len += strlen(name) + 1; + } + else + continue; + nlen = 0; + + for (; (user = strtoken(&p2, parv[2], ",")); parv[2] = NULL) + { + penalty++; + if (!(who = find_chasing(sptr, user, &chasing))) + continue; /* No such user left! */ + if (nlen + mlen + strlen(who->name) > + (size_t) BUFSIZE - NICKLEN) + continue; + if (IsMember(who, chptr)) + { + sendto_channel_butserv(chptr, sptr, + ":%s KICK %s %s :%s", parv[0], + name, who->name, comment); + /* Don't send &local &kicks out */ + if (*chptr->chname != '&' && + *chptr->chname != '!' && + index(chptr->chname, ':') == NULL) { + if (*nickbuf) + (void)strcat(nickbuf, ","); + (void)strcat(nickbuf, who->name); + nlen += strlen(who->name); + } + else + sendto_match_servs(chptr, cptr, + ":%s KICK %s %s :%s", + parv[0], name, + who->name, comment); + remove_user_from_channel(who,chptr); + penalty += 2; + if (penalty > MAXPENALTY && MyPerson(sptr)) + break; + } + else + sendto_one(sptr, + err_str(ERR_USERNOTINCHANNEL, + parv[0]), user, name); + } /* loop on parv[2] */ + } /* loop on parv[1] */ + + if (*buf && *nickbuf) + sendto_serv_butone(cptr, ":%s KICK %s %s :%s", + parv[0], buf, nickbuf, comment); + return penalty; +} + +int count_channels(sptr) +aClient *sptr; +{ +Reg aChannel *chptr; + Reg int count = 0; + + for (chptr = channel; chptr; chptr = chptr->nextch) + { + if (chptr->users) /* don't count channels in history */ +#ifdef SHOW_INVISIBLE_LUSERS + if (SecretChannel(chptr)) + { + if (IsAnOper(sptr)) + count++; + } + else +#endif + count++; + } + return (count); +} + +/* +** m_topic +** parv[0] = sender prefix +** parv[1] = topic text +*/ +int m_topic(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + aChannel *chptr = NullChn; + char *topic = NULL, *name, *p = NULL; + int penalty = 1; + + if (parc < 2) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), + "TOPIC"); + return 1; + } + + parv[1] = canonize(parv[1]); + + for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL) + { + if (!UseModes(name)) + { + sendto_one(sptr, err_str(ERR_NOCHANMODES, parv[0]), + name); + continue; + } + if (parc > 1 && IsChannelName(name)) + { + chptr = find_channel(name, NullChn); + if (!chptr || !IsMember(sptr, chptr)) + { + sendto_one(sptr, err_str(ERR_NOTONCHANNEL, + parv[0]), name); + continue; + } + if (parc > 2) + topic = parv[2]; + } + + if (!chptr) + { + sendto_one(sptr, rpl_str(RPL_NOTOPIC, parv[0]), name); + return penalty; + } + + if (check_channelmask(sptr, cptr, name)) + continue; + + if (!topic) /* only asking for topic */ + { + if (chptr->topic[0] == '\0') + sendto_one(sptr, rpl_str(RPL_NOTOPIC, parv[0]), + chptr->chname); + else + sendto_one(sptr, rpl_str(RPL_TOPIC, parv[0]), + chptr->chname, chptr->topic); + } + else if ((chptr->mode.mode & MODE_TOPICLIMIT) == 0 || + is_chan_op(sptr, chptr)) + { /* setting a topic */ + strncpyzt(chptr->topic, topic, sizeof(chptr->topic)); + sendto_match_servs(chptr, cptr,":%s TOPIC %s :%s", + parv[0], chptr->chname, + chptr->topic); + sendto_channel_butserv(chptr, sptr, ":%s TOPIC %s :%s", + parv[0], + chptr->chname, chptr->topic); +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_TOPIC, + NULL, sptr, ":%s TOPIC %s :%s", + parv[0], chptr->chname, + chptr->topic); +#endif + penalty += 2; + } + else + sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED, parv[0]), + chptr->chname); + } + return penalty; + } + +/* +** m_invite +** parv[0] - sender prefix +** parv[1] - user to invite +** parv[2] - channel number +*/ +int m_invite(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + aClient *acptr; + aChannel *chptr; + + if (parc < 3 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), + "INVITE"); + return 1; + } + + if (!(acptr = find_person(parv[1], (aClient *)NULL))) + { + sendto_one(sptr, err_str(ERR_NOSUCHNICK, parv[0]), parv[1]); + return 1; + } + clean_channelname(parv[2]); + if (check_channelmask(sptr, acptr->user->servp->bcptr, parv[2])) + return 1; + if (*parv[2] == '&' && !MyClient(acptr)) + return 1; + chptr = find_channel(parv[2], NullChn); + + if (!chptr) + { + sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s", + parv[0], parv[1], parv[2]); + if (MyConnect(sptr)) + { + sendto_one(sptr, rpl_str(RPL_INVITING, parv[0]), + acptr->name, parv[2]); + if (acptr->user->flags & FLAGS_AWAY) + sendto_one(sptr, rpl_str(RPL_AWAY, parv[0]), + acptr->name, (acptr->user->away) ? + acptr->user->away : "Gone"); + } + return 3; + } + + if (!IsMember(sptr, chptr)) + { + sendto_one(sptr, err_str(ERR_NOTONCHANNEL, parv[0]), parv[2]); + return 1; + } + + if (IsMember(acptr, chptr)) + { + sendto_one(sptr, err_str(ERR_USERONCHANNEL, parv[0]), + parv[1], parv[2]); + return 1; + } + + if ((chptr->mode.mode & MODE_INVITEONLY) && !is_chan_op(sptr, chptr)) + { + sendto_one(sptr, err_str(ERR_CHANOPRIVSNEEDED, + parv[0]), chptr->chname); + return 1; + } + + if (MyConnect(sptr)) + { + sendto_one(sptr, rpl_str(RPL_INVITING, parv[0]), + acptr->name, ((chptr) ? (chptr->chname) : parv[2])); + if (acptr->user->flags & FLAGS_AWAY) + sendto_one(sptr, rpl_str(RPL_AWAY, parv[0]), + acptr->name, + (acptr->user->away) ? acptr->user->away : + "Gone"); + } + + if (MyConnect(acptr)) + if (chptr && /* (chptr->mode.mode & MODE_INVITEONLY) && */ + sptr->user && is_chan_op(sptr, chptr)) + add_invite(acptr, chptr); + + sendto_prefix_one(acptr, sptr, ":%s INVITE %s :%s",parv[0], + acptr->name, ((chptr) ? (chptr->chname) : parv[2])); + return 2; +} + + +/* +** m_list +** parv[0] = sender prefix +** parv[1] = channel +*/ +int m_list(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + aChannel *chptr; + char *name, *p = NULL; + int rlen = 0; + + if (parc > 1 && + hunt_server(cptr, sptr, ":%s LIST %s %s", 2, parc, parv)) + return 10; + if (BadPtr(parv[1])) + for (chptr = channel; chptr; chptr = chptr->nextch) + { + if (!sptr->user || + !chptr->users || /* empty locked channel */ + (SecretChannel(chptr) && !IsMember(sptr, chptr))) + continue; + name = ShowChannel(sptr, chptr) ? chptr->chname : NULL; + rlen += sendto_one(sptr, rpl_str(RPL_LIST, parv[0]), + name ? name : "*", chptr->users, + name ? chptr->topic : ""); + if (!MyConnect(sptr) && rlen > CHREPLLEN) + break; + } + else { + parv[1] = canonize(parv[1]); + for (; (name = strtoken(&p, parv[1], ",")); parv[1] = NULL) + { + chptr = find_channel(name, NullChn); + if (chptr && ShowChannel(sptr, chptr) && sptr->user) + { + rlen += sendto_one(sptr, rpl_str(RPL_LIST, + parv[0]), name, + chptr->users, chptr->topic); + if (!MyConnect(sptr) && rlen > CHREPLLEN) + break; + } + if (*name == '!') + { + chptr = NULL; + while (chptr=hash_find_channels(name+1, chptr)) + { + int scr = SecretChannel(chptr) && + !IsMember(sptr, chptr); + rlen += sendto_one(sptr, + rpl_str(RPL_LIST, + parv[0]), + chptr->chname, + (scr) ? -1 : + chptr->users, + (scr) ? "" : + chptr->topic); + if (!MyConnect(sptr) && + rlen > CHREPLLEN) + break; + } + } + } + } + if (!MyConnect(sptr) && rlen > CHREPLLEN) + sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]), + !BadPtr(parv[1]) ? parv[1] : "*"); + sendto_one(sptr, rpl_str(RPL_LISTEND, parv[0])); + return 2; + } + + +/************************************************************************ + * m_names() - Added by Jto 27 Apr 1989 + ************************************************************************/ + +/* +** m_names +** parv[0] = sender prefix +** parv[1] = channel +*/ +int m_names(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aChannel *chptr; + Reg aClient *c2ptr; + Reg Link *lp; + aChannel *ch2ptr = NULL; + int idx, flag, len, mlen, rlen = 0; + char *s, *para = parc > 1 ? parv[1] : NULL; + + if (parc > 1 && + hunt_server(cptr, sptr, ":%s NAMES %s %s", 2, parc, parv)) + return 10; + + mlen = strlen(ME) + 10; /* server names + : : + spaces + "353" */ + mlen += strlen(parv[0]); + if (!BadPtr(para)) + { + s = index(para, ','); + if (s && MyConnect(sptr) && s != para) + { + parv[1] = ++s; + (void)m_names(cptr, sptr, parc, parv); + } + clean_channelname(para); + ch2ptr = find_channel(para, (aChannel *)NULL); + } + + *buf = '\0'; + + /* + * First, do all visible channels (public and the one user self is) + */ + + for (chptr = channel; chptr; chptr = chptr->nextch) + { + if (!chptr->users || /* locked empty channel */ + ((chptr != ch2ptr) && !BadPtr(para))) /* 'wrong' channel */ + continue; + if (!MyConnect(sptr) && (BadPtr(para) || (rlen > CHREPLLEN))) + break; + if ((BadPtr(para) || !HiddenChannel(chptr)) && + !ShowChannel(sptr, chptr)) + continue; /* -- users on this are not listed */ + + /* Find users on same channel (defined by chptr) */ + + (void)strcpy(buf, "* "); + len = strlen(chptr->chname); + (void)strcpy(buf + 2, chptr->chname); + (void)strcpy(buf + 2 + len, " :"); + + if (PubChannel(chptr)) + *buf = '='; + else if (SecretChannel(chptr)) + *buf = '@'; + + if (IsAnonymous(chptr)) + { + if ((lp = find_user_link(chptr->members, sptr))) + { + if (lp->flags & CHFL_CHANOP) + (void)strcat(buf, "@"); + else if (lp->flags & CHFL_VOICE) + (void)strcat(buf, "+"); + (void)strcat(buf, parv[0]); + } + rlen += strlen(buf); + sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf); + continue; + } + idx = len + 4; /* channel name + [@=] + 2?? */ + flag = 1; + for (lp = chptr->members; lp; lp = lp->next) + { + c2ptr = lp->value.cptr; + if (IsInvisible(c2ptr) && !IsMember(sptr,chptr)) + continue; + if (lp->flags & CHFL_CHANOP) + { + (void)strcat(buf, "@"); + idx++; + } + else if (lp->flags & CHFL_VOICE) + { + (void)strcat(buf, "+"); + idx++; + } + (void)strncat(buf, c2ptr->name, NICKLEN); + idx += strlen(c2ptr->name) + 1; + flag = 1; + (void)strcat(buf," "); + if (mlen + idx + NICKLEN + 1 > BUFSIZE - 2) + { + sendto_one(sptr, rpl_str(RPL_NAMREPLY, + parv[0]), buf); + (void)strncpy(buf, "* ", 3); + (void)strncpy(buf+2, chptr->chname, + len + 1); + (void)strcat(buf, " :"); + if (PubChannel(chptr)) + *buf = '='; + else if (SecretChannel(chptr)) + *buf = '@'; + idx = len + 4; + flag = 0; + } + } + if (flag) + { + rlen += strlen(buf); + sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf); + } + } /* for(channels) */ + if (!BadPtr(para)) + { + if (!MyConnect(sptr) && (rlen > CHREPLLEN)) + sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]), + para); + sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), para); + return(1); + } + + /* Second, do all non-public, non-secret channels in one big sweep */ + + (void)strncpy(buf, "* * :", 6); + idx = 5; + flag = 0; + for (c2ptr = client; c2ptr; c2ptr = c2ptr->next) + { + aChannel *ch3ptr; + int showflag = 0, secret = 0; + + if (!IsPerson(c2ptr) || IsInvisible(c2ptr)) + continue; + if (!MyConnect(sptr) && (BadPtr(para) || (rlen > CHREPLLEN))) + break; + lp = c2ptr->user->channel; + /* + * don't show a client if they are on a secret channel or + * they are on a channel sptr is on since they have already + * been show earlier. -avalon + */ + while (lp) + { + ch3ptr = lp->value.chptr; + if (PubChannel(ch3ptr) || IsMember(sptr, ch3ptr)) + showflag = 1; + if (SecretChannel(ch3ptr)) + secret = 1; + lp = lp->next; + } + if (showflag) /* have we already shown them ? */ + continue; + if (secret) /* on any secret channels ? */ + continue; + (void)strncat(buf, c2ptr->name, NICKLEN); + idx += strlen(c2ptr->name) + 1; + (void)strcat(buf," "); + flag = 1; + if (mlen + idx + NICKLEN > BUFSIZE - 2) + { + rlen += strlen(buf); + sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf); + (void)strncpy(buf, "* * :", 6); + idx = 5; + flag = 0; + } + } + if (flag) + { + rlen += strlen(buf); + sendto_one(sptr, rpl_str(RPL_NAMREPLY, parv[0]), buf); + } + if (!MyConnect(sptr) && rlen > CHREPLLEN) + sendto_one(sptr, err_str(ERR_TOOMANYMATCHES, parv[0]), + para ? para : "*"); + /* This is broken.. remove the recursion? */ + sendto_one(sptr, rpl_str(RPL_ENDOFNAMES, parv[0]), "*"); + return 2; +} + +void send_user_joins(cptr, user) +aClient *cptr, *user; +{ + Reg Link *lp; + Reg aChannel *chptr; + Reg int cnt = 0, len = 0, clen; + char *mask; + + *buf = ':'; + (void)strcpy(buf+1, user->name); + (void)strcat(buf, " JOIN "); + len = strlen(user->name) + 7; + + for (lp = user->user->channel; lp; lp = lp->next) + { + chptr = lp->value.chptr; + if (*chptr->chname == '&') + continue; + if (*chptr->chname == '!' && !(cptr->serv->version & SV_NCHAN)) + /* in reality, testing SV_NCHAN here is pointless */ + continue; + if ((mask = index(chptr->chname, ':'))) + if (match(++mask, cptr->name)) + continue; + clen = strlen(chptr->chname); + if ((clen + len) > (size_t) BUFSIZE - 7) + { + if (cnt) + sendto_one(cptr, "%s", buf); + *buf = ':'; + (void)strcpy(buf+1, user->name); + (void)strcat(buf, " JOIN "); + len = strlen(user->name) + 7; + cnt = 0; + } + if (cnt) + { + len++; + (void)strcat(buf, ","); + } + (void)strcpy(buf + len, chptr->chname); + len += clen; + if (lp->flags & (CHFL_UNIQOP|CHFL_CHANOP|CHFL_VOICE)) + { + buf[len++] = '\007'; + if (lp->flags & CHFL_UNIQOP) /*this should be useless*/ + buf[len++] = 'O'; + if (lp->flags & CHFL_CHANOP) + buf[len++] = 'o'; + if (lp->flags & CHFL_VOICE) + buf[len++] = 'v'; + buf[len] = '\0'; + } + cnt++; + } + if (*buf && cnt) + sendto_one(cptr, "%s", buf); + + return; +} + +#define CHECKFREQ 300 +/* consider reoping an opless !channel */ +static int +reop_channel(now, chptr) +time_t now; +aChannel *chptr; +{ + Link *lp, op; + + op.value.chptr = NULL; + if (chptr->users <= 5 && (now - chptr->history > DELAYCHASETIMELIMIT)) + { + /* few users, no recent split: this is really a small channel */ + char mbuf[4], nbuf[3*(NICKLEN+1)+1]; + int cnt; + + lp = chptr->members; + while (lp) + { + if (lp->flags & CHFL_CHANOP) + { + chptr->reop = 0; + return 0; + } + if (MyConnect(lp->value.cptr)) + op.value.cptr = lp->value.cptr; + lp = lp->next; + } + if (op.value.cptr == NULL && + ((now - chptr->reop) < LDELAYCHASETIMELIMIT)) + /* + ** do nothing if no local users, + ** unless the reop is really overdue. + */ + return 0; + sendto_channel_butone(&me, &me, chptr, + ":%s NOTICE %s :Enforcing channel mode +r (%d)", + ME, chptr->chname, now - chptr->reop); + op.flags = MODE_ADD|MODE_CHANOP; + lp = chptr->members; + cnt = 3; + while (lp) + { + if (cnt == 3) + { + mbuf[cnt] = '\0'; + if (lp != chptr->members) + { + sendto_match_servs_v(chptr, NULL, SV_NCHAN, + ":%s MODE %s +%s %s", + ME, chptr->chname, + mbuf, nbuf); + sendto_channel_butserv(chptr, &me, + ":%s MODE %s +%s %s", + ME, chptr->chname, + mbuf, nbuf); + } + cnt = 0; + mbuf[0] = nbuf[0] = '\0'; + } + op.value.cptr = lp->value.cptr; + change_chan_flag(&op, chptr); + mbuf[cnt++] = 'o'; + strcat(nbuf, lp->value.cptr->name); + strcat(nbuf, " "); + lp = lp->next; + } + if (cnt) + { + mbuf[cnt] = '\0'; + sendto_match_servs_v(chptr, NULL, SV_NCHAN, + ":%s MODE %s +%s %s", + ME, chptr->chname, mbuf, nbuf); + sendto_channel_butserv(chptr, &me, ":%s MODE %s +%s %s", + ME, chptr->chname, mbuf, nbuf); + } + } + else + { + time_t idlelimit = now - + MIN((LDELAYCHASETIMELIMIT/2), (2*CHECKFREQ)); + + lp = chptr->members; + while (lp) + { + if (lp->flags & CHFL_CHANOP) + { + chptr->reop = 0; + return 0; + } + if (MyConnect(lp->value.cptr) && + lp->value.cptr->user->last > idlelimit && + (op.value.cptr == NULL || + lp->value.cptr->user->last>op.value.cptr->user->last)) + op.value.cptr = lp->value.cptr; + lp = lp->next; + } + if (op.value.cptr == NULL) + return 0; + sendto_channel_butone(&me, &me, chptr, + ":%s NOTICE %s :Enforcing channel mode +r (%d)", ME, + chptr->chname, now - chptr->reop); + op.flags = MODE_ADD|MODE_CHANOP; + change_chan_flag(&op, chptr); + sendto_match_servs_v(chptr, NULL, SV_NCHAN, ":%s MODE %s +o %s", + ME, chptr->chname, op.value.cptr->name); + sendto_channel_butserv(chptr, &me, ":%s MODE %s +o %s", + ME, chptr->chname, op.value.cptr->name); + } + chptr->reop = 0; + return 1; +} + +/* + * Cleanup locked channels, run frequently. + * + * A channel life is defined by its users and the history stamp. + * It is alive if one of the following is true: + * chptr->users > 0 (normal state) + * chptr->history >= time(NULL) (eventually locked) + * It is locked if empty but alive. + * + * The history stamp is set when a remote user with channel op exits. + */ +time_t collect_channel_garbage(now) +time_t now; +{ + static u_int max_nb = 0; /* maximum of live channels */ + static u_char split = 0; + Reg aChannel *chptr = channel; + Reg u_int cur_nb = 1, curh_nb = 0, r_cnt = 0; + aChannel *del_ch; +#ifdef DEBUGMODE + u_int del = istat.is_hchan; +#endif +#define SPLITBONUS (CHECKFREQ - 50) + + collect_chid(); + + while (chptr) + { + if (chptr->users == 0) + curh_nb++; + else + { + cur_nb++; + if (*chptr->chname == '!' && + (chptr->mode.mode & MODE_REOP) && + chptr->reop && chptr->reop <= now) + r_cnt += reop_channel(now, chptr); + } + chptr = chptr->nextch; + } + if (cur_nb > max_nb) + max_nb = cur_nb; + + if (r_cnt) + sendto_flag(SCH_CHAN, "Re-opped %u channel(s).", r_cnt); + + /* + ** check for huge netsplits, if so, garbage collection is not really + ** done but make sure there aren't too many channels kept for + ** history - krys + */ + if ((2*curh_nb > cur_nb) && curh_nb < max_nb) + split = 1; + else + { + split = 0; + /* no empty channel? let's skip the while! */ + if (curh_nb == 0) + { +#ifdef DEBUGMODE + sendto_flag(SCH_LOCAL, + "Channel garbage: live %u (max %u), hist %u (extended)", + cur_nb - 1, max_nb - 1, curh_nb); +#endif + /* Check again after CHECKFREQ seconds */ + return (time_t) (now + CHECKFREQ); + } + } + + chptr = channel; + while (chptr) + { + /* + ** In case we are likely to be split, extend channel locking. + ** most splits should be short, but reality seems to prove some + ** aren't. + */ + if (!chptr->history) + { + chptr = chptr->nextch; + continue; + } + if (split) /* net splitted recently and we have a lock */ + chptr->history += SPLITBONUS; /* extend lock */ + + if ((chptr->users == 0) && (chptr->history <= now)) + { + del_ch = chptr; + + chptr = del_ch->nextch; + free_channel(del_ch); + } + else + chptr = chptr->nextch; + } + +#ifdef DEBUGMODE + sendto_flag(SCH_LOCAL, + "Channel garbage: live %u (max %u), hist %u (removed %u)%s", + cur_nb - 1, max_nb - 1, curh_nb, del - istat.is_hchan, + (split) ? " split detected" : ""); +#endif + /* Check again after CHECKFREQ seconds */ + return (time_t) (now + CHECKFREQ); +} diff --git a/ircd/channel_def.h b/ircd/channel_def.h new file mode 100644 index 0000000..7413f16 --- /dev/null +++ b/ircd/channel_def.h @@ -0,0 +1,29 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/channel_def.h + * 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. + */ + +#define CREATE 1 /* whether a channel should be + created or just tested for existance */ + +#define MODEBUFLEN 200 + +#define NullChn ((aChannel *)0) + +#define ChannelExists(n) (find_channel(n, NullChn) != NullChn) + +#define MAXMODEPARAMS 3 diff --git a/ircd/channel_ext.h b/ircd/channel_ext.h new file mode 100644 index 0000000..361d387 --- /dev/null +++ b/ircd/channel_ext.h @@ -0,0 +1,64 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/channel_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/channel.c. + */ + +/* External definitions for global variables. + */ +#ifndef CHANNEL_C +extern aChannel *channel; +#endif /* CHANNEL_C */ + +/* External definitions for global functions. + */ +#ifndef CHANNEL_C +#define EXTERN extern +#else /* CHANNEL_C */ +#define EXTERN +#endif /* CHANNEL_C */ +EXTERN void remove_user_from_channel __P((aClient *sptr, aChannel *chptr)); +EXTERN int is_chan_op __P((aClient *cptr, aChannel *chptr)); +EXTERN int has_voice __P((aClient *cptr, aChannel *chptr)); +EXTERN int can_send __P((aClient *cptr, aChannel *chptr)); +EXTERN aChannel *find_channel __P((Reg char *chname, Reg aChannel *chptr)); +EXTERN void setup_server_channels __P((aClient *mp)); +EXTERN void channel_modes __P((aClient *cptr, Reg char *mbuf, Reg char *pbuf, + aChannel *chptr)); +EXTERN void send_channel_modes __P((aClient *cptr, aChannel *chptr)); +EXTERN void send_channel_members __P((aClient *cptr, aChannel *chptr)); +EXTERN int m_mode __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN void clean_channelname __P((Reg char *cn)); +EXTERN void del_invite __P((aClient *cptr, aChannel *chptr)); +EXTERN int m_join __P((Reg aClient *cptr, Reg aClient *sptr, int parc, + char *parv[])); +EXTERN int m_njoin __P((Reg aClient *cptr, Reg aClient *sptr, int parc, + char *parv[])); +EXTERN int m_part __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_kick __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int count_channels __P((aClient *sptr)); +EXTERN int m_topic __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_invite __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_list __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_names __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN void send_user_joins __P((aClient *cptr, aClient *user)); +EXTERN time_t collect_channel_garbage __P((time_t now)); +#undef EXTERN diff --git a/ircd/chkconf.c b/ircd/chkconf.c new file mode 100644 index 0000000..7c0032d --- /dev/null +++ b/ircd/chkconf.c @@ -0,0 +1,745 @@ +/************************************************************************ + * 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 rcsid[] = "@(#)$Id: chkconf.c,v 1.13 1999/03/11 23:40:12 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define CHKCONF_C +#include "match_ext.h" +#undef CHKCONF_C + +#define MyMalloc(x) malloc(x) +/*#define MyFree(x) free(x)*/ + +static void new_class(); +static char *getfield(), confchar (); +static int openconf(), validate __P((aConfItem *)); +static int dgets __P((int, char *, int)); +static aClass *get_class(); +static aConfItem *initconf(); + +static int numclasses = 0, *classarr = (int *)NULL, debugflag = 0; +static char *configfile = IRCDCONF_PATH; +static char nullfield[] = ""; +static char maxsendq[12]; + +#define SHOWSTR(x) ((x) ? (x) : "*") + +int main(argc, argv) +int argc; +char *argv[]; +{ + if (argc > 1 && !strncmp(argv[1], "-h", 2)) { + (void)fprintf(stderr, "Usage: %s [-h] [-d[#]] [%s]\n", + argv[0], IRCDCONF_PATH); + exit(0); + } + new_class(0); + + 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]; + + /* ircd.m4 with full path now! Kratz */ + if (access(IRCDM4_PATH, R_OK) == -1) + { + (void)fprintf(stderr, "%s missing.\n", IRCDM4_PATH); + return -1; + } + 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", IRCDM4_PATH, 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; + 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+1)); s++) + ; + tmp++; + } + else if (*tmp == '#') + *tmp = '\0'; + } + if (!*line || *line == '#' || *line == '\n' || + *line == ' ' || *line == '\t') + continue; + + if (line[1] != IRCDCONF_DELIMITER) + { + (void)fprintf(stderr, "ERROR: Bad config line (%s)\n", + line); + if (IRCDCONF_DELIMITER != ':') + (void)fprintf(stderr, + "\tWrong delimiter? (should be %c)\n", + IRCDCONF_DELIMITER); + 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 'B': /* bounce line */ + case 'b': + aconf->status = CONF_BOUNCE; + break; + case 'C': /* Server where I should try to connect */ + case 'c': /* in case of lp failures */ + ccount++; + aconf->status = CONF_CONNECT_SERVER; + break; + case 'D': /* auto connect restrictions */ + case 'd': + aconf->status = CONF_DENY; + 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 'U': /* Uphost, ie. host where client reading */ + case 'u': /* this should connect. */ + /* This is for client only, I must ignore this */ + /* ...U-line should be removed... --msa */ + break; + case 'V': + aconf->status = CONF_VER; + 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) + { + 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", + QUEUELEN); + (void)sprintf(maxsendq, "%d", QUEUELEN); + } + 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; + } + + 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; + } + + if (aconf->status & CONF_VER) + { + if (*aconf->host && !index(aconf->host, '/')) + (void)fprintf(stderr, + "\tWARNING: No / in V line."); + else if (*aconf->passwd && !index(aconf->passwd, '/')) + (void)fprintf(stderr, + "\tWARNING: No / in V line."); + } +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(irc_newline) +char *irc_newline; +{ + static char *line = NULL; + char *end, *field; + + if (irc_newline) + line = irc_newline; + if (line == NULL) + return(NULL); + + field = line; + if ((end = (char *)index(line, IRCDCONF_DELIMITER)) == 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. +*/ +static 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; +{ + Reg aConfItem *aconf, *bconf; + u_int otype = 0, 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, + SHOWSTR(aconf->passwd), aconf->name); + return valid ? 0 : -1; +} + +static char confchar(status) +u_int status; +{ + static char letrs[] = "QIiCcNoOMKARYSLPHV"; + char *s = letrs; + + status &= ~(CONF_MATCH|CONF_ILLEGAL); + + for (; *s; s++, status >>= 1) + if (status & 1) + return *s; + return '-'; +} + +void outofmemory() +{ + (void)write(2, "Out of memory\n", 14); + exit(-1); +} diff --git a/ircd/class.c b/ircd/class.c new file mode 100644 index 0000000..e3457c8 --- /dev/null +++ b/ircd/class.c @@ -0,0 +1,256 @@ +/* + * 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 rcsid[] = "@(#)$Id: class.c,v 1.6 1997/12/19 13:35:57 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define CLASS_C +#include "s_externs.h" +#undef CLASS_C + +#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; +{ + Reg Link *tmp; + Reg aClass *cl; + int retc = BAD_CLIENT_CLASS; + + if (acptr && !IsMe(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| + CONF_ZCONNECT_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 (MAX(60, 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, hlocal, uhlocal, + hglobal, uhglobal) +int class, ping, confreq, maxli, hlocal, uhlocal, hglobal, uhglobal; +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; + MaxSendq(p) = QUEUELEN; + istat.is_class++; + } + else + p = t; + Debug((DEBUG_DEBUG, +"Add Class %d: p %x t %x - cf: %d pf: %d ml: %d sq: %l ml: %d.%d mg: %d.%d", + class, p, t, confreq, ping, maxli, QUEUELEN, hlocal, uhlocal, + hglobal, uhglobal)); + Class(p) = class; + ConFreq(p) = confreq; + PingFreq(p) = ping; + MaxLinks(p) = maxli; + if (sendq) + MaxSendq(p) = sendq; + MaxHLocal(p) = hlocal; + MaxUHLocal(p) = uhlocal; + MaxHGlobal(p) = hglobal; + MaxUHGlobal(p) = uhglobal; + 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() +{ + Reg 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); + istat.is_class--; + } + } + else + cltmp2 = cltmp; + } +} + +void initclass() +{ + classes = (aClass *)make_class(); + istat.is_class++; + + Class(FirstClass()) = 0; + ConFreq(FirstClass()) = CONNECTFREQUENCY; + PingFreq(FirstClass()) = PINGFREQUENCY; + MaxLinks(FirstClass()) = MAXIMUM_LINKS; + MaxSendq(FirstClass()) = QUEUELEN; + Links(FirstClass()) = 0; + NextClass(FirstClass()) = NULL; +} + +void report_classes(sptr, to) +aClient *sptr; +char *to; +{ + Reg aClass *cltmp; + + for (cltmp = FirstClass(); cltmp; cltmp = NextClass(cltmp)) + sendto_one(sptr, rpl_str(RPL_STATSYLINE, to), 'Y', + Class(cltmp), PingFreq(cltmp), ConFreq(cltmp), + MaxLinks(cltmp), MaxSendq(cltmp), + MaxHLocal(cltmp), MaxUHLocal(cltmp), + MaxHGlobal(cltmp), MaxUHGlobal(cltmp)); +} + +long get_sendq(cptr) +aClient *cptr; +{ + Reg int sendq = QUEUELEN, retc = BAD_CLIENT_CLASS; + Reg Link *tmp; + Reg aClass *cl; + + if (cptr->serv) + sendq = MaxSendq(cptr->serv->nline->class); + else 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; +} diff --git a/ircd/class_ext.h b/ircd/class_ext.h new file mode 100644 index 0000000..6d9fadb --- /dev/null +++ b/ircd/class_ext.h @@ -0,0 +1,49 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/class_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/class.c. + */ + +/* External definitions for global variables. + */ +#ifndef CLASS_C +extern aClass *classes; +#endif /* CLASS_C */ + +/* External definitions for global functions. + */ +#ifndef CLASS_C +#define EXTERN extern +#else /* CLASS_C */ +#define EXTERN +#endif /* CLASS_C */ +EXTERN int get_conf_class __P((aConfItem *aconf)); +EXTERN int get_client_class __P((aClient *acptr)); +EXTERN int get_client_ping __P((aClient *acptr)); +EXTERN int get_con_freq __P((aClass *clptr)); +EXTERN void add_class __P((int class, int ping, int confreq, int maxli, + long sendq, int hlocal, int uhlocal, + int hglobal, int uhglobal)); +EXTERN aClass *find_class __P((int cclass)); +EXTERN void check_class(); +EXTERN void initclass(); +EXTERN void report_classes __P((aClient *sptr, char *to)); +EXTERN long get_sendq __P((aClient *cptr)); +#undef EXTERN diff --git a/ircd/hash.c b/ircd/hash.c new file mode 100644 index 0000000..9d31f47 --- /dev/null +++ b/ircd/hash.c @@ -0,0 +1,940 @@ +/************************************************************************ + * 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 rcsid[] = "@(#)$Id: hash.c,v 1.15 1999/06/25 21:50:01 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define HASH_C +#include "s_externs.h" +#undef HASH_C + +static aHashEntry *clientTable = NULL; +static aHashEntry *channelTable = NULL; +static aHashEntry *serverTable = NULL; +static unsigned int *hashtab = NULL; +static int clhits = 0, clmiss = 0, clsize = 0; +static int chhits = 0, chmiss = 0, chsize = 0; +static int svsize = 0; +int _HASHSIZE = 0; +int _CHANNELHASHSIZE = 0; +int _SERVERSIZE = 0; + +/* + * 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. + */ +static u_int hash_nick_name(nname, store) +char *nname; +int *store; +{ + Reg u_char *name = (u_char *)nname; + Reg u_char ch; + Reg u_int hash = 1; + + for (; (ch = *name); name++) + { + hash <<= 1; + hash += hashtab[(int)ch]; + } + /* + if (hash < 0) + hash = -hash; + */ + *store = 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. + */ +static u_int hash_channel_name(hname, store, shortname) +char *hname, shortname; +int *store; +{ + Reg u_char *name = (u_char *)hname; + Reg u_char ch; + Reg int i = 30; + Reg u_int hash = 5; + + if (*name == '!' && shortname == 0) + name += 1 + CHIDLEN; + for (; (ch = *name) && --i; name++) + { + hash <<= 1; + hash += hashtab[(u_int)ch] + (i << 1); + } + *store = hash; + hash %= _CHANNELHASHSIZE; + return (hash); +} + +/* bigger prime + * + * given a positive integer, return a prime number that's larger + * + * 13feb94 gbl + */ +static int bigger_prime(size) +int size; +{ + int trial, failure, sq; + + if (size < 0) + return -1; + + if (size < 4) + return size; + + if (size % 2 == 0) /* Make sure it's odd because... */ + size++; + + for ( ; ; size += 2) /* ...no point checking even numbers - Core */ + { + failure = 0; + sq = (int)sqrt((double)size); + for (trial = 2; trial <= sq ; trial++) + { + if ((size % trial) == 0) + { + failure = 1; + break; + } + } + if (!failure) + return size; + } + /* return -1; */ /* Never reached */ +} + +/* + * clear_*_hash_table + * + * Nullify the hashtable and its contents so it is completely empty. + */ +static void clear_client_hash_table(size) +int size; +{ + _HASHSIZE = bigger_prime(size); + clhits = 0; + clmiss = 0; + if (!clientTable) + clientTable = (aHashEntry *)MyMalloc(_HASHSIZE * + sizeof(aHashEntry)); + bzero((char *)clientTable, sizeof(aHashEntry) * _HASHSIZE); + Debug((DEBUG_DEBUG, "Client Hash Table Init: %d (%d)", + _HASHSIZE, size)); +} + +static void clear_channel_hash_table(size) +int size; +{ + _CHANNELHASHSIZE = bigger_prime(size); + chmiss = 0; + chhits = 0; + if (!channelTable) + channelTable = (aHashEntry *)MyMalloc(_CHANNELHASHSIZE * + sizeof(aHashEntry)); + bzero((char *)channelTable, sizeof(aHashEntry) * _CHANNELHASHSIZE); + Debug((DEBUG_DEBUG, "Channel Hash Table Init: %d (%d)", + _CHANNELHASHSIZE, size)); +} + +static void clear_server_hash_table(size) +int size; +{ + _SERVERSIZE = bigger_prime(size); + if (!serverTable) + serverTable = (aHashEntry *)MyMalloc(_SERVERSIZE * + sizeof(aHashEntry)); + bzero((char *)serverTable, sizeof(aHashEntry) * _SERVERSIZE); + Debug((DEBUG_DEBUG, "Server Hash Table Init: %d (%d)", + _SERVERSIZE, size)); +} + +void inithashtables() +{ + Reg int i; + + clear_client_hash_table((_HASHSIZE) ? _HASHSIZE : HASHSIZE); + clear_channel_hash_table((_CHANNELHASHSIZE) ? _CHANNELHASHSIZE + : CHANNELHASHSIZE); + clear_server_hash_table((_SERVERSIZE) ? _SERVERSIZE : SERVERSIZE); + + /* + * Moved multiplication out from the hashfunctions and into + * a pre-generated lookup table. Should save some CPU usage + * even on machines with a fast mathprocessor. -- Core + */ + hashtab = (u_int *) MyMalloc(256 * sizeof(u_int)); + for (i = 0; i < 256; i++) + hashtab[i] = tolower((char)i) * 109; +} + +static void bigger_hash_table(size, table, new) +int *size; +aHashEntry *table; +int new; +{ + Reg aClient *cptr; + Reg aChannel *chptr; + Reg aServer *sptr; + aHashEntry *otab = table; + int osize = *size; + + while (!new || new <= osize) + if (!new) + { + new = osize; + new = bigger_prime(1 + (int)((float)new * 1.30)); + } + else + new = bigger_prime(1 + new); + + Debug((DEBUG_NOTICE, "bigger_h_table(*%#x = %d,%#x,%d)", + size, osize, table, new)); + + *size = new; + MyFree((char *)table); + table = (aHashEntry *)MyMalloc(sizeof(*table) * new); + bzero((char *)table, sizeof(*table) * new); + + if (otab == channelTable) + { + Debug((DEBUG_ERROR, "Channel Hash Table from %d to %d (%d)", + osize, new, chsize)); + chmiss = 0; + chhits = 0; + chsize = 0; + channelTable = table; + for (chptr = channel; chptr; chptr = chptr->nextch) + chptr->hnextch = NULL; + for (chptr = channel; chptr; chptr = chptr->nextch) + (void)add_to_channel_hash_table(chptr->chname, chptr); + sendto_flag(SCH_HASH, "Channel Hash Table from %d to %d (%d)", + osize, new, chsize); + } + else if (otab == clientTable) + { + Debug((DEBUG_ERROR, "Client Hash Table from %d to %d (%d)", + osize, new, clsize)); + sendto_flag(SCH_HASH, "Client Hash Table from %d to %d (%d)", + osize, new, clsize); + clmiss = 0; + clhits = 0; + clsize = 0; + clientTable = table; + for (cptr = client; cptr; cptr = cptr->next) + cptr->hnext = NULL; + for (cptr = client; cptr; cptr = cptr->next) + (void)add_to_client_hash_table(cptr->name, cptr); + } + else if (otab == serverTable) + { + Debug((DEBUG_ERROR, "Server Hash Table from %d to %d (%d)", + osize, new, svsize)); + sendto_flag(SCH_HASH, "Server Hash Table from %d to %d (%d)", + osize, new, svsize); + svsize = 0; + serverTable = table; + for (sptr = svrtop; sptr; sptr = sptr->nexts) + sptr->shnext = NULL; + for (sptr = svrtop; sptr; sptr = sptr->nexts) + (void)add_to_server_hash_table(sptr, sptr->bcptr); + } + ircd_writetune(tunefile); + return; +} + + +/* + * add_to_client_hash_table + */ +int add_to_client_hash_table(name, cptr) +char *name; +aClient *cptr; +{ + Reg u_int hashv; + + hashv = hash_nick_name(name, &cptr->hashv); + cptr->hnext = (aClient *)clientTable[hashv].list; + clientTable[hashv].list = (void *)cptr; + clientTable[hashv].links++; + clientTable[hashv].hits++; + clsize++; + if (clsize > _HASHSIZE) + bigger_hash_table(&_HASHSIZE, clientTable, 0); + return 0; +} + +/* + * add_to_channel_hash_table + */ +int add_to_channel_hash_table(name, chptr) +char *name; +aChannel *chptr; +{ + Reg u_int hashv; + + hashv = hash_channel_name(name, &chptr->hashv, 0); + chptr->hnextch = (aChannel *)channelTable[hashv].list; + channelTable[hashv].list = (void *)chptr; + channelTable[hashv].links++; + channelTable[hashv].hits++; + chsize++; + if (chsize > _CHANNELHASHSIZE) + bigger_hash_table(&_CHANNELHASHSIZE, channelTable, 0); + return 0; +} + +/* + * add_to_server_hash_table + */ +int add_to_server_hash_table(sptr, cptr) +aServer *sptr; +aClient *cptr; +{ + Reg u_int hashv; + + Debug((DEBUG_DEBUG, "Add %s token %d/%d/%s cptr %#x to server table", + sptr->bcptr->name, sptr->stok, sptr->ltok, sptr->tok, cptr)); + hashv = sptr->stok * 15053; + hashv %= _SERVERSIZE; + sptr->shnext = (aServer *)serverTable[hashv].list; + serverTable[hashv].list = (void *)sptr; + serverTable[hashv].links++; + serverTable[hashv].hits++; + svsize++; + if (svsize > _SERVERSIZE) + bigger_hash_table(&_SERVERSIZE, serverTable, 0); + return 0; +} + +/* + * del_from_client_hash_table + */ +int del_from_client_hash_table(name, cptr) +char *name; +aClient *cptr; +{ + Reg aClient *tmp, *prev = NULL; + Reg u_int hashv; + + hashv = cptr->hashv; + hashv %= _HASHSIZE; + 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--; + clsize--; + return 1; + } + else + { + sendto_flag(SCH_ERROR, "cl-hash table failure"); + Debug((DEBUG_ERROR, "cl-hash table failure")); + /* + * 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; +{ + Reg aChannel *tmp, *prev = NULL; + Reg u_int hashv; + + hashv = chptr->hashv; + hashv %= _CHANNELHASHSIZE; + 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--; + chsize--; + return 1; + } + else + { + sendto_flag(SCH_ERROR, "ch-hash table failure"); + return -1; + } + } + prev = tmp; + } + return 0; +} + + +/* + * del_from_server_hash_table + */ +int del_from_server_hash_table(sptr, cptr) +aServer *sptr; +aClient *cptr; +{ + Reg aServer *tmp, *prev = NULL; + Reg u_int hashv; + + hashv = sptr->stok * 15053; + hashv %= _SERVERSIZE; + for (tmp = (aServer *)serverTable[hashv].list; tmp; tmp = tmp->shnext) + { + if (tmp == sptr) + { + if (prev) + prev->shnext = tmp->shnext; + else + serverTable[hashv].list = (void *)tmp->shnext; + tmp->shnext = NULL; + if (serverTable[hashv].links > 0) + { + serverTable[hashv].links--; + svsize--; + return 1; + } + else + { + sendto_flag(SCH_ERROR, "se-hash table failure"); + return -1; + } + } + prev = tmp; + } + return 0; +} + + +/* + * hash_find_client + */ +aClient *hash_find_client(name, cptr) +char *name; +aClient *cptr; +{ + Reg aClient *tmp; + Reg aClient *prv = NULL; + Reg aHashEntry *tmp3; + u_int hashv, hv; + + hashv = hash_nick_name(name, &hv); + tmp3 = &clientTable[hashv]; + + /* + * Got the bucket, now search the chain. + */ + for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext) + if (hv == tmp->hashv && mycmp(name, tmp->name) == 0) + { + clhits++; + /* + * 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); + } + clmiss++; + return (cptr); +} + +/* + * hash_find_server + */ +aClient *hash_find_server(server, cptr) +char *server; +aClient *cptr; +{ + Reg aClient *tmp, *prv = NULL; + Reg char *t; + Reg char ch; + aHashEntry *tmp3; + u_int hashv, hv; + + hashv = hash_nick_name(server, &hv); + tmp3 = &clientTable[hashv]; + + for (tmp = (aClient *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnext) + { + if (!IsServer(tmp) && !IsMe(tmp)) + continue; + if (hv == tmp->hashv && mycmp(server, tmp->name) == 0) + { + clhits++; + if (prv) + { + aClient *tmp2; + + tmp2 = (aClient *)tmp3->list; + tmp3->list = (void *)tmp; + prv->hnext = tmp->hnext; + tmp->hnext = tmp2; + } + return (tmp); + } + } + 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 isn't often done this way in lieu of using match(). + */ + for (;;) + { + t--; + for (; t >= server; t--) + if (*(t+1) == '.') + break; + if (t < server || *t == '*') + break; + ch = *t; + *t = '*'; + /* + * Don't need to check IsServer() here since nicknames can't + * have *'s in them anyway. + */ + if (((tmp = hash_find_client(t, cptr))) != cptr) + { + *t = ch; + return (tmp); + } + *t = ch; + } + clmiss++; + return (cptr); +} + +/* + * hash_find_channel + */ +aChannel *hash_find_channel(name, chptr) +char *name; +aChannel *chptr; +{ + Reg aChannel *tmp, *prv = NULL; + Reg aHashEntry *tmp3; + u_int hashv, hv; + + hashv = hash_channel_name(name, &hv, 0); + tmp3 = &channelTable[hashv]; + + for (tmp = (aChannel *)tmp3->list; tmp; prv = tmp, tmp = tmp->hnextch) + if (hv == tmp->hashv && mycmp(name, tmp->chname) == 0) + { + chhits++; + if (prv) + { + register aChannel *tmp2; + + tmp2 = (aChannel *)tmp3->list; + tmp3->list = (void *)tmp; + prv->hnextch = tmp->hnextch; + tmp->hnextch = tmp2; + } + return (tmp); + } + chmiss++; + return chptr; +} + +/* + * hash_find_channels + * + * look up matches for !?????name instead of a real match. + */ +aChannel *hash_find_channels(name, chptr) +char *name; +aChannel *chptr; +{ + aChannel *tmp; + u_int hashv, hv; + + if (chptr == NULL) + { + aHashEntry *tmp3; + + hashv = hash_channel_name(name, &hv, 1); + tmp3 = &channelTable[hashv]; + chptr = (aChannel *) tmp3->list; + } + else + { + hv = chptr->hashv; + chptr = chptr->hnextch; + } + + if (chptr == NULL) + return NULL; + for (tmp = chptr; tmp; tmp = tmp->hnextch) + if (hv == tmp->hashv && *tmp->chname == '!' && + mycmp(name, tmp->chname + CHIDLEN + 1) == 0) + { + chhits++; + return (tmp); + } + chmiss++; + return NULL; +} + +/* + * hash_find_stoken + */ +aServer *hash_find_stoken(tok, cptr, dummy) +int tok; +aClient *cptr; +void *dummy; +{ + Reg aServer *tmp, *prv = NULL; + Reg aHashEntry *tmp3; + u_int hashv, hv; + + hv = hashv = tok * 15053; + hashv %= _SERVERSIZE; + tmp3 = &serverTable[hashv]; + + for (tmp = (aServer *)tmp3->list; tmp; prv = tmp, tmp = tmp->shnext) + if (tmp->stok == tok && tmp->bcptr->from == cptr) + { + if (prv) + { + Reg aServer *tmp2; + + tmp2 = (aServer *)tmp3->list; + tmp3->list = (void *)tmp; + prv->shnext = tmp->shnext; + tmp->shnext = tmp2; + } + return (tmp); + } + return (aServer *)dummy; +} + +/* + * 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 (2); + case 'r' : + { + Reg aClient *acptr; + + sendto_one(sptr,"NOTICE %s :Rehashing Client List.", parv[0]); + clear_client_hash_table(_HASHSIZE); + for (acptr = client; acptr; acptr = acptr->next) + (void)add_to_client_hash_table(acptr->name, acptr); + break; + } + case 'R' : + { + Reg aChannel *acptr; + + sendto_one(sptr,"NOTICE %s :Rehashing Channel List.", parv[0]); + clear_channel_hash_table(_CHANNELHASHSIZE); + 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], NULL, 0)); + return (2); + case 'h' : + if (parc > 2) + sendto_one(sptr,"NOTICE %s :%s hash to entry %d", + parv[0], parv[2], + hash_nick_name(parv[2], NULL)); + return (2); + case 'n' : + { + aClient *tmp; + int max; + + if (parc <= 2 || !IsAnOper(sptr)) + return (1); + 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 (2); + } + case 'N' : + { + aChannel *tmp; + int max; + + if (parc <= 2 || !IsAnOper(sptr)) + return (1); + 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 (2); + } + case 'S' : +#else + if (parc>1&&!strcmp(parv[1],"sums")){ +#endif + sendto_one(sptr, "NOTICE %s :[SBSDC] [SUSER]", parv[0]); + sendto_one(sptr, "NOTICE %s :[SSERV] [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 2; +#ifdef DEBUGMODE + case 'z' : + { + if (parc <= 2 || !IsAnOper(sptr)) + return 1; + l = atoi(parv[2]); + if (l < 256) + return 1; + bigger_hash_table(&_HASHSIZE, clientTable, l); + sendto_one(sptr, "NOTICE %s :HASHSIZE now %d", parv[0], l); + break; + } + case 'Z' : + { + if (parc <= 2 || !IsAnOper(sptr)) + return 1; + l = atoi(parv[2]); + if (l < 256) + return 1; + bigger_hash_table(&_CHANNELHASHSIZE, channelTable, l); + 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 * (float)tothits) / (1.0 * (float)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 2; +#endif +} + + diff --git a/ircd/hash_def.h b/ircd/hash_def.h new file mode 100644 index 0000000..e19c3ce --- /dev/null +++ b/ircd/hash_def.h @@ -0,0 +1,32 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/hash_def.h + * 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. + */ + +typedef struct hashentry { + int hits; + int links; + void *list; +} aHashEntry; + +/* + * it is not important for these to be "big" as ircd will make them grow + * as required. + */ +#define HASHSIZE ((int)((float)MAXCONNECTIONS*1.75)) +#define CHANNELHASHSIZE ((int)(((float)MAXCONNECTIONS*1.75)/2.0)) +#define SERVERSIZE (MAXCONNECTIONS/10) diff --git a/ircd/hash_ext.h b/ircd/hash_ext.h new file mode 100644 index 0000000..8ee1d88 --- /dev/null +++ b/ircd/hash_ext.h @@ -0,0 +1,52 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/hash_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/hash.c. + */ + +/* External definitions for global variables. + */ +#ifndef HASH_C +extern int _HASHSIZE; +extern int _CHANNELHASHSIZE; +extern int _SERVERSIZE; +#endif /* HASH_C */ + +/* External definitions for global functions. + */ +#ifndef HASH_C +#define EXTERN extern +#else /* HASH_C */ +#define EXTERN +#endif /* HASH_C */ +EXTERN void inithashtables(); +EXTERN int add_to_client_hash_table __P((char *name, aClient *cptr)); +EXTERN int add_to_channel_hash_table __P((char *name, aChannel *chptr)); +EXTERN int add_to_server_hash_table __P((aServer *sptr, aClient *cptr)); +EXTERN int del_from_client_hash_table __P((char *name, aClient *cptr)); +EXTERN int del_from_channel_hash_table __P((char *name, aChannel *chptr)); +EXTERN int del_from_server_hash_table __P((aServer *sptr, aClient *cptr)); +EXTERN aClient *hash_find_client __P((char *name, aClient *cptr)); +EXTERN aClient *hash_find_server __P((char *server, aClient *cptr)); +EXTERN aChannel *hash_find_channel __P((char *name, aChannel *chptr)); +EXTERN aChannel *hash_find_channels __P((char *name, aChannel *chptr)); +EXTERN aServer *hash_find_stoken __P((int tok, aClient *cptr, void *dummy)); +EXTERN int m_hash __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +#undef EXTERN diff --git a/ircd/ircd.c b/ircd/ircd.c new file mode 100644 index 0000000..72bbf95 --- /dev/null +++ b/ircd/ircd.c @@ -0,0 +1,1287 @@ +/************************************************************************ + * 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 rcsid[] = "@(#)$Id: ircd.c,v 1.62 1999/08/13 17:17:42 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define IRCD_C +#include "s_externs.h" +#undef IRCD_C + +aClient me; /* That's me */ +aClient *client = &me; /* Pointer to beginning of Client list */ + +static void open_debugfile(), setup_signals(), io_loop(); + +istat_t istat; +char **myargv; +int rehashed = 0; +int portnum = -1; /* Server port number, listening this */ +char *configfile = IRCDCONF_PATH; /* Server configuration file */ +int debuglevel = -1; /* Server debug level */ +int bootopt = BOOT_PROT|BOOT_STRICTPROT; /* Server boot option flags */ +char *debugmode = ""; /* -"- -"- -"- -"- */ +char *sbrk0; /* initial sbrk(0) */ +char *tunefile = IRCDTUNE_PATH; +static int dorehash = 0, + dorestart = 0, + restart_iauth = 0; + +time_t nextconnect = 1; /* time for next try_connections call */ +time_t nextgarbage = 1; /* time for next collect_channel_garbage 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 nextiarestart = 1; /* next time to check if iauth is alive */ + +#ifdef PROFIL +extern etext(); + +RETSIGTYPE s_monitor(s) +int s; +{ + static int mon = 0; +#if POSIX_SIGNALS + struct sigaction act; +#endif + + (void)moncontrol(mon); + mon = 1 - mon; +#if 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 + +RETSIGTYPE s_die(s) +int s; +{ +#ifdef USE_SYSLOG + (void)syslog(LOG_CRIT, "Server Killed By SIGTERM"); +#endif + ircd_writetune(tunefile); + flush_connections(me.fd); + exit(-1); +} + +#if defined(USE_IAUTH) +RETSIGTYPE s_slave(s) +int s; +{ +# if POSIX_SIGNALS + struct sigaction act; + + act.sa_handler = s_slave; + 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_slave); +# endif + restart_iauth = 1; +} +#endif + +static RETSIGTYPE s_rehash(s) +int s; +{ +#if POSIX_SIGNALS + struct sigaction act; + + 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 + dorehash = 1; +} + +void restart(mesg) +char *mesg; +{ +#ifdef USE_SYSLOG + (void)syslog(LOG_WARNING, "Restarting Server because: %s (%u)", mesg, + (u_int)((char *)sbrk((size_t)0)-sbrk0)); +#endif + sendto_flag(SCH_NOTICE, "Restarting server because: %s (%u)", mesg, + (u_int)((char *)sbrk((size_t)0)-sbrk0)); + server_reboot(); +} + +RETSIGTYPE s_restart(s) +int s; +{ +#if POSIX_SIGNALS + struct sigaction act; + + act.sa_handler = s_restart; + act.sa_flags = 0; + (void)sigemptyset(&act.sa_mask); + (void)sigaddset(&act.sa_mask, SIGINT); + (void)sigaction(SIGINT, &act, NULL); +#else + (void)signal(SIGHUP, SIG_DFL); /* sysV -argv */ +#endif + dorestart = 1; +} + +void server_reboot() +{ + Reg int i; + + sendto_flag(SCH_NOTICE, "Aieeeee!!! Restarting server... (%u)", + (u_int)((char *)sbrk((size_t)0)-sbrk0)); + + Debug((DEBUG_NOTICE,"Restarting server...")); + flush_connections(me.fd); + /* + ** fd 0 must be 'preserved' if either the -d or -i options have + ** been passed to us before restarting. + */ +#ifdef USE_SYSLOG + (void)closelog(); +#endif + for (i = 3; i < MAXCONNECTIONS; i++) + (void)close(i); + if (!(bootopt & (BOOT_TTY|BOOT_DEBUG))) + (void)close(2); + (void)close(1); + if ((bootopt & BOOT_CONSOLE) || isatty(0)) + (void)close(0); + ircd_writetune(tunefile); + if (!(bootopt & (BOOT_INETD|BOOT_OPER))) + { + (void)execv(IRCD_PATH, 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", IRCD_PATH, + 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(currenttime) +time_t currenttime; +{ + static time_t lastsort = 0; + Reg aConfItem *aconf; + Reg aClient *cptr; + aConfItem **pconf; + int confrq; + time_t next = 0; + aClass *cltmp; + aConfItem *con_conf = NULL; + double f, f2; + aCPing *cp; + + Debug((DEBUG_NOTICE,"Connection check at : %s", + myctime(currenttime))); + for (aconf = conf; aconf; aconf = aconf->next ) + { + /* Also when already connecting! (update holdtimes) --SRB */ + if (!(aconf->status & (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER))) + continue; + /* + ** 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 > currenttime)) + { + if ((next > aconf->hold) || (next == 0)) + next = aconf->hold; + continue; + } + send_ping(aconf); + if (aconf->port <= 0) + continue; + + cltmp = Class(aconf); + confrq = get_con_freq(cltmp); + aconf->hold = currenttime + 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) + cptr = find_mask(aconf->name, (aClient *)NULL); + /* + ** It is not connected, scan clients and see if any matches + ** a D(eny) line. + */ + if (find_denied(aconf->name, Class(cltmp))) + continue; + /* We have a candidate, let's see if it could be the best. */ + if (!cptr && (Links(cltmp) < MaxLinks(cltmp)) && + (!con_conf || + (con_conf->pref > aconf->pref && aconf->pref >= 0) || + (con_conf->pref == -1 && + Class(cltmp) > ConfClass(con_conf)))) + con_conf = aconf; + if ((next > aconf->hold) || (next == 0)) + next = aconf->hold; + } + if (con_conf) + { + if (con_conf->next) /* are we already last? */ + { + for (pconf = &conf; (aconf = *pconf); + pconf = &(aconf->next)) + /* put the current one at the end and + * make sure we try all connections + */ + if (aconf == con_conf) + *pconf = aconf->next; + (*pconf = con_conf)->next = 0; + } + if (connect_server(con_conf, (aClient *)NULL, + (struct hostent *)NULL) == 0) + sendto_flag(SCH_NOTICE, + "Connection to %s[%s] activated.", + con_conf->name, con_conf->host); + } + Debug((DEBUG_NOTICE,"Next connection check : %s", myctime(next))); + /* + * calculate preference value based on accumulated stats. + */ + if (!lastsort || lastsort < currenttime) + { + for (aconf = conf; aconf; aconf = aconf->next) + if (!(cp = aconf->ping) || !cp->seq || !cp->recvd) + aconf->pref = -1; + else + { + f = (double)cp->recvd / (double)cp->seq; + f2 = pow(f, (double)20.0); + if (f2 < (double)0.001) + f = (double)0.001; + else + f = f2; + f2 = (double)cp->ping / (double)cp->recvd; + f = f2 / f; + if (f > 100000.0) + f = 100000.0; + aconf->pref = (u_int) (f * (double)100.0); + } + lastsort = currenttime + 60; + } + return (next); +} + + +static void close_held(cptr) +aClient *cptr; +{ + Reg aClient *acptr; + int i; + + for (i = highest_fd; i >= 0; i--) + if ((acptr = local[i]) && (cptr->port == acptr->port) && + (acptr != cptr) && IsHeld(acptr) && + !bcmp((char *)&cptr->ip, (char *)&acptr->ip, + sizeof(acptr->ip))) + { + (void) exit_client(acptr, acptr, &me, + "Reconnect Timeout"); + return; + } +} + + +static time_t check_pings(currenttime) +time_t currenttime; +{ + static time_t lkill = 0; + Reg aClient *cptr; + Reg int kflag = 0; + int ping = 0, i, rflag = 0; + time_t oldest = 0, timeout; + char *reason; + + for (i = highest_fd; i >= 0; i--) + { + if (!(cptr = local[i]) || IsListening(cptr) || IsLog(cptr) || + IsHeld(cptr)) + continue; + + /* + * K and R lines once per minute, max. This is the max. + * granularity in K-lines anyway (with time field). + */ + if ((currenttime - lkill > 60) || rehashed) + { + if (IsPerson(cptr)) + { + kflag = find_kill(cptr, rehashed, &reason); +#ifdef R_LINES_OFTEN + rflag = find_restrict(cptr); +#endif + } + else + { + kflag = rflag = 0; + reason = NULL; + } + } + ping = IsRegistered(cptr) ? get_client_ping(cptr) : + ACCEPTTIMEOUT; + Debug((DEBUG_DEBUG, "c(%s) %d p %d k %d r %d a %d", + cptr->name, cptr->status, ping, kflag, rflag, + currenttime - cptr->lasttime)); + /* + * Ok, so goto's are ugly and can be avoided here but this code + * is already indented enough so I think its justified. -avalon + */ + if (!kflag && !rflag && IsRegistered(cptr) && + (ping >= currenttime - cptr->lasttime)) + goto ping_timeout; + /* + * If the server hasnt talked to us in 2*ping seconds + * and it has a ping time, then close its connection. + * If the client is a user and a KILL line was found + * to be active, close this connection too. + */ + if (kflag || rflag || + ((currenttime - cptr->lasttime) >= (2 * ping) && + (cptr->flags & FLAGS_PINGSENT)) || + (!IsRegistered(cptr) && + (currenttime - cptr->firsttime) >= ping)) + { + if (IsReconnect(cptr)) + { + sendto_flag(SCH_ERROR, + "Reconnect timeout to %s", + get_client_name(cptr, TRUE)); + close_held(cptr); + (void)exit_client(cptr, cptr, &me, + "Ping timeout"); + } + if (!IsRegistered(cptr) && + (DoingDNS(cptr) || DoingAuth(cptr) || + DoingXAuth(cptr))) + { + if (cptr->authfd >= 0) + { + (void)close(cptr->authfd); + cptr->authfd = -1; + cptr->count = 0; + *cptr->buffer = '\0'; + } + Debug((DEBUG_NOTICE, "%s/%c%s timeout %s", + (DoingDNS(cptr)) ? "DNS" : "dns", + (DoingXAuth(cptr)) ? "X" : "x", + (DoingAuth(cptr)) ? "AUTH" : "auth", + get_client_name(cptr,TRUE))); + del_queries((char *)cptr); + ClearAuth(cptr); +#if defined(USE_IAUTH) + if (DoingDNS(cptr) || DoingXAuth(cptr)) + { + if (DoingDNS(cptr) && + (iauth_options & XOPT_EXTWAIT)) + { + /* iauth wants more time */ + sendto_iauth("%d d", cptr->fd); + ClearDNS(cptr); + cptr->lasttime = currenttime; + continue; + } + if (DoingXAuth(cptr) && + (iauth_options & XOPT_NOTIMEOUT)) + { + cptr->exitc = EXITC_AUTHTOUT; + sendto_iauth("%d T", cptr->fd); + ereject_user(cptr, " Timeout ", + "Authentication Timeout"); + continue; + } + sendto_iauth("%d T", cptr->fd); + SetDoneXAuth(cptr); + } +#endif + ClearDNS(cptr); + ClearXAuth(cptr); + ClearWXAuth(cptr); + cptr->firsttime = currenttime; + cptr->lasttime = currenttime; + continue; + } + if (IsServer(cptr) || IsConnecting(cptr) || + IsHandshake(cptr)) + sendto_flag(SCH_NOTICE, + "No response from %s closing link", + get_client_name(cptr, FALSE)); + /* + * this is used for KILL lines with time restrictions + * on them - send a messgae to the user being killed + * first. + */ + if (kflag && IsPerson(cptr)) + { + char buf[100]; + + sendto_flag(SCH_NOTICE, + "Kill line active for %s", + get_client_name(cptr, FALSE)); + cptr->exitc = EXITC_KLINE; + if (!BadPtr(reason)) + sprintf(buf, "Kill line active: %.80s", + reason); + (void)exit_client(cptr, cptr, &me, (reason) ? + buf : "Kill line active"); + } + +#if defined(R_LINES) && defined(R_LINES_OFTEN) + else if (IsPerson(cptr) && rflag) + { + sendto_flag(SCH_NOTICE, + "Restricting %s, closing link.", + get_client_name(cptr,FALSE)); + cptr->exitc = EXITC_RLINE; + (void)exit_client(cptr, cptr, &me, + "Restricting"); + } +#endif + else + { + cptr->exitc = EXITC_PING; + (void)exit_client(cptr, cptr, &me, + "Ping timeout"); + } + continue; + } + else if (IsRegistered(cptr) && + (cptr->flags & FLAGS_PINGSENT) == 0) + { + /* + * if we havent PINGed the connection and we havent + * heard from it in a while, PING it to make sure + * it is still alive. + */ + cptr->flags |= FLAGS_PINGSENT; + /* not nice but does the job */ + cptr->lasttime = currenttime - ping; + sendto_one(cptr, "PING :%s", me.name); + } +ping_timeout: + timeout = cptr->lasttime + ping; + while (timeout <= currenttime) + timeout += ping; + if (timeout < oldest || !oldest) + oldest = timeout; + } + if (currenttime - lkill > 60) + lkill = currenttime; + if (!oldest || oldest < currenttime) + oldest = currenttime + PINGFREQUENCY; + if (oldest < currenttime + 2) + oldest += 2; + Debug((DEBUG_NOTICE,"Next check_ping() call at: %s, %d %d %d", + myctime(oldest), ping, oldest, currenttime)); + return (oldest); +} + + +static void setup_me(mp) +aClient *mp; +{ + struct passwd *p; + + p = getpwuid(getuid()); + strncpyzt(mp->username, (p) ? p->pw_name : "unknown", + sizeof(mp->username)); + (void)get_my_name(mp, mp->sockhost, sizeof(mp->sockhost)-1); + + /* Setup hostp - fake record to resolve localhost. -Toor */ + mp->hostp = (struct hostent *)MyMalloc(sizeof(struct hostent)); + mp->hostp->h_name = MyMalloc(strlen(me.sockhost)+1); + strcpy(mp->hostp->h_name, mp->sockhost); + mp->hostp->h_aliases = (char **)MyMalloc(sizeof(char *)); + *mp->hostp->h_aliases = NULL; + mp->hostp->h_addrtype = AFINET; + mp->hostp->h_length = +#ifdef INET6 + IN6ADDRSZ; +#else + sizeof(long); +#endif + mp->hostp->h_addr_list = (char **)MyMalloc(2*sizeof(char *)); +#ifdef INET6 + mp->hostp->h_addr_list[0] = (char *)&in6addr_loopback; +#else + mp->hostp->h_addr_list[0] = (void *)MyMalloc(mp->hostp->h_length); + *(long *)(mp->hostp->h_addr_list[0]) = IN_LOOPBACKNET; +#endif + mp->hostp->h_addr_list[1] = NULL ; + + if (mp->name[0] == '\0') + strncpyzt(mp->name, mp->sockhost, sizeof(mp->name)); + if (me.info == DefInfo) + me.info = mystrdup("IRCers United"); + mp->lasttime = mp->since = mp->firsttime = time(NULL); + mp->hopcount = 0; + mp->authfd = -1; + mp->auth = mp->username; + mp->confs = NULL; + mp->flags = 0; + mp->acpt = mp->from = mp; + mp->next = NULL; + mp->user = NULL; + mp->fd = -1; + SetMe(mp); + (void) make_server(mp); + mp->serv->snum = find_server_num (ME); + (void) make_user(mp); + istat.is_users++; /* here, cptr->next is NULL, see make_user() */ + mp->user->flags |= FLAGS_OPER; + mp->serv->up = mp->name; + mp->user->server = find_server_string(mp->serv->snum); + strncpyzt(mp->user->username, (p) ? p->pw_name : "unknown", + sizeof(mp->user->username)); + (void) strcpy(mp->user->host, mp->name); + + (void)add_to_client_hash_table(mp->name, mp); + + setup_server_channels(mp); +} + +/* +** 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 [-a] [-b] [-c]%s [-h servername] [-q] [-o] [-i] [-T tunefile] [-p (strict|on|off)] [-s] [-v] %s\n", +#ifdef CMDLINE_CONFIG + " [-f config]", +#else + "", +#endif +#ifdef DEBUGMODE + " [-x loglevel] [-t]" +#else + "" +#endif + ); + (void)printf("Server not started\n\n"); + exit(-1); +} + +int main(argc, argv) +int argc; +char *argv[]; +{ + uid_t uid, euid; + + (void) myctime(time(NULL)); /* Don't ask, just *don't* ask */ + sbrk0 = (char *)sbrk((size_t)0); + uid = getuid(); + euid = geteuid(); +#ifdef PROFIL + (void)monstartup(0, etext); + (void)moncontrol(1); + (void)signal(SIGUSR1, s_monitor); +#endif + +#ifdef CHROOTDIR + ircd_res_init(); + if (chroot(ROOT_PATH)) + { + perror("chroot"); + (void)fprintf(stderr,"%s: Cannot chroot: %s.\n", IRCD_PATH, + ROOT_PATH); + exit(5); + } +#endif /*CHROOTDIR*/ + +#ifdef ZIP_LINKS + if (zlib_version[0] == '0') + { + fprintf(stderr, "zlib version 1.0 or higher required\n"); + exit(1); + } + if (zlib_version[0] != ZLIB_VERSION[0]) + { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + } + if (strcmp(zlib_version, ZLIB_VERSION) != 0) + { + fprintf(stderr, "warning: different zlib version\n"); + } +#endif + + myargv = argv; + (void)umask(077); /* better safe than sorry --SRB */ + bzero((char *)&me, sizeof(me)); + + version = make_version(); /* Generate readable version string */ + + /* + ** 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 'b': + bootopt |= BOOT_BADTUNE; + break; + case 'c': + bootopt |= BOOT_CONSOLE; + break; + case 'q': + bootopt |= BOOT_QUICK; + 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': + if (*p == '\0') + bad_command(); + strncpyzt(me.name, p, sizeof(me.name)); + break; + case 'i': + bootopt |= BOOT_INETD|BOOT_AUTODIE; + break; + case 'p': + if (!strcmp(p, "strict")) + bootopt |= BOOT_PROT|BOOT_STRICTPROT; + else if (!strcmp(p, "on")) + bootopt |= BOOT_PROT; + else if (!strcmp(p, "off")) + bootopt &= ~(BOOT_PROT|BOOT_STRICTPROT); + else + bad_command(); + break; + case 's': + bootopt |= BOOT_NOIAUTH; + break; + case 't': + (void)setuid((uid_t)uid); + bootopt |= BOOT_TTY; + break; + case 'T': + if (*p == '\0') + bad_command(); + tunefile = p; + break; + case 'v': + (void)printf("ircd %s %s\n\tzlib %s\n\t%s #%s\n", + version, serveropts, +#ifndef ZIP_LINKS + "not used", +#else + zlib_version, +#endif + creation, generation); + 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(); + } + } + + if (argc > 0) + bad_command(); /* This exits out */ + +#if defined(USE_IAUTH) && defined(__CYGWIN32__) + if ((bootopt & BOOT_NOIAUTH) == 0) + { + bootopt |= BOOT_NOIAUTH; + (void)fprintf(stderr, "WARNING: Assuming -s option.\n"); + } +#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) + (void)setuid((uid_t)euid); +# if defined(IRC_UID) && defined(IRC_GID) + if ((int)getuid() == 0) + { + /* 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)setgid(IRC_GID); + (void)setuid(IRC_UID); + } +# endif +#endif /*CHROOTDIR/UID/GID*/ + +#if defined(USE_IAUTH) + if ((bootopt & BOOT_NOIAUTH) == 0) + switch (vfork()) + { + case -1: + fprintf(stderr, "%s: Unable to fork!", myargv[0]); + exit(-1); + case 0: + close(0); close(1); close(3); + if (execl(IAUTH_PATH, IAUTH, "-X", NULL) < 0) + _exit(-1); + default: + { + int rc; + + (void)wait(&rc); + if (rc != 0) + { + fprintf(stderr, + "%s: error: unable to find \"%s\".\n", + myargv[0], IAUTH_PATH); + exit(-1); + } + } + } +#endif + + setup_signals(); + + /* 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); + } + + initstats(); + ircd_readtune(tunefile); + timeofday = time(NULL); +#ifdef CACHED_MOTD + motd = NULL; + read_motd(IRCDMOTD_PATH); +#endif + inithashtables(); + initlists(); + initclass(); + initwhowas(); + timeofday = time(NULL); + open_debugfile(); + timeofday = time(NULL); + (void)init_sys(); + +#ifdef USE_SYSLOG + openlog(myargv[0], LOG_PID|LOG_NDELAY, LOG_FACILITY); +#endif + timeofday = time(NULL); + if (initconf(bootopt) == -1) + { + Debug((DEBUG_FATAL, "Failed in reading configuration file %s", + configfile)); + /* no can do. + (void)printf("Couldn't open configuration file %s\n", + configfile); + */ + exit(-1); + } + else + { + aClient *acptr = NULL; + int i; + + for (i = 0; i <= highest_fd; i++) + { + if (!(acptr = local[i])) + continue; + if (IsListening(acptr)) + break; + acptr = NULL; + } + /* exit if there is nothing to listen to */ + if (acptr == NULL) + exit(-1); + } + + dbuf_init(); + setup_me(&me); + check_class(); + ircd_writetune(tunefile); + if (bootopt & BOOT_INETD) + { + aClient *tmp; + aConfItem *aconf; + + tmp = make_client(NULL); + + tmp->fd = 0; + tmp->flags = FLAGS_LISTEN; + tmp->acpt = tmp; + tmp->from = tmp; + tmp->firsttime = time(NULL); + + SetMe(tmp); + + (void)strcpy(tmp->name, "*"); + + if (inetport(tmp, 0, "0.0.0.0", 0)) + tmp->fd = -1; + if (tmp->fd == 0) + { + aconf = make_conf(); + aconf->status = CONF_LISTEN_PORT; + aconf->clients++; + aconf->next = conf; + conf = aconf; + + tmp->confs = make_link(); + tmp->confs->next = NULL; + tmp->confs->value.aconf = aconf; + add_fd(tmp->fd, &fdas); + add_fd(tmp->fd, &fdall); + set_non_blocking(tmp->fd, tmp); + } + else + exit(5); + } + if (bootopt & BOOT_OPER) + { + aClient *tmp = add_connection(&me, 0); + + if (!tmp) + exit(1); + SetMaster(tmp); + local[0] = tmp; + } + else + write_pidfile(); + + Debug((DEBUG_NOTICE,"Server ready...")); +#ifdef USE_SYSLOG + syslog(LOG_NOTICE, "Server Ready: v%s (%s #%s)", version, creation, + generation); +#endif + timeofday = time(NULL); + while (1) + io_loop(); +} + + +void io_loop() +{ + static time_t delay = 0; + int maxs = 4; + + /* + ** 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 && timeofday >= nextconnect) + nextconnect = try_connections(timeofday); + /* + ** Every once in a while, hunt channel structures that + ** can be freed. + */ + if (timeofday >= nextgarbage) + nextgarbage = collect_channel_garbage(timeofday); + /* + ** DNS checks. One to timeout queries, one for cache expiries. + */ + if (timeofday >= nextdnscheck) + nextdnscheck = timeout_query_list(timeofday); + if (timeofday >= nextexpire) + nextexpire = expire_cache(timeofday); + /* + ** 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 -= timeofday; + /* + ** 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); + + /* + ** First, try to drain traffic from servers (this includes listening + ** ports). Give up, either if there's no traffic, or too many + ** iterations. + */ + while (maxs--) + if (read_message(0, &fdas, 0)) + flush_fdary(&fdas); + else + break; + + Debug((DEBUG_DEBUG, "delay for %d", delay)); + /* + ** Second, deal with _all_ clients but only try to empty sendQ's for + ** servers. Other clients are dealt with below.. + */ + if (read_message(1, &fdall, 1) == 0 && delay > 1) + { + /* + ** Timed out (e.g. *NO* traffic at all). + ** Try again but also check to empty sendQ's for all clients. + */ + sendto_flag(SCH_DEBUG, "read_message(RO) -> 0 [%d]", delay); + (void)read_message(delay - 1, &fdall, 0); + } + timeofday = time(NULL); + + 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 (timeofday >= nextping) + { + nextping = check_pings(timeofday); + rehashed = 0; + } + + if (dorestart) + restart("Caught SIGINT"); + if (dorehash) + { /* Only on signal, not on oper /rehash */ + ircd_writetune(tunefile); + (void)rehash(&me, &me, 1); + dorehash = 0; + } + if (restart_iauth || timeofday >= nextiarestart) + { + start_iauth(restart_iauth); + restart_iauth = 0; + nextiarestart = timeofday + 15; + } + /* + ** Flush output buffers on all connections now if they + ** have data in them (or at least try to flush) + ** -avalon + */ + flush_connections(me.fd); + +#ifdef DEBUGMODE + checklists(); +#endif + +} + +/* + * 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 IRCDDBG_PATH. + * 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 don't 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(IRCDDBG_PATH, 0); + if ((fd = open(IRCDDBG_PATH,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, IRCDDBG_PATH,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(time(NULL)))); + } + else + local[2] = NULL; +#endif + return; +} + +static void setup_signals() +{ +#if 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); +# if defined(USE_IAUTH) + act.sa_handler = s_slave; + (void)sigaddset(&act.sa_mask, SIGUSR1); + (void)sigaction(SIGUSR1, &act, NULL); + act.sa_handler = SIG_IGN; +# ifdef SA_NOCLDWAIT + act.sa_flags = SA_NOCLDWAIT; +# else + act.sa_flags = 0; +# endif + (void)sigaddset(&act.sa_mask, SIGCHLD); + (void)sigaction(SIGCHLD, &act, NULL); +# endif + +#else /* POSIX_SIGNALS */ + +# ifndef HAVE_RELIABLE_SIGNALS + (void)signal(SIGPIPE, dummy); +# ifdef SIGWINCH + (void)signal(SIGWINCH, dummy); +# endif +# else /* HAVE_RELIABLE_SIGNALS */ +# ifdef SIGWINCH + (void)signal(SIGWINCH, SIG_IGN); +# endif + (void)signal(SIGPIPE, SIG_IGN); +# endif /* HAVE_RELIABLE_SIGNALS */ + (void)signal(SIGALRM, dummy); + (void)signal(SIGHUP, s_rehash); + (void)signal(SIGTERM, s_die); + (void)signal(SIGINT, s_restart); +# if defined(USE_IAUTH) + (void)signal(SIGUSR1, s_slave); + (void)signal(SIGCHLD, SIG_IGN); +# endif +#endif /* POSIX_SIGNAL */ + +#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 +} + +/* + * Called from bigger_hash_table(), s_die(), server_reboot(), + * main(after initializations), grow_history(), rehash(io_loop) signal. + */ +void ircd_writetune(filename) +char *filename; +{ + int fd; + char buf[100]; + + (void)truncate(filename, 0); + if ((fd = open(filename, O_CREAT|O_WRONLY, 0600)) >= 0) + { + (void)sprintf(buf, "%d\n%d\n%d\n%d\n%d\n%d\n", ww_size, + lk_size, _HASHSIZE, _CHANNELHASHSIZE, + _SERVERSIZE, poolsize); + if (write(fd, buf, strlen(buf)) == -1) + sendto_flag(SCH_ERROR, + "Failed (%d) to write tune file: %s.", + errno, mybasename(filename)); + else + sendto_flag(SCH_NOTICE, "Updated %s.", + mybasename(filename)); + close(fd); + } + else + sendto_flag(SCH_ERROR, "Failed (%d) to open tune file: %s.", + errno, mybasename(filename)); +} + +/* + * Called only from main() at startup. + */ +void ircd_readtune(filename) +char *filename; +{ + int fd, t_data[6]; + char buf[100]; + + buf[0] = '\0'; + if ((fd = open(filename, O_RDONLY)) != -1) + { + read(fd, buf, 100); /* no panic if this fails.. */ + if (sscanf(buf, "%d\n%d\n%d\n%d\n%d\n%d\n", &t_data[0], + &t_data[1], &t_data[2], &t_data[3], + &t_data[4], &t_data[5]) != 6) + { + close(fd); + if (bootopt & BOOT_BADTUNE) + return; + else + { + fprintf(stderr, + "ircd tune file %s: bad format\n", + filename); + exit(1); + } + } + + /* + ** Initiate the tune-values after successfully + ** reading the tune-file. + */ + ww_size = t_data[0]; + lk_size = t_data[1]; + _HASHSIZE = t_data[2]; + _CHANNELHASHSIZE = t_data[3]; + _SERVERSIZE = t_data[4]; + poolsize = t_data[5]; + + /* + ** the lock array only grows if the whowas array grows, + ** I don't think it should be initialized with a lower + ** size since it will never adjust unless whowas array does. + */ + if (lk_size < ww_size) + lk_size = ww_size; + close(fd); + } +} diff --git a/ircd/ircd_ext.h b/ircd/ircd_ext.h new file mode 100644 index 0000000..e47b148 --- /dev/null +++ b/ircd/ircd_ext.h @@ -0,0 +1,62 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/ircd_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/ircd.c. + */ + +/* External definitions for global variables. + */ +#ifndef IRCD_C +extern aClient me; +extern aClient *client; +extern istat_t istat; +extern char **myargv; +extern int rehashed; +extern int portnum; +extern char *configfile; +extern int debuglevel; +extern int bootopt; +extern char *debugmode; +extern char *sbrk0; +extern char *tunefile; +extern time_t nextconnect; +extern time_t nextgarbage; +extern time_t nextping; +extern time_t nextdnscheck; +extern time_t nextexpire; +#endif /* IRCD_C */ + +/* External definitions for global functions. + */ +#ifndef IRCD_C +#define EXTERN extern +#else /* IRCD_C */ +#define EXTERN +#endif /* IRCD_C */ +#ifdef PROFIL +EXTERN RETSIGTYPE s_monitor __P((int s)); +#endif /* PROFIL */ +EXTERN RETSIGTYPE s_die __P((int s)); +EXTERN void restart __P((char *mesg)); +EXTERN RETSIGTYPE s_restart __P((int s)); +EXTERN void server_reboot(); +EXTERN void ircd_writetune __P((char *filename)); +EXTERN void ircd_readtune __P((char *filename)); +#undef EXTERN diff --git a/ircd/list.c b/ircd/list.c new file mode 100644 index 0000000..52ba815 --- /dev/null +++ b/ircd/list.c @@ -0,0 +1,685 @@ +/************************************************************************ + * 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 rcsid[] = "@(#)$Id: list.c,v 1.9 1999/07/02 16:49:37 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define LIST_C +#include "s_externs.h" +#undef LIST_C + +char *DefInfo = "*Not On This Net*"; /* constant */ + +#ifdef DEBUGMODE +static struct liststats { + int inuse; +} cloc, crem, users, servs, links, classs, aconfs; + +#endif + +aServer *svrtop = NULL; + +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...")); + sendto_flag(SCH_NOTICE, "Ouch!!! Out of memory..."); + restart("Out of Memory"); +} + +#ifdef DEBUGMODE +void checklists() +{ + aServer *sp; + anUser *up; + + for (sp = svrtop; sp; sp = sp->nexts) + if (sp->bcptr->serv != sp) + Debug((DEBUG_ERROR, "svrtop: %#x->%#x->%#x != %#x", + sp, sp->bcptr, sp->bcptr->serv, sp)); +} +#endif + +/* +** 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; +{ + Reg aClient *cptr = NULL; + Reg 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"); + cptr->info = DefInfo; + if (size == CLIENT_LOCAL_SIZE) + { + cptr->since = cptr->lasttime = cptr->firsttime = timeofday; + cptr->confs = NULL; + cptr->sockhost[0] = '\0'; + cptr->buffer[0] = '\0'; + cptr->authfd = -1; + cptr->auth = cptr->username; + cptr->exitc = EXITC_UNDEF; +#ifdef ZIP_LINKS + cptr->zip = NULL; +#endif + } + return (cptr); +} + +void free_client(cptr) +aClient *cptr; +{ + if (cptr->info != DefInfo) + MyFree(cptr->info); + 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; +{ + Reg 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->flags = 0; + user->channel = NULL; + user->invited = NULL; + user->uwas = NULL; + cptr->user = user; + user->servp = NULL; + user->bcptr = cptr; + if (cptr->next) /* the only cptr->next == NULL is me */ + istat.is_users++; + } + return user; +} + +aServer *make_server(cptr) +aClient *cptr; +{ + Reg aServer *serv = cptr->serv, *sp, *spp = NULL; + + if (!serv) + { + serv = (aServer *)MyMalloc(sizeof(aServer)); +#ifdef DEBUGMODE + servs.inuse++; +#endif + serv->user = NULL; + serv->snum = -1; + *serv->by = '\0'; + *serv->tok = '\0'; + serv->stok = 0; + serv->up = NULL; + serv->refcnt = 1; + serv->nexts = NULL; + cptr->serv = serv; + + for (sp = svrtop; sp; spp = sp, sp = sp->nexts) + if (spp && ((spp->ltok) + 1 < sp->ltok)) + break; + serv->prevs = spp; + if (spp) + { + serv->ltok = spp->ltok + 1; + spp->nexts = serv; + } + else + { /* Me, myself and I alone */ + svrtop = serv; + serv->ltok = 1; + } + + if (sp) + { + serv->nexts = sp; + sp->prevs = serv; + } + serv->bcptr = cptr; + SPRINTF(serv->tok, "%d", serv->ltok); + serv->lastload = 0; + } + return cptr->serv; +} + +/* +** free_user +** Decrease user reference count by one and realease block, +** if count reaches 0 +*/ +void free_user(user, cptr) +Reg anUser *user; +aClient *cptr; +{ + aServer *serv; + + if (--user->refcnt <= 0) + { + if ((serv = user->servp)) + { + user->servp = NULL; /* to avoid some impossible loop */ + free_server(serv, cptr); + } + if (user->away) + { + istat.is_away--; + istat.is_awaymem -= (strlen(user->away) + 1); + MyFree((char *)user->away); + } + /* + * sanity check + */ + if (user->joined || user->refcnt < 0 || + user->invited || user->channel || user->uwas || + user->bcptr) + { + char buf[512]; + /*too many arguments for dumpcore() and sendto_flag()*/ + SPRINTF(buf, "%#x %#x %#x %#x %d %d %#x (%s)", + user, user->invited, user->channel, user->uwas, + user->joined, user->refcnt, + user->bcptr, + (user->bcptr) ? user->bcptr->name :"none"); +#ifdef DEBUGMODE + dumpcore("%#x user (%s!%s@%s) %s", + cptr, cptr ? cptr->name : "<noname>", + user->username, user->host, buf); +#else + sendto_flag(SCH_ERROR, + "* %#x user (%s!%s@%s) %s *", + cptr, cptr ? cptr->name : "<noname>", + user->username, user->host, buf); +#endif + } + MyFree((char *)user); +#ifdef DEBUGMODE + users.inuse--; +#endif + } +} + +void free_server(serv, cptr) +aServer *serv; +aClient *cptr; +{ + if (--serv->refcnt <= 0) + { + if (serv->refcnt < 0 || serv->prevs || serv->nexts || + serv->bcptr || serv->user) + { + char buf[512]; + SPRINTF(buf, "%d %#x %#x %#x %#x (%s)", + serv->refcnt, serv->prevs, serv->nexts, + serv->user, serv->bcptr, + (serv->bcptr) ? serv->bcptr->name : "none"); +#ifdef DEBUGMODE + dumpcore("%#x server %s %s", + cptr, cptr ? cptr->name : "<noname>", buf); + servs.inuse--; +#else + sendto_flag(SCH_ERROR, "* %#x server %s %s *", + cptr, cptr ? cptr->name : "<noname>", buf); +#endif + } + MyFree((char *)serv); + } +} + +/* + * taken the code from ExitOneClient() for this and placed it here. + * - avalon + * remove client **AND** _related structures_ from lists, + * *free* them too. -krys + */ +void remove_client_from_list(cptr) +Reg aClient *cptr; +{ + checklist(); + if (cptr->hopcount == 0) /* is there another way, at this point? */ + istat.is_localc--; + else + istat.is_remc--; + if (cptr->prev) + cptr->prev->next = cptr->next; + else + { + client = cptr->next; + client->prev = NULL; + } + if (cptr->next) + cptr->next->prev = cptr->prev; + + if (cptr->user) + { + istat.is_users--; + /* decrement reference counter, and eventually free it */ + cptr->user->bcptr = NULL; + (void)free_user(cptr->user, cptr); + } + + if (cptr->serv) + { + /* has to be removed from the list of aServer structures */ + if (cptr->serv->nexts) + cptr->serv->nexts->prevs = cptr->serv->prevs; + if (cptr->serv->prevs) + cptr->serv->prevs->nexts = cptr->serv->nexts; + if (svrtop == cptr->serv) + svrtop = cptr->serv->nexts; + cptr->serv->prevs = NULL; + cptr->serv->nexts = NULL; + + if (cptr->serv->user) + { + free_user(cptr->serv->user, cptr); + cptr->serv->user = NULL; + } + + /* decrement reference counter, and eventually free it */ + cptr->serv->bcptr = NULL; + free_server(cptr->serv, cptr); + } + + if (cptr->service) + /* + ** has to be removed from the list of aService structures, + ** no reference counter for services, thus this part of the + ** code can safely be included in free_service() + */ + free_service(cptr); + +#ifdef DEBUGMODE + if (cptr->fd == -2) + cloc.inuse--; + else + crem.inuse--; +#endif + + (void)free_client(cptr); + numclients--; + return; +} + +/* + * move the client aClient struct before its server's + */ +void reorder_client_in_list(cptr) +aClient *cptr; +{ + if (cptr->user == NULL && cptr->service == NULL) + return; + + /* update neighbours */ + if (cptr->next) + cptr->next->prev = cptr->prev; + if (cptr->prev) + cptr->prev->next = cptr->next; + else + client = cptr->next; + + /* re-insert */ + if (cptr->user) + { + cptr->next = cptr->user->servp->bcptr; + cptr->prev = cptr->user->servp->bcptr->prev; +#ifdef DEBUGMODE + sendto_flag(SCH_DEBUG, "%p [%s] moved before server: %p [%s]", + cptr, cptr->name, cptr->user->servp->bcptr, + cptr->user->servp->bcptr->name); +#endif + } + else if (cptr->service) + { + cptr->next = cptr->service->servp->bcptr; + cptr->prev = cptr->service->servp->bcptr->prev; + } + + /* update new neighbours */ + if (cptr->prev) + cptr->prev->next = cptr; + else + client = cptr; + cptr->next->prev = cptr; +} + +/* + * 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. + */ + if (cptr->from == cptr) + istat.is_localc++; + else + istat.is_remc++; + if (cptr->user) + istat.is_users++; + + cptr->next = client; + client = cptr; + + if (cptr->next) + cptr->next->prev = cptr; + + numclients++; + return; +} + +/* + * Look for ptr in the linked listed pointed to by link. + */ +Link *find_user_link(lp, ptr) +Reg Link *lp; +Reg aClient *ptr; +{ + if (ptr) + for (; lp; lp = lp->next) + if (lp->value.cptr == ptr) + return (lp); + return NULL; +} + +Link *find_channel_link(lp, ptr) +Reg Link *lp; +Reg aChannel *ptr; +{ + if (ptr) + for (; lp; lp = lp->next) + if (lp->value.chptr == ptr) + return (lp); + return NULL; +} + +Link *make_link() +{ + Reg Link *lp; + + lp = (Link *)MyMalloc(sizeof(Link)); +#ifdef DEBUGMODE + links.inuse++; +#endif + lp->flags = 0; + return lp; +} + +void free_link(lp) +Reg Link *lp; +{ + MyFree((char *)lp); +#ifdef DEBUGMODE + links.inuse--; +#endif +} + + +aClass *make_class() +{ + Reg aClass *tmp; + + tmp = (aClass *)MyMalloc(sizeof(aClass)); +#ifdef DEBUGMODE + classs.inuse++; +#endif + return tmp; +} + +void free_class(tmp) +Reg aClass *tmp; +{ + MyFree((char *)tmp); +#ifdef DEBUGMODE + classs.inuse--; +#endif +} + +aConfItem *make_conf() +{ + Reg aConfItem *aconf; + + aconf = (struct ConfItem *)MyMalloc(sizeof(aConfItem)); + +#ifdef DEBUGMODE + aconfs.inuse++; +#endif + istat.is_conf++; + istat.is_confmem += sizeof(aConfItem); + + bzero((char *)&aconf->ipnum, sizeof(struct in_addr)); + aconf->clients = aconf->port = 0; + aconf->next = NULL; + aconf->host = aconf->passwd = aconf->name = NULL; + aconf->ping = NULL; + aconf->status = CONF_ILLEGAL; + aconf->pref = -1; + aconf->hold = time(NULL); + Class(aconf) = NULL; + 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; +{ + del_queries((char *)aconf); + + istat.is_conf--; + istat.is_confmem -= aconf->host ? strlen(aconf->host)+1 : 0; + istat.is_confmem -= aconf->passwd ? strlen(aconf->passwd)+1 : 0; + istat.is_confmem -= aconf->name ? strlen(aconf->name)+1 : 0; + istat.is_confmem -= aconf->ping ? sizeof(*aconf->ping) : 0; + istat.is_confmem -= sizeof(aConfItem); + + MyFree(aconf->host); + if (aconf->passwd) + bzero(aconf->passwd, strlen(aconf->passwd)); + if (aconf->ping) + MyFree((char *)aconf->ping); + MyFree(aconf->passwd); + MyFree(aconf->name); + MyFree((char *)aconf); +#ifdef DEBUGMODE + aconfs.inuse--; +#endif + return; +} + +#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 + + +void add_fd(fd, ary) +int fd; +FdAry *ary; +{ + Debug((DEBUG_DEBUG,"add_fd(%d,%#x)", fd, ary)); + if (fd >= 0) + ary->fd[++(ary->highest)] = fd; +} + + +int del_fd(fd, ary) +int fd; +FdAry *ary; +{ + int i; + + Debug((DEBUG_DEBUG,"del_fd(%d,%#x)", fd, ary)); + if ((ary->highest == -1) || (fd < 0)) + return -1; + for (i = 0; i <= ary->highest; i++) + if (ary->fd[i] == fd) + break; + if (i < ary->highest) + { + ary->fd[i] = ary->fd[ary->highest--]; + return 0; + } + else if (i > ary->highest) + return -1; + ary->highest--; + return 0; +} diff --git a/ircd/list2.c b/ircd/list2.c new file mode 100644 index 0000000..17f5ac0 --- /dev/null +++ b/ircd/list2.c @@ -0,0 +1,515 @@ +/************************************************************************ + * 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[] = "@(#)list2.c 1.1 1/22/95 (C) 1988 University of Oulu, \ +Computing Center and Jarkko Oikarinen"; +#endif + +#include "struct.h" +#include "common.h" +#include "sys.h" +#include "h.h" +#ifdef DBMALLOC +#include "malloc.h" +#endif +void free_link __P((Link *)); +Link *make_link __P(()); + +static struct liststats { + int inuse; + int free; +} listc[8]; + +#define LC_CLOC 0 +#define LC_CREM 1 +#define LC_SERV 2 +#define LC_LINK 3 +#define LC_USER 4 +#define LC_CONF 5 +#define LC_CLAS 6 +#define LC_DBUF 7 + +void outofmemory(); + +static aClient *clofree = NULL; +static aClient *crefree = NULL; +static aClass *clfree = NULL; +static aConfItem *cofree = NULL; +static anUser *ufree = NULL; +static Link *lfree = NULL; +static aServer *sfree = NULL; + +int numclients = 0; + +void initlists() +{ + bzero(listc, sizeof(struct liststats)* 7); +} + +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; +{ + Reg aClient *cptr = NULL; + Reg 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 = clofree)) + { + clofree = cptr->next; + listc[LC_CLOC].free--; + Debug((DEBUG_LIST, "make_client(%#x) = %#x", + from, cptr)); + } + } + else if ((cptr = crefree)) + { + crefree = cptr->next; + listc[LC_CREM].free--; + Debug((DEBUG_LIST, "make_client(%#x) = %#x", + from, cptr)); + } + + if (!cptr) + { + if (!(cptr = (aClient *)MyMalloc(size))) + outofmemory(); + else + { + if (size == CLIENT_LOCAL_SIZE) + listc[LC_CLOC].inuse++; + else + listc[LC_CREM].inuse++; + } + } + + bzero((char *)cptr, (int)size); + + /* 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 = time(NULL); + cptr->confs = NULL; + cptr->sockhost[0] = '\0'; + cptr->buffer[0] = '\0'; + cptr->authfd = -1; + } + return (cptr); +} + + +checksanity() +{ + register aClient *c; + register anUser *u; + register aServer *s; + + for (c = client; c; c = c->next) +#ifdef LIST_DEBUG + if ((u = c->user) && (u->bcptr != c)) + dumpcore("c %#x u %#x b %#x", c, u, u->bcptr); + else if ((s = c->serv) && s->bcptr != c) + dumpcore("c %#x s %#x b %#x", c, s, s->bcptr); + else +#endif + if (u && u->refcnt <= 0) + dumpcore("c %#x u %#x r %d", c, u, u->refcnt); +} + + +void free_client(cptr) +aClient *cptr; +{ + Debug((DEBUG_LIST, "free_client(%#x) %d", cptr, cptr->fd)); + if (cptr->fd != -1) + { + bzero((char *)cptr, CLIENT_LOCAL_SIZE); + listc[LC_CLOC].free++; + cptr->next = clofree; + clofree = cptr; + } + else + { + bzero((char *)cptr, CLIENT_REMOTE_SIZE); + listc[LC_CREM].free++; + cptr->next = crefree; + crefree = cptr; + } +} + +/* +** 'make_user' add's an User information block to a client +** if it was not previously allocated. +*/ +anUser *make_user(cptr) +aClient *cptr; +{ + Reg anUser *user; + char c; + + user = cptr->user; + if (!user) + if ((user = ufree)) + { + ufree = user->nextu; + listc[LC_USER].free--; + c = '-'; + } + if (!user) + { + user = (anUser *)MyMalloc(sizeof(anUser)); + listc[LC_USER].inuse++; + c = '='; + } + cptr->user = user; + user->nextu = NULL; + user->away = NULL; + user->refcnt = 1; + user->joined = 0; + user->channel = NULL; + user->invited = NULL; + Debug((DEBUG_LIST, "make_user(%#x) %c %#x %d", + cptr, c, user, user->refcnt)); + user->bcptr = cptr; + return user; +} + +aServer *make_server(cptr) +aClient *cptr; +{ + Reg aServer *serv = cptr->serv; + char c; + + if (!serv) + if ((serv = sfree)) + { + sfree = serv->nexts; + listc[LC_SERV].free--; + c = '-'; + } + if (!serv) + { + serv = (aServer *)MyMalloc(sizeof(aServer)); + listc[LC_SERV].inuse++; + c = '='; + } + serv->user = NULL; + serv->nexts = NULL; + *serv->by = '\0'; + *serv->up = '\0'; + cptr->serv = serv; +#ifdef LIST_DEBUG + serv->bcptr = cptr; +#endif + Debug((DEBUG_LIST, "make_server(%#x) %c %#x", + cptr, c, serv)); + return cptr->serv; +} + +/* +** free_user +** Decrease user reference count by one and realease block, +** if count reaches 0 +*/ +void free_user(user, cptr) +Reg anUser *user; +aClient *cptr; +{ + if (cptr && user->bcptr && (user->bcptr != cptr)) + { + dumpcore("user %#x bcptr %#x cptr %#x", + user, user->bcptr, cptr); + exit(0); + } + user->bcptr = cptr; + user->refcnt--; + Debug((DEBUG_LIST, "free_user(%#x,%#x) %d", + user, cptr, user->refcnt)); + if (user->refcnt <= 0) + { + if (user->away) + (void)MyFree((char *)user->away); + bzero((char *)user, sizeof(*user)); + user->nextu = ufree; + ufree = user; + listc[LC_USER].free++; + } +} + +/* + * taken the code from ExitOneClient() for this and placed it here. + * - avalon + */ +void remove_client_from_list(cptr) +Reg 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 (cptr->user) + { + add_history(cptr); + off_history(cptr); + (void)free_user(cptr->user, cptr); + } + if (cptr->serv) + { + if (cptr->serv->user) + free_user(cptr->serv->user, cptr); + listc[LC_SERV].free++; + cptr->serv->nexts = sfree; + cptr->serv->bcptr = NULL; + sfree = cptr->serv; + } + free_client(cptr); + 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) +Reg Link *lp; +Reg aClient *ptr; +{ + while (lp && ptr) + { + if (lp->value.cptr == ptr) + return (lp); + lp = lp->next; + } + return NULL; +} + +Link *make_link() +{ + Reg Link *lp; + char c; + + if ((lp = lfree)) + { + lfree = lp->next; + listc[LC_LINK].free--; + c = '-'; + } + else + { + lp = (Link *)MyMalloc(sizeof(Link)*3); + bzero((char *)lp+1, sizeof(Link)*2); + lp->next = lp+1; + lp->next->next = lp+2; + lp->next->next->next = lfree; + lfree = lp->next; + listc[LC_LINK].inuse += 3; + listc[LC_LINK].free += 2; + c = '='; + } + Debug((DEBUG_LIST, "make_link() %c %#x", c, lp)); + return lp; +} + +void free_link(lp) +Reg Link *lp; +{ + bzero((char *)lp, sizeof(*lp)); + lp->next = lfree; + lfree = lp; + listc[LC_LINK].free++; + Debug((DEBUG_LIST, "free_link(%#x)", lp)); +} + + +aClass *make_class() +{ + Reg aClass *tmp; + + if ((tmp = clfree)) + { + listc[LC_CLAS].free--; + clfree = tmp->next; + Debug((DEBUG_LIST, "make_class() - %#x", tmp)); + } + else + { + tmp = (aClass *)MyMalloc(sizeof(aClass)); + listc[LC_CLAS].inuse++; + Debug((DEBUG_LIST, "make_class() = %#x", tmp)); + } + return tmp; +} + +void free_class(tmp) +Reg aClass *tmp; +{ + bzero((char *)tmp, sizeof(*tmp)); + tmp->next = clfree; + clfree = tmp; + listc[LC_CLAS].free++; + Debug((DEBUG_LIST, "free_class(%#x)", tmp)); +} + +aConfItem *make_conf() +{ + Reg aConfItem *aconf; + char c; + + if ((aconf = cofree)) + { + cofree = aconf->next; + listc[LC_CONF].free--; + c = '-'; + } + else + { + aconf = (struct ConfItem *)MyMalloc(sizeof(aConfItem)); + listc[LC_CONF].inuse++; + c = '='; + bzero((char *)aconf, sizeof(*aconf)); + } + aconf->next = NULL; + aconf->host = aconf->passwd = aconf->name = NULL; + aconf->status = CONF_ILLEGAL; + Class(aconf) = 0; + Debug((DEBUG_LIST, "make_conf() %c %#x",c , aconf)); + return (aconf); +} + +void free_conf(aconf) +aConfItem *aconf; +{ + MyFree(aconf->host); + if (aconf->passwd) + bzero(aconf->passwd, strlen(aconf->passwd)); + MyFree(aconf->passwd); + MyFree(aconf->name); + bzero((char *)aconf, sizeof(*aconf)); + aconf->next = cofree; + cofree = aconf; + Debug((DEBUG_LIST, "free_conf(%#x)", aconf)); + listc[LC_CONF].free++; + return; +} + +void send_listinfo(cptr, name) +aClient *cptr; +char *name; +{ + static char *labels[] = { "Local", "Remote", "Servs", "Links", + "Users", "Confs", "Classes", "dbufs" }; + static int sizes[] = { CLIENT_LOCAL_SIZE, CLIENT_REMOTE_SIZE, + sizeof(aServer), sizeof(Link), + sizeof(anUser), sizeof(aConfItem), + sizeof(aClass), sizeof(dbufbuf)}; + + struct liststats *ls = listc; + int inuse = 0, mem = 0, tmp = 0, i; + + listc[LC_DBUF].inuse = dbufblocks; + listc[LC_DBUF].free = dbufblocks - dbufalloc; + for (i = 0; i < 8; i++, ls++) + { + tmp = sizes[i] * ls->inuse; + sendto_one(cptr, ":%s NOTICE %s :%s: inuse: %d(%d) free: %d", + me.name, cptr->name, + labels[i], ls->inuse, tmp, ls->free); + inuse += ls->inuse; + mem += tmp; + } + + sendto_one(cptr, ":%s NOTICE %s :Totals: inuse %d %d", + me.name, name, inuse, mem); +} diff --git a/ircd/list_ext.h b/ircd/list_ext.h new file mode 100644 index 0000000..db3f245 --- /dev/null +++ b/ircd/list_ext.h @@ -0,0 +1,66 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/list_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/list.c. + */ + +/* External definitions for global variables. + */ +#ifndef LIST_C +extern anUser *usrtop; +extern aServer *svrtop; +extern int numclients; +extern const char *DefInfo; +#endif /* LIST_C */ + +/* External definitions for global functions. + */ +#ifndef LIST_C +#define EXTERN extern +#else /* LIST_C */ +#define EXTERN +#endif /* LIST_C */ +EXTERN void initlists(); +EXTERN void outofmemory(); +#ifdef DEBUGMODE +EXTERN void checklists(); +EXTERN void send_listinfo __P((aClient *cptr, char *name)); +#endif /* DEBUGMOE */ +EXTERN aClient *make_client __P((aClient *from)); +EXTERN void free_client __P((aClient *cptr)); +EXTERN anUser *make_user __P((aClient *cptr)); +EXTERN aServer *make_server __P((aClient *cptr)); +EXTERN void free_user __P((Reg anUser *user, aClient *cptr)); +EXTERN void free_server __P((aServer *serv, aClient *cptr)); +EXTERN void remove_client_from_list __P((Reg aClient *cptr)); +EXTERN void reorder_client_in_list __P((aClient *cptr)); +EXTERN void add_client_to_list __P((aClient *cptr)); +EXTERN Link *find_user_link __P((Reg Link *lp, Reg aClient *ptr)); +EXTERN Link *find_channel_link __P((Reg Link *lp, Reg aChannel *ptr)); +EXTERN Link *make_link(); +EXTERN void free_link __P((Reg Link *lp)); +EXTERN aClass *make_class(); +EXTERN void free_class __P((Reg aClass *tmp)); +EXTERN aConfItem *make_conf(); +EXTERN void delist_conf __P((aConfItem *aconf)); +EXTERN void free_conf __P((aConfItem *aconf)); +EXTERN void add_fd __P((int fd, FdAry *ary)); +EXTERN int del_fd __P((int fd, FdAry *ary)); +#undef EXTERN diff --git a/ircd/nameser_def.h b/ircd/nameser_def.h new file mode 100644 index 0000000..39c2ce8 --- /dev/null +++ b/ircd/nameser_def.h @@ -0,0 +1,330 @@ +/* + * ++Copyright++ 1983, 1989, 1993 + * - + * Copyright (c) 1983, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * Portions Copyright (c) 1995 by International Business Machines, Inc. + * + * International Business Machines, Inc. (hereinafter called IBM) grants + * permission under its copyrights to use, copy, modify, and distribute this + * Software with or without fee, provided that the above copyright notice and + * all paragraphs of this notice appear in all copies, and that the name of IBM + * not be used in connection with the marketing of any product incorporating + * the Software or modifications thereof, without specific, written prior + * permission. + * + * To the extent it has a right to do so, IBM grants an immunity from suit + * under its patents, if any, for the use, sale or manufacture of products to + * the extent that such products are used for performing Domain Name System + * dynamic updates in TCP/IP networks by means of the Software. No immunity is + * granted for any product per se or for any other function of any product. + * + * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, + * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN + * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. + * --Copyright-- + */ + +/* + * @(#)nameser.h 8.1 (Berkeley) 6/2/93 + * $Id: nameser_def.h,v 1.3 1998/12/13 00:19:03 kalt Exp $ + */ + +/* + * revision information. this is the release date in YYYYMMDD format. + * it can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__BIND > 19931104)". do not + * compare for equality; rather, use it to determine whether your resolver + * is new enough to contain a certain feature. + */ + +#define __BIND 19960801 /* interface version stamp */ + +/* + * Define constants based on rfc883 + */ +#define PACKETSZ 512 /* maximum packet size */ +#define MAXDNAME 1025 /* maximum presentation domain name */ +#define MAXCDNAME 255 /* maximum compressed domain name */ +#define MAXLABEL 63 /* maximum length of domain label */ +#define HFIXEDSZ 12 /* #/bytes of fixed data in header */ +#define QFIXEDSZ 4 /* #/bytes of fixed data in query */ +#define RRFIXEDSZ 10 /* #/bytes of fixed data in r record */ +#define INT32SZ 4 /* for systems without 32-bit ints */ +#define INT16SZ 2 /* for systems without 16-bit ints */ +#define INADDRSZ 4 /* IPv4 T_A */ +#define IN6ADDRSZ 16 /* IPv6 T_AAAA */ + +/* + * Internet nameserver port number + */ +#define NAMESERVER_PORT 53 + +/* + * Currently defined opcodes + */ +#define QUERY 0x0 /* standard query */ +#define IQUERY 0x1 /* inverse query */ +#define STATUS 0x2 /* nameserver status query */ +/*#define xxx 0x3*/ /* 0x3 reserved */ +#define NS_NOTIFY_OP 0x4 /* notify secondary of SOA change */ +/* + * Currently defined response codes + */ +#define NOERROR 0 /* no error */ +#define FORMERR 1 /* format error */ +#define SERVFAIL 2 /* server failure */ +#define NXDOMAIN 3 /* non existent domain */ +#define NOTIMP 4 /* not implemented */ +#define REFUSED 5 /* query refused */ + +/* + * Type values for resources and queries + */ +#define T_A 1 /* host address */ +#define T_NS 2 /* authoritative server */ +#define T_MD 3 /* mail destination */ +#define T_MF 4 /* mail forwarder */ +#define T_CNAME 5 /* canonical name */ +#define T_SOA 6 /* start of authority zone */ +#define T_MB 7 /* mailbox domain name */ +#define T_MG 8 /* mail group member */ +#define T_MR 9 /* mail rename name */ +#define T_NULL 10 /* null resource record */ +#define T_WKS 11 /* well known service */ +#define T_PTR 12 /* domain name pointer */ +#define T_HINFO 13 /* host information */ +#define T_MINFO 14 /* mailbox information */ +#define T_MX 15 /* mail routing information */ +#define T_TXT 16 /* text strings */ +#define T_RP 17 /* responsible person */ +#define T_AFSDB 18 /* AFS cell database */ +#define T_X25 19 /* X_25 calling address */ +#define T_ISDN 20 /* ISDN calling address */ +#define T_RT 21 /* router */ +#define T_NSAP 22 /* NSAP address */ +#define T_NSAP_PTR 23 /* reverse NSAP lookup (deprecated) */ +#define T_SIG 24 /* security signature */ +#define T_KEY 25 /* security key */ +#define T_PX 26 /* X.400 mail mapping */ +#define T_GPOS 27 /* geographical position (withdrawn) */ +#define T_AAAA 28 /* IP6 Address */ +#define T_LOC 29 /* Location Information */ +#define T_NXT 30 /* Next Valid Name in Zone */ +#define T_EID 31 /* Endpoint identifier */ +#define T_NIMLOC 32 /* Nimrod locator */ +#define T_SRV 33 /* Server selection */ +#define T_ATMA 34 /* ATM Address */ +#define T_NAPTR 35 /* Naming Authority PoinTeR */ + /* non standard */ +#define T_UINFO 100 /* user (finger) information */ +#define T_UID 101 /* user ID */ +#define T_GID 102 /* group ID */ +#define T_UNSPEC 103 /* Unspecified format (binary data) */ + /* Query type values which do not appear in resource records */ +#define T_IXFR 251 /* incremental zone transfer */ +#define T_AXFR 252 /* transfer zone of authority */ +#define T_MAILB 253 /* transfer mailbox records */ +#define T_MAILA 254 /* transfer mail agent records */ +#define T_ANY 255 /* wildcard match */ + +/* + * Values for class field + */ + +#define C_IN 1 /* the arpa internet */ +#define C_CHAOS 3 /* for chaos net (MIT) */ +#define C_HS 4 /* for Hesiod name server (MIT) (XXX) */ + /* Query class values which do not appear in resource records */ +#define C_ANY 255 /* wildcard match */ + +/* + * Flags field of the KEY RR rdata + */ +#define KEYFLAG_TYPEMASK 0xC000 /* Mask for "type" bits */ +#define KEYFLAG_TYPE_AUTH_CONF 0x0000 /* Key usable for both */ +#define KEYFLAG_TYPE_CONF_ONLY 0x8000 /* Key usable for confidentiality */ +#define KEYFLAG_TYPE_AUTH_ONLY 0x4000 /* Key usable for authentication */ +#define KEYFLAG_TYPE_NO_KEY 0xC000 /* No key usable for either; no key */ +/* The type bits can also be interpreted independently, as single bits: */ +#define KEYFLAG_NO_AUTH 0x8000 /* Key not usable for authentication */ +#define KEYFLAG_NO_CONF 0x4000 /* Key not usable for confidentiality */ + +#define KEYFLAG_EXPERIMENTAL 0x2000 /* Security is *mandatory* if bit=0 */ +#define KEYFLAG_RESERVED3 0x1000 /* reserved - must be zero */ +#define KEYFLAG_RESERVED4 0x0800 /* reserved - must be zero */ +#define KEYFLAG_USERACCOUNT 0x0400 /* key is assoc. with a user acct */ +#define KEYFLAG_ENTITY 0x0200 /* key is assoc. with entity eg host */ +#define KEYFLAG_ZONEKEY 0x0100 /* key is zone key for the zone named */ +#define KEYFLAG_IPSEC 0x0080 /* key is for IPSEC use (host or user)*/ +#define KEYFLAG_EMAIL 0x0040 /* key is for email (MIME security) */ +#define KEYFLAG_RESERVED10 0x0020 /* reserved - must be zero */ +#define KEYFLAG_RESERVED11 0x0010 /* reserved - must be zero */ +#define KEYFLAG_SIGNATORYMASK 0x000F /* key can sign DNS RR's of same name */ + +#define KEYFLAG_RESERVED_BITMASK ( KEYFLAG_RESERVED3 | \ + KEYFLAG_RESERVED4 | \ + KEYFLAG_RESERVED10| KEYFLAG_RESERVED11) + +/* The Algorithm field of the KEY and SIG RR's is an integer, {1..254} */ +#define ALGORITHM_MD5RSA 1 /* MD5 with RSA */ +#define ALGORITHM_EXPIRE_ONLY 253 /* No alg, no security */ +#define ALGORITHM_PRIVATE_OID 254 /* Key begins with OID indicating alg */ + +/* Signatures */ + /* Size of a mod or exp in bits */ +#define MIN_MD5RSA_KEY_PART_BITS 512 +#define MAX_MD5RSA_KEY_PART_BITS 2552 + /* Total of binary mod and exp, bytes */ +#define MAX_MD5RSA_KEY_BYTES ((MAX_MD5RSA_KEY_PART_BITS+7/8)*2+3) + /* Max length of text sig block */ +#define MAX_KEY_BASE64 (((MAX_MD5RSA_KEY_BYTES+2)/3)*4) + +/* + * Status return codes for T_UNSPEC conversion routines + */ +#define CONV_SUCCESS 0 +#define CONV_OVERFLOW (-1) +#define CONV_BADFMT (-2) +#define CONV_BADCKSUM (-3) +#define CONV_BADBUFLEN (-4) + +/* + * Structure for query header. The order of the fields is machine- and + * compiler-dependent, depending on the byte/bit order and the layout + * of bit fields. We use bit fields only in int variables, as this + * is all ANSI requires. This requires a somewhat confusing rearrangement. + */ + +typedef struct { + unsigned id :16; /* query identification number */ +#if WORDS_BIGENDIAN + /* fields in third byte */ + unsigned qr: 1; /* response flag */ + unsigned opcode: 4; /* purpose of message */ + unsigned aa: 1; /* authoritive answer */ + unsigned tc: 1; /* truncated message */ + unsigned rd: 1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /* recursion available */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad: 1; /* authentic data from named */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned rcode :4; /* response code */ +#else /* WORDS_BIGENDIAN */ + /* fields in third byte */ + unsigned rd :1; /* recursion desired */ + unsigned tc :1; /* truncated message */ + unsigned aa :1; /* authoritive answer */ + unsigned opcode :4; /* purpose of message */ + unsigned qr :1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /* response code */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned ad: 1; /* authentic data from named */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra :1; /* recursion available */ +#endif /* WORDS_BIGENDIAN */ + /* remaining bytes */ + unsigned qdcount :16; /* number of question entries */ + unsigned ancount :16; /* number of answer entries */ + unsigned nscount :16; /* number of authority entries */ + unsigned arcount :16; /* number of resource entries */ +} HEADER; + +/* + * Defines for handling compressed domain names + */ +#define INDIR_MASK 0xc0 + +/* + * Inline versions of get/put short/long. Pointer is advanced. + * + * These macros demonstrate the property of C whereby it can be + * portable or it can be elegant but rarely both. + */ +#define GETSHORT(s, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (s) = ((u_int16_t)t_cp[0] << 8) \ + | ((u_int16_t)t_cp[1]) \ + ; \ + (cp) += INT16SZ; \ +} + +#define GETLONG(l, cp) { \ + register u_char *t_cp = (u_char *)(cp); \ + (l) = ((u_int32_t)t_cp[0] << 24) \ + | ((u_int32_t)t_cp[1] << 16) \ + | ((u_int32_t)t_cp[2] << 8) \ + | ((u_int32_t)t_cp[3]) \ + ; \ + (cp) += INT32SZ; \ +} + +#define PUTSHORT(s, cp) { \ + register u_int16_t t_s = (u_int16_t)(s); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_s >> 8; \ + *t_cp = t_s; \ + (cp) += INT16SZ; \ +} + +#define PUTLONG(l, cp) { \ + register u_int32_t t_l = (u_int32_t)(l); \ + register u_char *t_cp = (u_char *)(cp); \ + *t_cp++ = t_l >> 24; \ + *t_cp++ = t_l >> 16; \ + *t_cp++ = t_l >> 8; \ + *t_cp = t_l; \ + (cp) += INT32SZ; \ +} diff --git a/ircd/res.c b/ircd/res.c new file mode 100644 index 0000000..1be09c7 --- /dev/null +++ b/ircd/res.c @@ -0,0 +1,1697 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/res.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 "os.h" +#include "s_defines.h" +#define RES_C +#include "s_externs.h" +#undef RES_C + +#ifndef lint +static char rcsid[] = "@(#)$Id: res.c,v 1.21 1999/07/02 17:31:17 kalt Exp $"; +#endif + +/* #undef DEBUG /* because there is a lot of debug code in here :-) */ + +static char hostbuf[HOSTLEN+1+100]; /* +100 for INET6 */ +static char dot[] = "."; +static int incache = 0; +static CacheTable hashtable[ARES_CACSIZE]; +static aCache *cachetop = NULL; +static ResRQ *last, *first; + +static void rem_cache __P((aCache *)); +static void rem_request __P((ResRQ *)); +static int do_query_name __P((Link *, char *, ResRQ *)); +static int do_query_number __P((Link *, struct IN_ADDR *, ResRQ *)); +static void resend_query __P((ResRQ *)); +static int proc_answer __P((ResRQ *, HEADER *, char *, char *)); +static int query_name __P((char *, int, int, ResRQ *)); +static aCache *make_cache __P((ResRQ *)), *rem_list __P((aCache *)); +static aCache *find_cache_name __P((char *)); +static aCache *find_cache_number __P((ResRQ *, char *)); +static int add_request __P((ResRQ *)); +static ResRQ *make_request __P((Link *)); +static int send_res_msg __P((char *, int, int)); +static ResRQ *find_id __P((int)); +static int hash_number __P((unsigned char *)); +static void update_list __P((ResRQ *, aCache *)); +static int hash_name __P((char *)); +static int bad_hostname __P((char *, int)); + +static struct cacheinfo { + int ca_adds; + int ca_dels; + int ca_expires; + int ca_lookups; + int ca_na_hits; + int ca_nu_hits; + int ca_updates; +} cainfo; + +static struct resinfo { + int re_errors; + int re_nu_look; + int re_na_look; + int re_replies; + int re_requests; + int re_resends; + int re_sent; + int re_timeouts; + int re_shortttl; + int re_unkrep; +} reinfo; + +int init_resolver(op) +int op; +{ + int ret = 0; + +#ifdef LRAND48 + srand48(time(NULL)); +#endif + if (op & RES_INITLIST) + { + bzero((char *)&reinfo, sizeof(reinfo)); + first = last = NULL; + } + if (op & RES_CALLINIT) + { + ret = ircd_res_init(); + if (!ircd_res.nscount) + { + ircd_res.nscount = 1; +#ifdef INET6 + /* still IPv4 */ + ircd_res.nsaddr_list[0].sin_addr.s_addr = + inet_pton(AF_INET, "127.0.0.1", + &ircd_res.nsaddr_list[0].sin_addr.s_addr); +#else + ircd_res.nsaddr_list[0].sin_addr.s_addr = + inetaddr("127.0.0.1"); +#endif + } + } + + if (op & RES_INITSOCK) + { + int on = 0; + +#ifdef INET6 + /* still IPv4 */ + ret = resfd = socket(AF_INET, SOCK_DGRAM, 0); +#else + ret = resfd = socket(AF_INET, SOCK_DGRAM, 0); +#endif + (void) SETSOCKOPT(ret, SOL_SOCKET, SO_BROADCAST, &on, on); + } +#ifdef DEBUG + if (op & RES_INITDEBG); + ircd_res.options |= RES_DEBUG; +#endif + if (op & RES_INITCACH) + { + bzero((char *)&cainfo, sizeof(cainfo)); + bzero((char *)hashtable, sizeof(hashtable)); + } + if (op == 0) + ret = resfd; + return ret; +} + +static int add_request(new) +ResRQ *new; +{ + if (!new) + return -1; + if (!first) + first = last = new; + else + { + last->next = new; + last = new; + } + new->next = NULL; + reinfo.re_requests++; + return 0; +} + +/* + * remove a request from the list. This must also free any memory that has + * been allocated for temporary storage of DNS results. + */ +static void rem_request(old) +ResRQ *old; +{ + Reg ResRQ **rptr, *r2ptr = NULL; + Reg int i; + Reg char *s; + + if (!old) + return; + for (rptr = &first; *rptr; r2ptr = *rptr, rptr = &(*rptr)->next) + if (*rptr == old) + { + *rptr = old->next; + if (last == old) + last = r2ptr; + break; + } +#ifdef DEBUG + Debug((DEBUG_INFO,"rem_request:Remove %#x at %#x %#x", + old, *rptr, r2ptr)); +#endif + r2ptr = old; + if (r2ptr->he.h_name) + MyFree((char *)r2ptr->he.h_name); + for (i = 0; i < MAXALIASES; i++) + if ((s = r2ptr->he.h_aliases[i])) + MyFree(s); + if (r2ptr->name) + MyFree(r2ptr->name); + MyFree((char *)r2ptr); + + return; +} + +/* + * Create a DNS request record for the server. + */ +static ResRQ *make_request(lp) +Link *lp; +{ + Reg ResRQ *nreq; + + nreq = (ResRQ *)MyMalloc(sizeof(ResRQ)); + bzero((char *)nreq, sizeof(ResRQ)); + nreq->next = NULL; /* where NULL is non-zero ;) */ + nreq->sentat = timeofday; + nreq->retries = 3; + nreq->resend = 1; + nreq->srch = -1; + if (lp) + bcopy((char *)lp, (char *)&nreq->cinfo, sizeof(Link)); + else + bzero((char *)&nreq->cinfo, sizeof(Link)); + nreq->timeout = 4; /* start at 4 and exponential inc. */ + nreq->he.h_addrtype = AFINET; + nreq->he.h_name = NULL; + nreq->he.h_aliases[0] = NULL; + (void)add_request(nreq); + return nreq; +} + +/* + * Remove queries from the list which have been there too long without + * being resolved. + */ +time_t timeout_query_list(now) +time_t now; +{ + Reg ResRQ *rptr, *r2ptr; + Reg time_t next = 0, tout; + aClient *cptr; + + Debug((DEBUG_DNS,"timeout_query_list at %s",myctime(now))); + for (rptr = first; rptr; rptr = r2ptr) + { + r2ptr = rptr->next; + tout = rptr->sentat + rptr->timeout; + if (now >= tout) + if (--rptr->retries <= 0) + { +#ifdef DEBUG + Debug((DEBUG_ERROR,"timeout %x now %d cptr %x", + rptr, now, rptr->cinfo.value.cptr)); +#endif + reinfo.re_timeouts++; + cptr = rptr->cinfo.value.cptr; + switch (rptr->cinfo.flags) + { + case ASYNC_CLIENT : +#if defined(USE_IAUTH) + sendto_iauth("%d d", cptr->fd); +#endif + ClearDNS(cptr); + break; + case ASYNC_CONNECT : + sendto_flag(SCH_ERROR, + "Host %s unknown", + rptr->name); + break; + } + rem_request(rptr); + continue; + } + else + { + rptr->sentat = now; + rptr->timeout += rptr->timeout; + resend_query(rptr); + tout = now + rptr->timeout; +#ifdef DEBUG + Debug((DEBUG_INFO,"r %x now %d retry %d c %x", + rptr, now, rptr->retries, + rptr->cinfo.value.cptr)); +#endif + } + if (!next || tout < next) + next = tout; + } + return (next > now) ? next : (now + AR_TTL); +} + +/* + * del_queries - called by the server to cleanup outstanding queries for + * which there no longer exist clients or conf lines. + */ +void del_queries(cp) +char *cp; +{ + Reg ResRQ *rptr, *r2ptr; + + for (rptr = first; rptr; rptr = r2ptr) + { + r2ptr = rptr->next; + if (cp == rptr->cinfo.value.cp) + rem_request(rptr); + } +} + +/* + * sends msg to all nameservers found in the "ircd_res" structure. + * This should reflect /etc/resolv.conf. We will get responses + * which arent needed but is easier than checking to see if nameserver + * isnt present. Returns number of messages successfully sent to + * nameservers or -1 if no successful sends. + */ +static int send_res_msg(msg, len, rcount) +char *msg; +int len, rcount; +{ + Reg int i; + int sent = 0, max; + + if (!msg) + return -1; + + max = MIN(ircd_res.nscount, rcount); + if (ircd_res.options & RES_PRIMARY) + max = 1; + if (!max) + max = 1; + + for (i = 0; i < max; i++) + { +#ifdef INET6 + /* still IPv4 */ + ircd_res.nsaddr_list[i].sin_family = AF_INET; +#else + ircd_res.nsaddr_list[i].sin_family = AF_INET; +#endif +#ifdef INET6 + if (sendto(resfd, msg, len, 0, + (struct sockaddr *)&(ircd_res.nsaddr_list[i]), + sizeof(struct sockaddr)) == len) +#else + if (sendto(resfd, msg, len, 0, + (struct sockaddr *)&(ircd_res.nsaddr_list[i]), + sizeof(struct sockaddr)) == len) +#endif + + { + reinfo.re_sent++; + sent++; + } + else + Debug((DEBUG_ERROR,"s_r_m:sendto: %d on %d", + errno, resfd)); + } + + return (sent) ? sent : -1; +} + + +/* + * find a dns request id (id is determined by dn_mkquery) + */ +static ResRQ *find_id(id) +int id; +{ + Reg ResRQ *rptr; + + for (rptr = first; rptr; rptr = rptr->next) + if (rptr->id == id) + return rptr; + return NULL; +} + +struct hostent *gethost_byname(name, lp) +char *name; +Link *lp; +{ + Reg aCache *cp; + + reinfo.re_na_look++; + if ((cp = find_cache_name(name))) + return (struct hostent *)&(cp->he); + if (!lp) + return NULL; + (void)do_query_name(lp, name, NULL); + return NULL; +} + +struct hostent *gethost_byaddr(addr, lp) +char *addr; +Link *lp; +{ + aCache *cp; + + reinfo.re_nu_look++; + if ((cp = find_cache_number(NULL, addr))) + return (struct hostent *)&(cp->he); + if (!lp) + return NULL; + (void)do_query_number(lp, (struct IN_ADDR *)addr, NULL); + return NULL; +} + +static int do_query_name(lp, name, rptr) +Link *lp; +char *name; +Reg ResRQ *rptr; +{ + char hname[HOSTLEN+1]; + int len; + + strncpyzt(hname, name, sizeof(hname)); + len = strlen(hname); + + if (rptr && !index(hname, '.') && ircd_res.options & RES_DEFNAMES) + { + (void)strncat(hname, dot, sizeof(hname) - len - 1); + len++; + (void)strncat(hname, ircd_res.defdname, sizeof(hname) - len -1); + } + + /* + * Store the name passed as the one to lookup and generate other host + * names to pass onto the nameserver(s) for lookups. + */ + if (!rptr) + { + rptr = make_request(lp); +#ifdef INET6 + rptr->type = T_AAAA; +#else + rptr->type = T_A; +#endif + rptr->name = (char *)MyMalloc(strlen(name) + 1); + (void)strcpy(rptr->name, name); + } + Debug((DEBUG_DNS,"do_query_name(): %s ", hname)); +#ifdef INET6 + return (query_name(hname, C_IN, T_AAAA, rptr)); +#else + return (query_name(hname, C_IN, T_A, rptr)); +#endif +} + +/* + * Use this to do reverse IP# lookups. + */ +static int do_query_number(lp, numb, rptr) +Link *lp; +struct IN_ADDR *numb; +Reg ResRQ *rptr; +{ + char ipbuf[128]; + Reg u_char *cp; + +#ifdef INET6 + cp = (u_char *)numb->s6_addr; + if (cp[0]==0 && cp[1]==0 && cp[2]==0 && cp[3]==0 && cp[4]==0 && + cp[5]==0 && cp[6]==0 && cp[7]==0 && cp[8]==0 && cp[9]==0 && + ((cp[10]==0 && cp[11]==0) || (cp[10]==0xff && cp[11]==0xff))) + { + (void)sprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.", + (u_int)(cp[15]), (u_int)(cp[14]), + (u_int)(cp[13]), (u_int)(cp[12])); + } + else + { + (void)sprintf(ipbuf, "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.ip6.int.", + (u_int)(cp[15]&0xf), (u_int)(cp[15]>>4), + (u_int)(cp[14]&0xf), (u_int)(cp[14]>>4), + (u_int)(cp[13]&0xf), (u_int)(cp[13]>>4), + (u_int)(cp[12]&0xf), (u_int)(cp[12]>>4), + (u_int)(cp[11]&0xf), (u_int)(cp[11]>>4), + (u_int)(cp[10]&0xf), (u_int)(cp[10]>>4), + (u_int)(cp[9]&0xf), (u_int)(cp[9]>>4), + (u_int)(cp[8]&0xf), (u_int)(cp[8]>>4), + (u_int)(cp[7]&0xf), (u_int)(cp[7]>>4), + (u_int)(cp[6]&0xf), (u_int)(cp[6]>>4), + (u_int)(cp[5]&0xf), (u_int)(cp[5]>>4), + (u_int)(cp[4]&0xf), (u_int)(cp[4]>>4), + (u_int)(cp[3]&0xf), (u_int)(cp[3]>>4), + (u_int)(cp[2]&0xf), (u_int)(cp[2]>>4), + (u_int)(cp[1]&0xf), (u_int)(cp[1]>>4), + (u_int)(cp[0]&0xf), (u_int)(cp[0]>>4)); + } +#else + cp = (u_char *)&numb->s_addr; + (void)sprintf(ipbuf, "%u.%u.%u.%u.in-addr.arpa.", + (u_int)(cp[3]), (u_int)(cp[2]), + (u_int)(cp[1]), (u_int)(cp[0])); +#endif + + if (!rptr) + { + rptr = make_request(lp); + rptr->type = T_PTR; +#ifdef INET6 + bcopy(numb->s6_addr, rptr->addr.s6_addr, IN6ADDRSZ); + bcopy((char *)numb->s6_addr, + (char *)&rptr->he.h_addr, sizeof(struct in6_addr)); +#else + rptr->addr.s_addr = numb->s_addr; + bcopy((char *)&numb->s_addr, + (char *)&rptr->he.h_addr, sizeof(struct in_addr)); +#endif + rptr->he.h_length = sizeof(struct IN_ADDR); + } + return (query_name(ipbuf, C_IN, T_PTR, rptr)); +} + +/* + * generate a query based on class, type and name. + */ +static int query_name(name, class, type, rptr) +char *name; +int class, type; +ResRQ *rptr; +{ + struct timeval tv; + char buf[MAXPACKET]; + int r,s,k = 0; + HEADER *hptr; + + bzero(buf, sizeof(buf)); + r = ircd_res_mkquery(QUERY, name, class, type, NULL, 0, NULL, + (u_char *)buf, sizeof(buf)); + if (r <= 0) + { + h_errno = NO_RECOVERY; + return r; + } + hptr = (HEADER *)buf; +#ifdef LRAND48 + do { + hptr->id = htons(ntohs(hptr->id) + k + lrand48() & 0xffff); +#else + (void) gettimeofday(&tv, NULL); + do { + /* htons/ntohs can be assembler macros, which cannot + be nested. Thus two lines. -Vesa */ + u_short nstmp = ntohs(hptr->id) + k + + (u_short)(tv.tv_usec & 0xffff); + hptr->id = htons(nstmp); +#endif /* LRAND48 */ + k++; + } while (find_id(ntohs(hptr->id))); + rptr->id = ntohs(hptr->id); + rptr->sends++; + s = send_res_msg(buf, r, rptr->sends); + if (s == -1) + { + h_errno = TRY_AGAIN; + return -1; + } + else + rptr->sent += s; + return 0; +} + +static void resend_query(rptr) +ResRQ *rptr; +{ + if (rptr->resend == 0) + return; + reinfo.re_resends++; + switch(rptr->type) + { + case T_PTR: + (void)do_query_number(NULL, &rptr->addr, rptr); + break; +#ifdef INET6 + case T_AAAA: +#endif + case T_A: + (void)do_query_name(NULL, rptr->name, rptr); + break; + default: + break; + } + return; +} + +/* + * process name server reply. + */ +static int proc_answer(rptr, hptr, buf, eob) +ResRQ *rptr; +char *buf, *eob; +HEADER *hptr; +{ + Reg char *cp, **alias; + Reg struct hent *hp; + int class, type, dlen, len, ans = 0, n; + struct IN_ADDR dr, *adr; + + cp = buf + sizeof(HEADER); + hp = (struct hent *)&(rptr->he); + adr = &hp->h_addr; +#ifdef INET6 + while (adr->s6_laddr[0] | adr->s6_laddr[1] | adr->s6_laddr[2] | + adr->s6_laddr[3]) +#else + while (adr->s_addr) +#endif + adr++; + alias = hp->h_aliases; + while (*alias) + alias++; +#if SOLARIS_2 && !defined(__GNUC__) /* brain damaged compiler it seems */ + for (; hptr->qdcount > 0; hptr->qdcount--) +#else + while (hptr->qdcount-- > 0) +#endif + if ((n = __ircd_dn_skipname((u_char *)cp, (u_char *)eob)) == -1) + break; + else + cp += (n + QFIXEDSZ); + /* + * proccess each answer sent to us blech. + */ + while (hptr->ancount-- > 0 && cp && cp < eob) { + n = ircd_dn_expand((u_char *)buf, (u_char *)eob, (u_char *)cp, + hostbuf, sizeof(hostbuf)); + if (n <= 0) + break; + + cp += n; + type = (int)ircd_getshort((u_char *)cp); + cp += 2; /* INT16SZ */ + class = (int)ircd_getshort((u_char *)cp); + cp += 2; /* INT16SZ */ + rptr->ttl = ircd_getlong((u_char *)cp); + cp += 4; /* INT32SZ */ + dlen = (int)ircd_getshort((u_char *)cp); + cp += 2; /* INT16SZ */ + rptr->type = type; + + len = strlen(hostbuf); + /* name server never returns with trailing '.' */ + if (!index(hostbuf,'.') && (ircd_res.options & RES_DEFNAMES)) + { + (void)strcat(hostbuf, dot); + len++; + (void)strncat(hostbuf, ircd_res.defdname, + sizeof(hostbuf) - 1 - len); + len = MIN(len + strlen(ircd_res.defdname), + sizeof(hostbuf) - 1); + } + + switch(type) + { +#ifdef INET6 + case T_AAAA : +#endif + case T_A : +#ifdef INET6 + if (dlen != ((type==T_AAAA) ? sizeof(dr) : + sizeof(struct in_addr))) +#else + if (dlen != sizeof(dr)) +#endif + { + sendto_flag(SCH_ERROR, + "Bad IP length (%d) returned for %s", dlen, + hostbuf); + Debug((DEBUG_DNS, + "Bad IP length (%d) returned for %s", + dlen, hostbuf)); + return -2; + } + hp->h_length = dlen; + if (ans == 1) + hp->h_addrtype = (class == C_IN) ? + AFINET: AF_UNSPEC; +#ifdef INET6 + if (type == T_AAAA) + bcopy(cp, (char *)&dr, dlen); + else { + dr.s6_laddr[0]=dr.s6_laddr[1]=0; + dr.s6_laddr[2]=htonl(0xffff); + bcopy(cp, &dr.s6_laddr[3], INADDRSZ); + } + bcopy(dr.s6_addr, adr->s6_addr, IN6ADDRSZ); +#else + bcopy(cp, (char *)&dr, dlen); + adr->s_addr = dr.s_addr; +#endif +#ifdef INET6 + Debug((DEBUG_INFO,"got ip # %s for %s", + inet_ntop(AF_INET6, (char *)adr, mydummy, + MYDUMMY_SIZE), + hostbuf)); +#else + Debug((DEBUG_INFO,"got ip # %s for %s", + inetntoa((char *)adr), + hostbuf)); +#endif + if (!hp->h_name) + { + hp->h_name =(char *)MyMalloc(len+1); + (void)strcpy(hp->h_name, hostbuf); + } + ans++; + adr++; + cp += dlen; + break; + case T_PTR : + if((n = ircd_dn_expand((u_char *)buf, (u_char *)eob, + (u_char *)cp, hostbuf, + sizeof(hostbuf) )) < 0) + { + cp = NULL; + break; + } + cp += n; + len = strlen(hostbuf); + Debug((DEBUG_INFO, "got host %s (%d vs %d)", + hostbuf, len, strlen(hostbuf))); + if (bad_hostname(hostbuf, len)) + return -1; + /* + * copy the returned hostname into the host name + * or alias field if there is a known hostname + * already. + */ + if (hp->h_name) + { + Debug((DEBUG_INFO, "duplicate PTR ignored")); + } + else + { + hp->h_name = (char *)MyMalloc(len + 1); + (void)strcpy(hp->h_name, hostbuf); + } + ans++; + break; + case T_CNAME : + cp += dlen; + Debug((DEBUG_INFO,"got cname %s",hostbuf)); + if (bad_hostname(hostbuf, len)) + return -1; /* a break would be enough here */ + if (alias >= &(hp->h_aliases[MAXALIASES-1])) + break; + *alias = (char *)MyMalloc(len + 1); + (void)strcpy(*alias++, hostbuf); + *alias = NULL; + ans++; + break; + default : +#ifdef DEBUG + Debug((DEBUG_INFO,"proc_answer: type:%d for:%s", + type,hostbuf)); +#endif + break; + } + } + return ans; +} + +/* + * read a dns reply from the nameserver and process it. + */ +struct hostent *get_res(lp) +char *lp; +{ + static char buf[sizeof(HEADER) + MAXPACKET]; + Reg HEADER *hptr; + Reg ResRQ *rptr = NULL; + aCache *cp = NULL; +#ifdef INET6 + struct sockaddr_in sin; +#else + struct sockaddr_in sin; +#endif + int rc, a, max; + SOCK_LEN_TYPE len = sizeof(sin); + + (void)alarm((unsigned)4); +#ifdef INET6 + rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &len); +#else + rc = recvfrom(resfd, buf, sizeof(buf), 0, (struct sockaddr *)&sin, &len); +#endif + + (void)alarm((unsigned)0); + if (rc <= sizeof(HEADER)) + goto getres_err; + /* + * convert DNS reply reader from Network byte order to CPU byte order. + */ + hptr = (HEADER *)buf; + hptr->id = ntohs(hptr->id); + hptr->ancount = ntohs(hptr->ancount); + hptr->qdcount = ntohs(hptr->qdcount); + hptr->nscount = ntohs(hptr->nscount); + hptr->arcount = ntohs(hptr->arcount); +#ifdef DEBUG + Debug((DEBUG_NOTICE, "get_res:id = %d rcode = %d ancount = %d", + hptr->id, hptr->rcode, hptr->ancount)); +#endif + reinfo.re_replies++; + /* + * response for an id which we have already received an answer for + * just ignore this response. + */ + rptr = find_id(hptr->id); + if (!rptr) + goto getres_err; + /* + * check against possibly fake replies + */ + max = MIN(ircd_res.nscount, rptr->sends); + if (!max) + max = 1; + + for (a = 0; a < max; a++) +#ifdef INET6 + if (!ircd_res.nsaddr_list[a].sin_addr.s_addr || + !bcmp((char *)&sin.sin_addr, + (char *)&ircd_res.nsaddr_list[a].sin_addr, + sizeof(struct in_addr))) +#else + if (!ircd_res.nsaddr_list[a].sin_addr.s_addr || + !bcmp((char *)&sin.sin_addr, + (char *)&ircd_res.nsaddr_list[a].sin_addr, + sizeof(struct in_addr))) +#endif + break; + if (a == max) + { + reinfo.re_unkrep++; + goto getres_err; + } + + if ((hptr->rcode != NOERROR) || (hptr->ancount == 0)) + { + switch (hptr->rcode) + { + case NXDOMAIN: + h_errno = TRY_AGAIN; + break; + case SERVFAIL: + h_errno = TRY_AGAIN; + break; + case NOERROR: + h_errno = NO_DATA; + break; + case FORMERR: + case NOTIMP: + case REFUSED: + default: + h_errno = NO_RECOVERY; + break; + } + reinfo.re_errors++; + /* + ** If a bad error was returned, we stop here and dont send + ** send any more (no retries granted). + */ + if (h_errno != TRY_AGAIN) + { + Debug((DEBUG_DNS, "Fatal DNS error %d for %d", + h_errno, hptr->rcode)); + rptr->resend = 0; + rptr->retries = 0; + } + goto getres_err; + } + a = proc_answer(rptr, hptr, buf, buf+rc); + if (a == -1) { + sendto_flag(SCH_ERROR, "Bad hostname returned from %s for %s", +#ifdef INET6 + inetntop(AF_INET, &sin.sin_addr, mydummy2, + MYDUMMY_SIZE), + inetntop(AF_INET6, rptr->he.h_addr.s6_addr, + mydummy, MYDUMMY_SIZE)); +#else + inetntoa((char *)&sin.sin_addr), + inetntoa((char *)&rptr->he.h_addr)); +#endif +#ifdef INET6 + Debug((DEBUG_DNS, "Bad hostname returned from %s for %s", + inet_ntop(AF_INET, &sin.sin_addr,mydummy2,MYDUMMY_SIZE), + inet_ntop(AF_INET6, rptr->he.h_addr.s6_addr, mydummy, + MYDUMMY_SIZE))); +#else + Debug((DEBUG_DNS, "Bad hostname returned from %s for %s", + inetntoa((char *)&sin.sin_addr), + inetntoa((char *)&rptr->he.h_addr))); +#endif + } +#ifdef DEBUG + Debug((DEBUG_INFO,"get_res:Proc answer = %d",a)); +#endif + if (a > 0 && rptr->type == T_PTR) + { + struct hostent *hp2 = NULL; + + if (BadPtr(rptr->he.h_name)) /* Kludge! 960907/Vesa */ + goto getres_err; + +#ifdef INET6 + Debug((DEBUG_DNS, "relookup %s <-> %s", + rptr->he.h_name, inet_ntop(AF_INET6, + (char *)&rptr->he.h_addr, + mydummy, MYDUMMY_SIZE))); +#else + Debug((DEBUG_DNS, "relookup %s <-> %s", + rptr->he.h_name, inetntoa((char *)&rptr->he.h_addr))); +#endif + /* + * Lookup the 'authoritive' name that we were given for the + * ip#. By using this call rather than regenerating the + * type we automatically gain the use of the cache with no + * extra kludges. + */ + if ((hp2 = gethost_byname(rptr->he.h_name, &rptr->cinfo))) + if (lp) + bcopy((char *)&rptr->cinfo, lp, sizeof(Link)); + /* + * If name wasn't found, a request has been queued and it will + * be the last one queued. This is rather nasty way to keep + * a host alias with the query. -avalon + */ + if (!hp2 && rptr->he.h_aliases[0]) + for (a = 0; rptr->he.h_aliases[a]; a++) + { + Debug((DEBUG_DNS, "Copied CNAME %s for %s", + rptr->he.h_aliases[a], + rptr->he.h_name)); + last->he.h_aliases[a] = rptr->he.h_aliases[a]; + rptr->he.h_aliases[a] = NULL; + } + + rem_request(rptr); + return hp2; + } + + if (a > 0) + { + if (lp) + bcopy((char *)&rptr->cinfo, lp, sizeof(Link)); + cp = make_cache(rptr); +#ifdef DEBUG + Debug((DEBUG_INFO,"get_res:cp=%#x rptr=%#x (made)",cp,rptr)); +#endif + + rem_request(rptr); + } + else + if (!rptr->sent) + rem_request(rptr); + return cp ? (struct hostent *)&cp->he : NULL; + +getres_err: + /* + * Reprocess an error if the nameserver didnt tell us to "TRY_AGAIN". + */ + if (rptr) + { + if (h_errno != TRY_AGAIN) + { + /* + * If we havent tried with the default domain and its + * set, then give it a try next. + */ + if (ircd_res.options & RES_DEFNAMES && ++rptr->srch == 0) + { + rptr->retries = ircd_res.retry; + rptr->sends = 0; + rptr->resend = 1; +#ifdef INET6 +/* Comment out this ifdef to get names like ::ffff:a.b.c.d */ + if(rptr->type == T_AAAA) + query_name(rptr->name, C_IN, T_A, rptr); + Debug((DEBUG_DNS,"getres_err: didn't work with T_AAAA, now also trying with T_A for %s",rptr->name)); +#endif + resend_query(rptr); + } + else + { +#ifdef INET6 +/* Comment out this ifdef to get names like ::ffff:a.b.c.d */ + if(rptr->type == T_AAAA) + query_name(rptr->name, C_IN, T_A, rptr); + Debug((DEBUG_DNS,"getres_err: didn't work with T_AAAA, now also trying with T_A for %s",rptr->name)); +#endif + resend_query(rptr); + } + } + else if (lp) + bcopy((char *)&rptr->cinfo, lp, sizeof(Link)); + } + return (struct hostent *)NULL; +} + +static int hash_number(ip) +Reg u_char *ip; +{ + Reg u_int hashv = 0; + + /* could use loop but slower */ + hashv += (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; +#ifdef INET6 + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; + hashv += hashv + (int)*ip++; +#endif + hashv += hashv + (int)*ip; + hashv %= ARES_CACSIZE; + return (hashv); +} + +static int hash_name(name) +register char *name; +{ + Reg u_int hashv = 0; + + for (; *name && *name != '.'; name++) + hashv += *name; + hashv %= ARES_CACSIZE; + return (hashv); +} + +/* +** Add a new cache item to the queue and hash table. +*/ +static aCache *add_to_cache(ocp) +Reg aCache *ocp; +{ + Reg aCache *cp = NULL; + Reg int hashv; + +#ifdef DEBUG + Debug((DEBUG_INFO, + "add_to_cache:ocp %#x he %#x name %#x addrl %#x 0 %#x", + ocp, &ocp->he, ocp->he.h_name, ocp->he.h_addr_list, + ocp->he.h_addr_list[0])); +#endif + ocp->list_next = cachetop; + cachetop = ocp; + + hashv = hash_name(ocp->he.h_name); + ocp->hname_next = hashtable[hashv].name_list; + hashtable[hashv].name_list = ocp; + + hashv = hash_number((u_char *)ocp->he.h_addr); + ocp->hnum_next = hashtable[hashv].num_list; + hashtable[hashv].num_list = ocp; + +#ifdef DEBUG +#ifdef INET6 + Debug((DEBUG_INFO,"add_to_cache:added %s[%08x%08x%08x%08x] cache %#x.", + ocp->he.h_name, + ((struct in6_addr *)ocp->he.h_addr_list)->s6_laddr[0], + ((struct in6_addr *)ocp->he.h_addr_list)->s6_laddr[1], + ((struct in6_addr *)ocp->he.h_addr_list)->s6_laddr[2], + ((struct in6_addr *)ocp->he.h_addr_list)->s6_laddr[3], ocp)); +#else + Debug((DEBUG_INFO, "add_to_cache:added %s[%08x] cache %#x.", + ocp->he.h_name, ocp->he.h_addr_list[0], ocp)); +#endif + Debug((DEBUG_INFO, + "add_to_cache:h1 %d h2 %x lnext %#x namnext %#x numnext %#x", + hash_name(ocp->he.h_name), hashv, ocp->list_next, + ocp->hname_next, ocp->hnum_next)); +#endif + + /* + * LRU deletion of excessive cache entries. + */ + if (++incache > MAXCACHED) + { + for (cp = cachetop; cp->list_next; cp = cp->list_next) + ; + rem_cache(cp); + } + cainfo.ca_adds++; + + return ocp; +} + +/* +** update_list does not alter the cache structure passed. It is assumed that +** it already contains the correct expire time, if it is a new entry. Old +** entries have the expirey time updated. +*/ +static void update_list(rptr, cachep) +ResRQ *rptr; +aCache *cachep; +{ + Reg aCache **cpp, *cp = cachep; + Reg char *s, *t, **base; + Reg int i, j; + int addrcount; + + /* + ** search for the new cache item in the cache list by hostname. + ** If found, move the entry to the top of the list and return. + */ + cainfo.ca_updates++; + + for (cpp = &cachetop; *cpp; cpp = &((*cpp)->list_next)) + if (cp == *cpp) + break; + if (!*cpp) + return; + *cpp = cp->list_next; + cp->list_next = cachetop; + cachetop = cp; + if (!rptr) + return; + +#ifdef DEBUG + Debug((DEBUG_DEBUG,"u_l:cp %#x na %#x al %#x ad %#x", + cp,cp->he.h_name,cp->he.h_aliases,cp->he.h_addr)); + Debug((DEBUG_DEBUG,"u_l:rptr %#x h_n %#x", rptr, rptr->he.h_name)); +#endif + /* + * Compare the cache entry against the new record. Add any + * previously missing names for this entry. + */ + for (i = 0; cp->he.h_aliases[i]; i++) + ; + addrcount = i; + for (i = 0, s = rptr->he.h_name; s && i < MAXALIASES; + s = rptr->he.h_aliases[i++]) + { + for (j = 0, t = cp->he.h_name; t && j < MAXALIASES; + t = cp->he.h_aliases[j++]) + if (!mycmp(t, s)) + break; + if (!t && j < MAXALIASES-1) + { + base = cp->he.h_aliases; + + addrcount++; + base = (char **)MyRealloc((char *)base, + sizeof(char *) * (addrcount + 1)); + cp->he.h_aliases = base; +#ifdef DEBUG + Debug((DEBUG_DNS,"u_l:add name %s hal %x ac %d", + s, cp->he.h_aliases, addrcount)); +#endif + base[addrcount-1] = mystrdup(s); + base[addrcount] = NULL; + } + } +#ifdef INET6 + for (i = 0; cp->he.h_addr_list[i]; i++) +#else + for (i = 0; cp->he.h_addr_list[i]; i++) +#endif + ; + addrcount = i; + + /* + * Do the same again for IP#'s. + */ +#ifdef INET6 + for (s = (char *)rptr->he.h_addr.S_ADDR; + ((struct IN_ADDR *)s)->S_ADDR; s += sizeof(struct IN_ADDR)) +#else + for (s = (char *)&rptr->he.h_addr.S_ADDR; + ((struct IN_ADDR *)s)->S_ADDR; s += sizeof(struct IN_ADDR)) +#endif + { +#ifdef INET6 + for (i = 0; (t = cp->he.h_addr_list[i]); i++) +#else + for (i = 0; (t = cp->he.h_addr_list[i]); i++) +#endif + if (!bcmp(s, t, sizeof(struct IN_ADDR))) + break; + if (i >= MAXADDRS || addrcount >= MAXADDRS) + break; + /* + * Oh man this is bad...I *HATE* it. -avalon + * + * Whats it do ? Reallocate two arrays, one of pointers + * to "char *" and the other of IP addresses. Contents of + * the IP array *MUST* be preserved and the pointers into + * it recalculated. + */ + if (!t) + { + struct IN_ADDR **ab; + + ab = (struct IN_ADDR **)cp->he.h_addr_list; + addrcount++; + t = (char *)MyRealloc((char *)*ab, + addrcount * sizeof(struct IN_ADDR)); + base = (char **)MyRealloc((char *)ab, + (addrcount + 1) * sizeof(*ab)); + cp->he.h_addr_list = base; +#ifdef DEBUG + Debug((DEBUG_DNS,"u_l:add IP %x hal %x ac %d", + ntohl(((struct IN_ADDR *)s)->S_ADDR), + cp->he.h_addr_list, + addrcount)); +#endif + for (; addrcount; addrcount--) + { + *ab++ = (struct IN_ADDR *)t; + t += sizeof(struct IN_ADDR); + } + *ab = NULL; + bcopy(s, (char *)*--ab, sizeof(struct IN_ADDR)); + } + } + return; +} + +static aCache *find_cache_name(name) +char *name; +{ + Reg aCache *cp; + Reg char *s; + Reg int hashv, i; + + hashv = hash_name(name); + + cp = hashtable[hashv].name_list; +#ifdef DEBUG + Debug((DEBUG_DNS,"find_cache_name:find %s : hashv = %d",name,hashv)); +#endif + + for (; cp; cp = cp->hname_next) + for (i = 0, s = cp->he.h_name; s; s = cp->he.h_aliases[i++]) + if (mycmp(s, name) == 0) + { + cainfo.ca_na_hits++; + update_list(NULL, cp); + return cp; + } + + for (cp = cachetop; cp; cp = cp->list_next) + { + /* + * if no aliases or the hash value matches, we've already + * done this entry and all possiblilities concerning it. + */ + if (!*cp->he.h_aliases) + continue; + if (hashv == hash_name(cp->he.h_name)) + continue; + for (i = 0, s = cp->he.h_aliases[i]; s && i < MAXALIASES; i++) + if (!mycmp(name, s)) { + cainfo.ca_na_hits++; + update_list(NULL, cp); + return cp; + } + } + return NULL; +} + +/* + * find a cache entry by ip# and update its expire time + */ +static aCache *find_cache_number(rptr, numb) +ResRQ *rptr; +char *numb; +{ + Reg aCache *cp; + Reg int hashv,i; +#ifdef DEBUG + struct IN_ADDR *ip = (struct IN_ADDR *)numb; +#endif + + hashv = hash_number((u_char *)numb); + + cp = hashtable[hashv].num_list; +#ifdef DEBUG +#ifdef INET6 + Debug((DEBUG_DNS, + "find_cache_number:find %s[%08x%08x%08x%08x]: hashv = %d", + inet_ntop(AF_INET6, numb,mydummy,MYDUMMY_SIZE), ip->s6_laddr[0], + ip->s6_laddr[1], ip->s6_laddr[2], ip->s6_laddr[3], hashv)); +#else + Debug((DEBUG_DNS,"find_cache_number:find %s[%08x]: hashv = %d", + inetntoa(numb), ntohl(ip->s_addr), hashv)); +#endif +#endif + for (; cp; cp = cp->hnum_next) + { +#ifdef INET6 + for (i = 0; cp->he.h_addr_list[i]; i++) +#else + for (i = 0; cp->he.h_addr_list[i]; i++) +#endif + { + if (!bcmp(cp->he.h_addr_list[i], numb, + sizeof(struct IN_ADDR))) + { + cainfo.ca_nu_hits++; + update_list(rptr, cp); + return cp; + } + } + } + for (cp = cachetop; cp; cp = cp->list_next) + { + if (!cp->he.h_addr_list && !cp->he.h_aliases) + { + cp = rem_list(cp); + continue; + } + /* + * single address entry...would have been done by hashed + * search above... + */ +#ifdef INET6 + if (!cp->he.h_addr_list[1]) +#else + if (!cp->he.h_addr_list[1]) +#endif + continue; + /* + * if the first IP# has the same hashnumber as the IP# we + * are looking for, its been done already. + */ + if (hashv == hash_number((u_char *)cp->he.h_addr_list[0])) + continue; +#ifdef INET6 + for (i = 1; cp->he.h_addr_list[i]; i++) +#else + for (i = 1; cp->he.h_addr_list[i]; i++) +#endif + if (!bcmp(cp->he.h_addr_list[i], numb, + sizeof(struct IN_ADDR))) + { + cainfo.ca_nu_hits++; + update_list(rptr, cp); + return cp; + } + } + return NULL; +} + +static aCache *make_cache(rptr) +ResRQ *rptr; +{ + Reg aCache *cp; + Reg int i, n; + Reg struct hostent *hp; + Reg char *s, **t; + + /* + ** shouldn't happen but it just might... + */ + if (!rptr->he.h_name || !WHOSTENTP(rptr->he.h_addr.S_ADDR)) + return NULL; + /* + ** Make cache entry. First check to see if the cache already exists + ** and if so, return a pointer to it. + */ + for (i = 0; WHOSTENTP(rptr->he.h_addr_list[i].S_ADDR); i++) + if ((cp = find_cache_number(rptr, +#ifdef INET6 + (char *)(rptr->he.h_addr_list[i].S_ADDR)))) +#else + (char *)&(rptr->he.h_addr_list[i].S_ADDR)))) +#endif + return cp; + + /* + ** a matching entry wasnt found in the cache so go and make one up. + */ + cp = (aCache *)MyMalloc(sizeof(aCache)); + bzero((char *)cp, sizeof(aCache)); + hp = &cp->he; + for (i = 0; i < MAXADDRS - 1; i++) + if (!WHOSTENTP(rptr->he.h_addr_list[i].S_ADDR)) + break; + + /* + ** build two arrays, one for IP#'s, another of pointers to them. + */ + t = hp->h_addr_list = (char **)MyMalloc(sizeof(char *) * (i+1)); + bzero((char *)t, sizeof(char *) * (i+1)); + + s = (char *)MyMalloc(sizeof(struct IN_ADDR) * i); + bzero(s, sizeof(struct IN_ADDR) * i); + + for (n = 0; n < i; n++, s += sizeof(struct IN_ADDR)) + { + *t++ = s; + bcopy((char *)&rptr->he.h_addr_list[n], s, + sizeof(struct IN_ADDR)); + } + *t = (char *)NULL; + + /* + ** an array of pointers to CNAMEs. + */ + for (i = 0; i < MAXALIASES - 1; i++) + if (!rptr->he.h_aliases[i]) + break; + i++; + t = hp->h_aliases = (char **)MyMalloc(sizeof(char *) * i); + for (n = 0; n < i; n++, t++) + { + *t = rptr->he.h_aliases[n]; + rptr->he.h_aliases[n] = NULL; + } + + hp->h_addrtype = rptr->he.h_addrtype; + hp->h_length = rptr->he.h_length; + hp->h_name = rptr->he.h_name; + if (rptr->ttl < 600) + { + reinfo.re_shortttl++; + cp->ttl = 600; + } + else + cp->ttl = rptr->ttl; + cp->expireat = timeofday + cp->ttl; + rptr->he.h_name = NULL; +#ifdef DEBUG + Debug((DEBUG_INFO,"make_cache:made cache %#x", cp)); +#endif + return add_to_cache(cp); +} + +/* + * rem_list + */ +static aCache *rem_list(cp) +aCache *cp; +{ + aCache **cpp, *cr = cp->list_next; + + /* + * remove cache entry from linked list + */ + for (cpp = &cachetop; *cpp; cpp = &((*cpp)->list_next)) + if (*cpp == cp) + { + *cpp = cp->list_next; + MyFree((char *)cp); + break; + } + return cr; +} + + +/* + * rem_cache + * delete a cache entry from the cache structures and lists and return + * all memory used for the cache back to the memory pool. + */ +static void rem_cache(ocp) +aCache *ocp; +{ + Reg aCache **cp; + Reg struct hostent *hp = &ocp->he; + Reg int hashv; + Reg aClient *cptr; + +#ifdef DEBUG + Debug((DEBUG_DNS, "rem_cache: ocp %#x hp %#x l_n %#x aliases %#x", + ocp, hp, ocp->list_next, hp->h_aliases)); +#endif + /* + ** Cleanup any references to this structure by destroying the + ** pointer. + */ + for (hashv = highest_fd; hashv >= 0; hashv--) + if ((cptr = local[hashv]) && (cptr->hostp == hp)) + cptr->hostp = NULL; + /* + * remove cache entry from linked list + */ + for (cp = &cachetop; *cp; cp = &((*cp)->list_next)) + if (*cp == ocp) + { + *cp = ocp->list_next; + break; + } + /* + * remove cache entry from hashed name lists + */ + hashv = hash_name(hp->h_name); +#ifdef DEBUG + Debug((DEBUG_DEBUG,"rem_cache: h_name %s hashv %d next %#x first %#x", + hp->h_name, hashv, ocp->hname_next, + hashtable[hashv].name_list)); +#endif + for (cp = &hashtable[hashv].name_list; *cp; cp = &((*cp)->hname_next)) + if (*cp == ocp) + { + *cp = ocp->hname_next; + break; + } + /* + * remove cache entry from hashed number list + */ + hashv = hash_number((u_char *)hp->h_addr); +#ifdef DEBUG +# ifdef INET6 + Debug((DEBUG_DEBUG,"rem_cache: h_addr %s hashv %d next %#x first %#x", + inet_ntop(AF_INET6, hp->h_addr, mydummy, MYDUMMY_SIZE), + hashv, ocp->hnum_next, hashtable[hashv].num_list)); +# else + Debug((DEBUG_DEBUG,"rem_cache: h_addr %s hashv %d next %#x first %#x", + inetntoa(hp->h_addr), + hashv, ocp->hnum_next, hashtable[hashv].num_list)); +# endif +#endif + for (cp = &hashtable[hashv].num_list; *cp; cp = &((*cp)->hnum_next)) + if (*cp == ocp) + { + *cp = ocp->hnum_next; + break; + } + + /* + * free memory used to hold the various host names and the array + * of alias pointers. + */ + if (hp->h_name) + MyFree(hp->h_name); + if (hp->h_aliases) + { + for (hashv = 0; hp->h_aliases[hashv]; hashv++) + MyFree(hp->h_aliases[hashv]); + MyFree((char *)hp->h_aliases); + } + + /* + * free memory used to hold ip numbers and the array of them. + */ + if (hp->h_addr_list) + { + if (*hp->h_addr_list) + MyFree((char *)*hp->h_addr_list); + MyFree((char *)hp->h_addr_list); + } + + MyFree((char *)ocp); + + incache--; + cainfo.ca_dels++; + + return; +} + +/* + * removes entries from the cache which are older than their expirey times. + * returns the time at which the server should next poll the cache. + */ +time_t expire_cache(now) +time_t now; +{ + Reg aCache *cp, *cp2; + Reg time_t next = 0; + + for (cp = cachetop; cp; cp = cp2) + { + cp2 = cp->list_next; + + if (now >= cp->expireat) + { + cainfo.ca_expires++; + rem_cache(cp); + } + else if (!next || next > cp->expireat) + next = cp->expireat; + } + return (next > now) ? next : (now + AR_TTL); +} + +/* + * remove all dns cache entries. + */ +void flush_cache() +{ + Reg aCache *cp; + + while ((cp = cachetop)) + rem_cache(cp); +} + +int m_dns(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aCache *cp; + Reg int i; + + if (parv[1] && *parv[1] == 'l') { + for(cp = cachetop; cp; cp = cp->list_next) + { + sendto_one(sptr, "NOTICE %s :Ex %d ttl %d host %s(%s)", + parv[0], cp->expireat - timeofday, cp->ttl, +#ifdef INET6 + cp->he.h_name, inetntop(AF_INET6, + cp->he.h_addr, + mydummy, + MYDUMMY_SIZE)); +#else + cp->he.h_name, inetntoa(cp->he.h_addr)); +#endif + for (i = 0; cp->he.h_aliases[i]; i++) + sendto_one(sptr,"NOTICE %s : %s = %s (CN)", + parv[0], cp->he.h_name, + cp->he.h_aliases[i]); +#ifdef INET6 + for (i = 1; cp->he.h_addr_list[i]; i++) { +#else + for (i = 1; cp->he.h_addr_list[i]; i++) { +#endif + sendto_one(sptr,"NOTICE %s : %s = %s (IP)", + parv[0], cp->he.h_name, +#ifdef INET6 + inetntop(AF_INET6, + cp->he.h_addr_list[i], + mydummy, MYDUMMY_SIZE)); +#else + inetntoa(cp->he.h_addr_list[i])); +#endif + } + } + return 2; + } + sendto_one(sptr,"NOTICE %s :Ca %d Cd %d Ce %d Cl %d Ch %d:%d Cu %d", + sptr->name, + cainfo.ca_adds, cainfo.ca_dels, cainfo.ca_expires, + cainfo.ca_lookups, + cainfo.ca_na_hits, cainfo.ca_nu_hits, cainfo.ca_updates); + + sendto_one(sptr,"NOTICE %s :Re %d Rl %d/%d Rp %d Rq %d", + sptr->name, reinfo.re_errors, reinfo.re_nu_look, + reinfo.re_na_look, reinfo.re_replies, reinfo.re_requests); + sendto_one(sptr,"NOTICE %s :Ru %d Rsh %d Rs %d(%d) Rt %d", sptr->name, + reinfo.re_unkrep, reinfo.re_shortttl, reinfo.re_sent, + reinfo.re_resends, reinfo.re_timeouts); + return 2; +} + +u_long cres_mem(sptr, nick) +aClient *sptr; +char *nick; +{ + register aCache *c = cachetop; + register struct hostent *h; + register int i; + u_long nm = 0, im = 0, sm = 0, ts = 0; + + for ( ;c ; c = c->list_next) + { + sm += sizeof(*c); + h = &c->he; +#ifdef INET6 + for (i = 0; h->h_addr_list[i]; i++) +#else + for (i = 0; h->h_addr_list[i]; i++) +#endif + { + im += sizeof(char *); + im += sizeof(struct IN_ADDR); + } + im += sizeof(char *); + for (i = 0; h->h_aliases[i]; i++) + { + nm += sizeof(char *); + nm += strlen(h->h_aliases[i]); + } + nm += i - 1; + nm += sizeof(char *); + if (h->h_name) + nm += strlen(h->h_name); + } + ts = ARES_CACSIZE * sizeof(CacheTable); + sendto_one(sptr, ":%s %d %s :RES table %d", + me.name, RPL_STATSDEBUG, nick, ts); + sendto_one(sptr, ":%s %d %s :Structs %d IP storage %d Name storage %d", + me.name, RPL_STATSDEBUG, nick, sm, im, nm); + return ts + sm + im + nm; +} + + +static int bad_hostname(name, len) +char *name; +int len; +{ + char *s, c; + + for (s = name; (c = *s) && len; s++, len--) + if (isspace(c) || (c == 0x7) || (c == ':') || + (c == '*') || (c == '?')) + return -1; + return 0; +} diff --git a/ircd/res_comp.c b/ircd/res_comp.c new file mode 100644 index 0000000..74e517f --- /dev/null +++ b/ircd/res_comp.c @@ -0,0 +1,929 @@ +/* + * ++Copyright++ 1985, 1993 + * - + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id: res_comp.c,v 1.6 1999/03/08 20:51:58 kalt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "os.h" +#include "s_defines.h" +#define RES_COMP_C +#include "s_externs.h" +#undef RES_COMP_C + +static int ns_name_ntop __P((const u_char *, char *, size_t)); +static int ns_name_pton __P((const char *, u_char *, size_t)); +static int ns_name_unpack __P((const u_char *, const u_char *, + const u_char *, u_char *, size_t)); +static int ns_name_pack __P((const u_char *, u_char *, int, + const u_char **, const u_char **)); +static int ns_name_uncompress __P((const u_char *, const u_char *, + const u_char *, char *, size_t)); +static int ns_name_compress __P((const char *, u_char *, size_t, + const u_char **, const u_char **)); +static int ns_name_skip __P((const u_char **, const u_char *)); + +/* + * 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. + */ +int +ircd_dn_expand(msg, eom, src, dst, dstsiz) + const u_char *msg; + const u_char *eom; + const u_char *src; + char *dst; + int dstsiz; +{ + int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz); + + if (n > 0 && dst[0] == '.') + dst[0] = '\0'; + return (n); +} + +/* + * Pack domain name 'exp_dn' in presentation form into 'comp_dn'. + * Return the size of the compressed name or -1. + * 'length' is the size of the array pointed to by 'comp_dn'. + */ +int +ircd_dn_comp(src, dst, dstsiz, dnptrs, lastdnptr) + const char *src; + u_char *dst; + int dstsiz; + u_char **dnptrs; + u_char **lastdnptr; +{ + return (ns_name_compress(src, dst, (size_t)dstsiz, + (const u_char **)dnptrs, + (const u_char **)lastdnptr)); +} + +/* + * Skip over a compressed domain name. Return the size or -1. + */ +int +__ircd_dn_skipname(ptr, eom) + const u_char *ptr; + const u_char *eom; +{ + const u_char *saveptr = ptr; + + if (ns_name_skip(&ptr, eom) == -1) + return (-1); + return (ptr - saveptr); +} + +/* + * Verify that a domain name uses an acceptable character set. + */ + +/* + * Note the conspicuous absence of ctype macros in these definitions. On + * non-ASCII hosts, we can't depend on string literals or ctype macros to + * tell us anything about network-format data. The rest of the BIND system + * is not careful about this, but for some reason, we're doing it right here. + */ +#define PERIOD 0x2e +#define hyphenchar(c) ((c) == 0x2d) +#define bslashchar(c) ((c) == 0x5c) +#define periodchar(c) ((c) == PERIOD) +#define asterchar(c) ((c) == 0x2a) +#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \ + || ((c) >= 0x61 && (c) <= 0x7a)) +#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) + +#define borderchar(c) (alphachar(c) || digitchar(c)) +#define middlechar(c) (borderchar(c) || hyphenchar(c)) +#define domainchar(c) ((c) > 0x20 && (c) < 0x7f) + +#if 0 +/* it seems that we don't need these -krys */ + +int +res_hnok(dn) + const char *dn; +{ + int ppch = '\0', pch = PERIOD, ch = *dn++; + + while (ch != '\0') { + int nch = *dn++; + + if (periodchar(ch)) { + NULL; + } else if (periodchar(pch)) { + if (!borderchar(ch)) + return (0); + } else if (periodchar(nch) || nch == '\0') { + if (!borderchar(ch)) + return (0); + } else { + if (!middlechar(ch)) + return (0); + } + ppch = pch, pch = ch, ch = nch; + } + return (1); +} + +/* + * hostname-like (A, MX, WKS) owners can have "*" as their first label + * but must otherwise be as a host name. + */ +int +res_ownok(dn) + const char *dn; +{ + if (asterchar(dn[0])) { + if (periodchar(dn[1])) + return (res_hnok(dn+2)); + if (dn[1] == '\0') + return (1); + } + return (res_hnok(dn)); +} + +/* + * SOA RNAMEs and RP RNAMEs can have any printable character in their first + * label, but the rest of the name has to look like a host name. + */ +int +res_mailok(dn) + const char *dn; +{ + int ch, escaped = 0; + + /* "." is a valid missing representation */ + if (*dn == '\0') + return(1); + + /* otherwise <label>.<hostname> */ + while ((ch = *dn++) != '\0') { + if (!domainchar(ch)) + return (0); + if (!escaped && periodchar(ch)) + break; + if (escaped) + escaped = 0; + else if (bslashchar(ch)) + escaped = 1; + } + if (periodchar(ch)) + return (res_hnok(dn)); + return(0); +} + +/* + * This function is quite liberal, since RFC 1034's character sets are only + * recommendations. + */ +int +res_dnok(dn) + const char *dn; +{ + int ch; + + while ((ch = *dn++) != '\0') + if (!domainchar(ch)) + return (0); + return (1); +} +#endif + +/* + * Routines to insert/extract short/long's. + */ + +u_int16_t +ircd_getshort(msgp) + register const u_char *msgp; +{ + register u_int16_t u; + + GETSHORT(u, msgp); + return (u); +} + +u_int32_t +ircd_getlong(msgp) + register const u_char *msgp; +{ + register u_int32_t u; + + GETLONG(u, msgp); + return (u); +} + +void +#if __STDC__ +ircd__putshort(register u_int16_t s, register u_char *msgp) /* must match proto */ +#else +ircd__putshort(s, msgp) + register u_int16_t s; + register u_char *msgp; +#endif +{ + PUTSHORT(s, msgp); +} + +void +ircd__putlong(l, msgp) + register u_int32_t l; + register u_char *msgp; +{ + PUTLONG(l, msgp); +} + +/* ++ From BIND 8.1.1. ++ */ +/* + * Copyright (c) 1996 by Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS + * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE + * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/*"Id: ns_name.c,v 1.1 1997/12/13 02:41:13 vixie Exp vixie"*/ + +/*#include "port_before.h"*/ + +/*#include <sys/types.h>*/ + +/*#include <netinet/in.h>*/ +/*#include <arpa/nameser.h>*/ + +/*#include <errno.h>*/ +/*#include <resolv.h>*/ +/*#include <string.h>*/ + +/*#include "port_after.h"*/ + +#define NS_CMPRSFLGS 0xc0 /* Flag bits indicating name compression. */ +#define NS_MAXCDNAME 255 /* maximum compressed domain name */ + +/* Data. */ + +static char digits[] = "0123456789"; + +/* Forward. */ + +static int special __P((int)); +static int printable __P((int)); +static int dn_find __P((const u_char *, const u_char *, + const u_char * const *, + const u_char * const *)); + +/* Public. */ + +/* + * ns_name_ntop(src, dst, dstsiz) + * Convert an encoded domain name to printable ascii as per RFC1035. + * return: + * Number of bytes written to buffer, or -1 (with errno set) + * notes: + * The root is returned as "." + * All other domains are returned in non absolute form + */ +static int +ns_name_ntop(src, dst, dstsiz) + const u_char *src; + char *dst; + size_t dstsiz; +{ + const u_char *cp; + char *dn, *eom; + u_char c; + u_int n; + + cp = src; + dn = dst; + eom = dst + dstsiz; + + while ((n = *cp++) != 0) { + if ((n & NS_CMPRSFLGS) != 0) { + /* Some kind of compression pointer. */ + errno = EMSGSIZE; + return (-1); + } + if (dn != dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn + n >= eom) { + errno = EMSGSIZE; + return (-1); + } + for ((void)NULL; n > 0; n--) { + c = *cp++; + if (special(c)) { + if (dn + 1 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = (char)c; + } else if (!printable(c)) { + if (dn + 3 >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\\'; + *dn++ = digits[c / 100]; + *dn++ = digits[(c % 100) / 10]; + *dn++ = digits[c % 10]; + } else { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = (char)c; + } + } + } + if (dn == dst) { + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '.'; + } + if (dn >= eom) { + errno = EMSGSIZE; + return (-1); + } + *dn++ = '\0'; + return (dn - dst); +} + +/* + * ns_name_pton(src, dst, dstsiz) + * Convert a ascii string into an encoded domain name as per RFC1035. + * return: + * -1 if it fails + * 1 if string was fully qualified + * 0 is string was not fully qualified + * notes: + * Enforces label and domain length limits. + */ + +static int +ns_name_pton(src, dst, dstsiz) + const char *src; + u_char *dst; + size_t dstsiz; +{ + u_char *label, *bp, *eom; + int c, n, escaped; + char *cp; + + escaped = 0; + bp = dst; + eom = dst + dstsiz; + label = bp++; + + while ((c = *src++) != 0) { + if (escaped) { + if ((cp = strchr(digits, c)) != NULL) { + n = (cp - digits) * 100; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits) * 10; + if ((c = *src++) == 0 || + (cp = strchr(digits, c)) == NULL) { + errno = EMSGSIZE; + return (-1); + } + n += (cp - digits); + if (n > 255) { + errno = EMSGSIZE; + return (-1); + } + c = n; + } + escaped = 0; + } else if (c == '\\') { + escaped = 1; + continue; + } else if (c == '.') { + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + /* Fully qualified ? */ + if (*src == '\0') { + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = '\0'; + } + if ((bp - dst) > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + return (1); + } + if (c == 0) { + errno = EMSGSIZE; + return (-1); + } + label = bp++; + continue; + } + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = (u_char)c; + } + c = (bp - label - 1); + if ((c & NS_CMPRSFLGS) != 0) { /* Label too big. */ + errno = EMSGSIZE; + return (-1); + } + if (label >= eom) { + errno = EMSGSIZE; + return (-1); + } + *label = c; + if (c != 0) { + if (bp >= eom) { + errno = EMSGSIZE; + return (-1); + } + *bp++ = 0; + } + if ((bp - dst) > MAXCDNAME) { /* src too big */ + errno = EMSGSIZE; + return (-1); + } + return (0); +} + +/* + * ns_name_unpack(msg, eom, src, dst, dstsiz) + * Unpack a domain name from a message, source may be compressed. + * return: + * -1 if it fails, or consumed octets if it succeeds. + */ +static int +ns_name_unpack(msg, eom, src, dst, dstsiz) + const u_char *msg; + const u_char *eom; + const u_char *src; + u_char *dst; + size_t dstsiz; +{ + const u_char *srcp, *dstlim; + u_char *dstp; + int n, c, len, checked; + + len = -1; + checked = 0; + dstp = dst; + srcp = src; + dstlim = dst + dstsiz; + if (srcp < msg || srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + /* Fetch next label in domain name. */ + while ((n = *srcp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: + /* Limit checks. */ + if (dstp + n + 1 >= dstlim || srcp + n >= eom) { + errno = EMSGSIZE; + return (-1); + } + checked += n + 1; + *dstp++ = n; + memcpy(dstp, srcp, n); + dstp += n; + srcp += n; + break; + + case NS_CMPRSFLGS: + if (srcp >= eom) { + errno = EMSGSIZE; + return (-1); + } + if (len < 0) + len = srcp - src + 1; + srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff)); + if (srcp < msg || srcp >= eom) { /* Out of range. */ + errno = EMSGSIZE; + 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 >= eom - msg) { + errno = EMSGSIZE; + return (-1); + } + break; + + default: + errno = EMSGSIZE; + return (-1); /* flag error */ + } + } + *dstp = '\0'; + if (len < 0) + len = srcp - src; + return (len); +} + +/* + * ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) + * Pack domain name 'domain' into 'comp_dn'. + * return: + * Size of the compressed name, or -1. + * notes: + * 'dnptrs' is an array of pointers to previous compressed names. + * dnptrs[0] is a pointer to the beginning of the message. The array + * ends with NULL. + * 'lastdnptr' is a pointer to the end of the array pointed to + * by 'dnptrs'. + * Side effects: + * The list of pointers in dnptrs is updated 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. + */ +static int +ns_name_pack(src, dst, dstsiz, dnptrs, lastdnptr) + const u_char *src; + u_char *dst; + int dstsiz; + const u_char **dnptrs; + const u_char **lastdnptr; +{ + u_char *dstp; + const u_char **cpp, **lpp, *eob, *msg; + const u_char *srcp; + int n, l; + + srcp = src; + dstp = dst; + eob = dstp + dstsiz; + lpp = cpp = NULL; + if (dnptrs != NULL) { + if ((msg = *dnptrs++) != NULL) { + for (cpp = dnptrs; *cpp != NULL; cpp++) + (void)NULL; + lpp = cpp; /* end of list to search */ + } + } else + msg = NULL; + + /* make sure the domain we are about to add is legal */ + l = 0; + do { + n = *srcp; + if ((n & NS_CMPRSFLGS) != 0) { + errno = EMSGSIZE; + return (-1); + } + l += n + 1; + if (l > MAXCDNAME) { + errno = EMSGSIZE; + return (-1); + } + srcp += n + 1; + } while (n != 0); + + srcp = src; + do { + /* Look to see if we can use pointers. */ + n = *srcp; + if (n != 0 && msg != NULL) { + l = dn_find(srcp, msg, (const u_char * const *)dnptrs, + (const u_char * const *)lpp); + if (l >= 0) { + if (dstp + 1 >= eob) { + errno = EMSGSIZE; + return (-1); + } + *dstp++ = (l >> 8) | NS_CMPRSFLGS; + *dstp++ = l % 256; + return (dstp - dst); + } + /* Not found, save it. */ + if (lastdnptr != NULL && cpp < lastdnptr - 1 && + (dstp - msg) < 0x4000) { + *cpp++ = dstp; + *cpp = NULL; + } + } + /* copy label to buffer */ + if (n & NS_CMPRSFLGS) { /* Should not happen. */ + errno = EMSGSIZE; + return (-1); + } + if (dstp + 1 + n >= eob) { + errno = EMSGSIZE; + return (-1); + } + memcpy(dstp, srcp, n + 1); + srcp += n + 1; + dstp += n + 1; + } while (n != 0); + + if (dstp > eob) { + if (msg != NULL) + *lpp = NULL; + errno = EMSGSIZE; + return (-1); + } + return (dstp - dst); +} + +/* + * ns_name_uncompress(msg, eom, src, dst, dstsiz) + * Expand compressed domain name to presentation format. + * return: + * Number of bytes read out of `src', or -1 (with errno set). + * note: + * Root domain returns as "." not "". + */ +static int +ns_name_uncompress(msg, eom, src, dst, dstsiz) + const u_char *msg; + const u_char *eom; + const u_char *src; + char *dst; + size_t dstsiz; +{ + u_char tmp[NS_MAXCDNAME]; + int n; + + if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1) + return (-1); + if (ns_name_ntop(tmp, dst, dstsiz) == -1) + return (-1); + return (n); +} + +/* + * ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) + * Compress a domain name into wire format, using compression pointers. + * return: + * Number of bytes consumed in `dst' or -1 (with errno set). + * notes: + * 'dnptrs' is an array 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 + * array 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. + */ +static int +ns_name_compress(src, dst, dstsiz, dnptrs, lastdnptr) + const char *src; + u_char *dst; + size_t dstsiz; + const u_char **dnptrs; + const u_char **lastdnptr; +{ + u_char tmp[NS_MAXCDNAME]; + + if (ns_name_pton(src, tmp, sizeof tmp) == -1) + return (-1); + return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr)); +} + +/* + * ns_name_skip(ptrptr, eom) + * Advance *ptrptr to skip over the compressed name it points at. + * return: + * 0 on success, -1 (with errno set) on failure. + */ +static int +ns_name_skip(ptrptr, eom) + const u_char **ptrptr; + const u_char *eom; +{ + const u_char *cp; + u_int n; + + cp = *ptrptr; + while (cp < eom && (n = *cp++) != 0) { + /* Check for indirection. */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + cp += n; + continue; + case NS_CMPRSFLGS: /* indirection */ + cp++; + break; + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + break; + } + if (cp > eom) { + errno = EMSGSIZE; + return (-1); + } + *ptrptr = cp; + return (0); +} + +/* Private. */ + +/* + * special(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this characted special ("in need of quoting") ? + * return: + * boolean. + */ +static int +special(ch) + int ch; +{ + switch (ch) { + case 0x22: /* '"' */ + case 0x2E: /* '.' */ + case 0x3B: /* ';' */ + case 0x5C: /* '\\' */ + /* Special modifiers in zone files. */ + case 0x40: /* '@' */ + case 0x24: /* '$' */ + return (1); + default: + return (0); + } +} + +/* + * printable(ch) + * Thinking in noninternationalized USASCII (per the DNS spec), + * is this character visible and not a space when printed ? + * return: + * boolean. + */ +static int +printable(ch) + int ch; +{ + return (ch > 0x20 && ch < 0x7f); +} + +/* + * Thinking in noninternationalized USASCII (per the DNS spec), + * convert this character to lower case if it's upper case. + */ +static int +mklower(ch) + int ch; +{ + if (ch >= 0x41 && ch <= 0x5A) + return (ch + 0x20); + return (ch); +} + +/* + * dn_find(domain, msg, dnptrs, lastdnptr) + * Search for the counted-label name in an array of compressed names. + * return: + * offset from msg if found, or -1. + * notes: + * dnptrs is the pointer to the first name on the list, + * not the pointer to the start of the message. + */ +static int +dn_find(domain, msg, dnptrs, lastdnptr) + const u_char *domain; + const u_char *msg; + const u_char * const *dnptrs; + const u_char * const *lastdnptr; +{ + const u_char *dn, *cp, *sp; + const u_char * const *cpp; + u_int n; + + for (cpp = dnptrs; cpp < lastdnptr; cpp++) { + dn = domain; + sp = cp = *cpp; + while ((n = *cp++) != 0) { + /* + * check for indirection + */ + switch (n & NS_CMPRSFLGS) { + case 0: /* normal case, n == len */ + if (n != *dn++) + goto next; + for ((void)NULL; n > 0; n--) + if (mklower(*dn++) != mklower(*cp++)) + goto next; + /* Is next root for both ? */ + if (*dn == '\0' && *cp == '\0') + return (sp - msg); + if (*dn) + continue; + goto next; + + case NS_CMPRSFLGS: /* indirection */ + cp = msg + (((n & 0x3f) << 8) | *cp); + break; + + default: /* illegal type */ + errno = EMSGSIZE; + return (-1); + } + } + next: ; + } + errno = ENOENT; + return (-1); +} + +/* -- From BIND 8.1.1. -- */ diff --git a/ircd/res_comp_ext.h b/ircd/res_comp_ext.h new file mode 100644 index 0000000..273bf05 --- /dev/null +++ b/ircd/res_comp_ext.h @@ -0,0 +1,44 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/res_comp_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/res_comp.c. + */ + +/* External definitions for global functions. + */ +#ifndef RES_COMP_C +#define EXTERN extern +#else /* RES_COMP_C */ +#define EXTERN +#endif /* RES_COMP_C */ +EXTERN int ircd_dn_expand __P((const u_char *msg, const u_char *eomorig, + const u_char *comp_dn, char *exp_dn, + int length)); +EXTERN int ircd_dn_comp __P((const char *exp_dn, u_char *comp_dn, int length, + u_char **dnptrs, u_char **lastdnptr)); +EXTERN int __ircd_dn_skipname __P((const u_char *comp_dn, const u_char *eom)); +EXTERN u_int16_t ircd_getshort __P((register const u_char *msgp)); +EXTERN u_int32_t ircd_getlong __P((register const u_char *msgp)); +EXTERN void ircd__putshort __P((register u_int16_t s, register u_char *msgp)); +EXTERN void ircd__putlong __P((register u_int32_t l, register u_char *msgp)); +#ifdef NEXT +EXTERN u_int16_t res_getshort __P((register const u_char *msgp)); +#endif /* NEXT */ +#undef EXTERN diff --git a/ircd/res_def.h b/ircd/res_def.h new file mode 100644 index 0000000..689b36f --- /dev/null +++ b/ircd/res_def.h @@ -0,0 +1,59 @@ +/* + * ircd/res_def.h (C)opyright 1992 Darren Reed. + */ + +#define RES_INITLIST 1 +#define RES_CALLINIT 2 +#define RES_INITSOCK 4 +#define RES_INITDEBG 8 +#define RES_INITCACH 16 + +#define MAXPACKET 1024 +#define MAXALIASES 35 +#define MAXADDRS 35 + +#define AR_TTL 600 /* TTL in seconds for dns cache entries */ + +struct hent { + char *h_name; /* official name of host */ + char *h_aliases[MAXALIASES]; /* alias list */ + int h_addrtype; /* host address type */ + int h_length; /* length of address */ + /* list of addresses from name server */ + struct IN_ADDR h_addr_list[MAXADDRS]; +#define h_addr h_addr_list[0] /* address, for backward compatiblity */ +}; + +typedef struct reslist { + int id; + int sent; /* number of requests sent */ + int srch; + time_t ttl; + char type; + char retries; /* retry counter */ + char sends; /* number of sends (>1 means resent) */ + char resend; /* send flag. 0 == dont resend */ + time_t sentat; + time_t timeout; + struct IN_ADDR addr; + char *name; + struct reslist *next; + Link cinfo; + struct hent he; + } ResRQ; + +typedef struct cache { + time_t expireat; + time_t ttl; + struct hostent he; + struct cache *hname_next, *hnum_next, *list_next; + } aCache; + +typedef struct cachetable { + aCache *num_list; + aCache *name_list; + } CacheTable; + +#define ARES_CACSIZE 101 + +#define MAXCACHED 81 diff --git a/ircd/res_ext.h b/ircd/res_ext.h new file mode 100644 index 0000000..9e4c8eb --- /dev/null +++ b/ircd/res_ext.h @@ -0,0 +1,41 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/res_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/res.c. + */ + +/* External definitions for global functions. + */ +#ifndef RES_C +#define EXTERN extern +#else /* RES_C */ +#define EXTERN +#endif /* RES_C */ +extern int init_resolver __P((int op)); +EXTERN time_t timeout_query_list __P((time_t now)); +EXTERN void del_queries __P((char *cp)); +EXTERN struct hostent *gethost_byname __P((char *name, Link *lp)); +EXTERN struct hostent *gethost_byaddr __P((char *addr, Link *lp)); +EXTERN struct hostent *get_res __P((char *lp)); +EXTERN time_t expire_cache __P((time_t now)); +EXTERN void flush_cache(); +EXTERN int m_dns __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN u_long cres_mem __P((aClient *sptr, char *nick)); +#undef EXTERN diff --git a/ircd/res_init.c b/ircd/res_init.c new file mode 100644 index 0000000..126144a --- /dev/null +++ b/ircd/res_init.c @@ -0,0 +1,642 @@ +/* + * ++Copyright++ 1985, 1989, 1993 + * - + * Copyright (c) 1985, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; +static char rcsid[] = "$Id: res_init.c,v 1.10 1999/01/20 01:33:08 kalt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "os.h" +#include "s_defines.h" +#define RES_INIT_C +#include "s_externs.h" +#undef RES_INIT_C + +/*-------------------------------------- info about "sortlist" -------------- + * Marc Majka 1994/04/16 + * Allan Nathanson 1994/10/29 (BIND 4.9.3.x) + * + * NetInfo resolver configuration directory support. + * + * Allow a NetInfo directory to be created in the hierarchy which + * contains the same information as the resolver configuration file. + * + * - The local domain name is stored as the value of the "domain" property. + * - The Internet address(es) of the name server(s) are stored as values + * of the "nameserver" property. + * - The name server addresses are stored as values of the "nameserver" + * property. + * - The search list for host-name lookup is stored as values of the + * "search" property. + * - The sortlist comprised of IP address netmask pairs are stored as + * values of the "sortlist" property. The IP address and optional netmask + * should be seperated by a slash (/) or ampersand (&) character. + * - Internal resolver variables can be set from the value of the "options" + * property. + */ +#if defined(NEXT) +# define NI_PATH_RESCONF "/locations/resolver" +# define NI_TIMEOUT 10 +static int ircd_netinfo_res_init __P((int *haveenv, int *havesearch)); +#endif + +static void ircd_res_setoptions __P((char *, char *)); + +#ifdef RESOLVSORT +static const char sort_mask[] = "/&"; +#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) +#ifdef INET6 +static u_int32_t ircd_net_mask __P((struct in_addr)); +#else +static u_int32_t ircd_net_mask __P((struct in_addr)); +#endif +#endif + +#if !defined(isascii) /* XXX - could be a function */ +# define isascii(c) (!(c & 0200)) +#endif + +/* + * Resolver state default settings. + */ + +struct __res_state ircd_res +# if defined(__BIND_RES_TEXT) + = { RES_TIMEOUT, } /* Motorola, et al. */ +# endif + ; + +/* + * 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(). + * + * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 + * rather than INADDR_ANY ("0.0.0.0") as the default name server address + * since it was noted that INADDR_ANY actually meant ``the first interface + * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, + * it had to be "up" in order for you to reach your own name server. It + * was later decided that since the recommended practice is to always + * install local static routes through 127.0.0.1 for all your network + * interfaces, that we could solve this problem without a code change. + * + * The configuration file should always be used, since it is the only way + * to specify a default domain. If you are running a server on your local + * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" + * in the configuration file. + * + * Return 0 if completes successfully, -1 on error + */ +int +ircd_res_init() +{ + register FILE *fp; + register char *cp, **pp; + register int n; + char buf[MAXDNAME]; + int nserv = 0; /* number of nameserver records read from file */ + int haveenv = 0; + int havesearch = 0; +#ifdef RESOLVSORT + int nsort = 0; + char *net; +#endif +#ifndef RFC1535 + int dots; +#endif + + /* + * These three fields used to be statically initialized. This made + * it hard to use this code in a shared library. It is necessary, + * now that we're doing dynamic initialization here, that we preserve + * the old semantics: if an application modifies one of these three + * fields of _res before res_init() is called, res_init() will not + * alter them. Of course, if an application is setting them to + * _zero_ before calling res_init(), hoping to override what used + * to be the static default, we can't detect it and unexpected results + * will follow. Zero for any of these fields would make no sense, + * so one can safely assume that the applications were already getting + * unexpected results. + * + * _res.options is tricky since some apps were known to diddle the bits + * before res_init() was first called. We can't replicate that semantic + * with dynamic initialization (they may have turned bits off that are + * set in RES_DEFAULT). Our solution is to declare such applications + * "broken". They could fool us by setting RES_INIT but none do (yet). + */ + if (!ircd_res.retrans) + ircd_res.retrans = RES_TIMEOUT; + if (!ircd_res.retry) + ircd_res.retry = 4; + if (!(ircd_res.options & RES_INIT)) + ircd_res.options = RES_DEFAULT; + + /* + * This one used to initialize implicitly to zero, so unless the app + * has set it to something in particular, we can randomize it now. + */ + if (!ircd_res.id) + ircd_res.id = ircd_res_randomid(); + +/*ifdef INET6 not, because of IPv4 DNS serving */ +#ifdef USELOOPBACK + ircd_res.nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); +#else + ircd_res.nsaddr.sin_addr.s_addr = INADDR_ANY; +#endif + ircd_res.nsaddr.sin_family = AF_INET; + ircd_res.nsaddr.sin_port = htons(NAMESERVER_PORT); + ircd_res.nscount = 1; + ircd_res.ndots = 1; + ircd_res.pfcode = 0; + + /* Allow user to override the local domain definition */ + if ((cp = getenv("LOCALDOMAIN")) != NULL) { + strncpyzt(ircd_res.defdname, cp, sizeof(ircd_res.defdname)); + haveenv++; + + /* + * Set search list to be blank-separated strings + * from rest of env value. Permits users of LOCALDOMAIN + * to still have a search list, and anyone to set the + * one that they want to use as an individual (even more + * important now that the rfc1535 stuff restricts searches) + */ + cp = ircd_res.defdname; + pp = ircd_res.dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < ircd_res.dnsrch + MAXDNSRCH; cp++) { + if (*cp == '\n') /* silly backwards compat */ + break; + else if (*cp == ' ' || *cp == '\t') { + *cp = 0; + n = 1; + } else if (n) { + *pp++ = cp; + n = 0; + havesearch = 1; + } + } + /* null terminate last domain if there are excess */ + while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') + cp++; + *cp = '\0'; + *pp++ = 0; + } + +#define MATCH(line, name) \ + (!strncmp(line, name, sizeof(name) - 1) && \ + (line[sizeof(name) - 1] == ' ' || \ + line[sizeof(name) - 1] == '\t')) + +#ifdef NEXT + if (ircd_netinfo_res_init(&haveenv, &havesearch) == 0) +#endif + if ((fp = fopen(IRC_RESCONF, "r")) != NULL) { + /* read the config file */ + while (fgets(buf, sizeof(buf), fp) != NULL) { + /* skip comments */ + if (*buf == ';' || *buf == '#') + continue; + /* read default domain name */ + if (MATCH(buf, "domain")) { + if (haveenv) /* skip if have from environ */ + continue; + cp = buf + sizeof("domain") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpyzt(ircd_res.defdname, cp, sizeof(ircd_res.defdname)); + if ((cp = strpbrk(ircd_res.defdname, " \t\n")) != NULL) + *cp = '\0'; + havesearch = 0; + continue; + } + /* set search list */ + if (MATCH(buf, "search")) { + if (haveenv) /* skip if have from environ */ + continue; + cp = buf + sizeof("search") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp == '\0') || (*cp == '\n')) + continue; + strncpyzt(ircd_res.defdname, cp, sizeof(ircd_res.defdname)); + if ((cp = strchr(ircd_res.defdname, '\n')) != NULL) + *cp = '\0'; + /* + * Set search list to be blank-separated strings + * on rest of line. + */ + cp = ircd_res.defdname; + pp = ircd_res.dnsrch; + *pp++ = cp; + for (n = 0; *cp && pp < ircd_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 (MATCH(buf, "nameserver") && nserv < MAXNS) { + struct in_addr a; + + cp = buf + sizeof("nameserver") - 1; + while (*cp == ' ' || *cp == '\t') + cp++; + if ((*cp != '\0') && (*cp != '\n') && inetaton(cp, &a)) { + ircd_res.nsaddr_list[nserv].sin_addr = a; + ircd_res.nsaddr_list[nserv].sin_family = AF_INET; + ircd_res.nsaddr_list[nserv].sin_port = + htons(NAMESERVER_PORT); + nserv++; + } + continue; + } +#ifdef RESOLVSORT + if (MATCH(buf, "sortlist")) { + struct in_addr a; + + cp = buf + sizeof("sortlist") - 1; + while (nsort < MAXRESOLVSORT) { + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp == '\0' || *cp == '\n' || *cp == ';') + break; + net = cp; + while (*cp && !ISSORTMASK(*cp) && *cp != ';' && + isascii(*cp) && !isspace(*cp)) + cp++; + n = *cp; + *cp = 0; + if (inetaton(net, &a)) { + ircd_res.sort_list[nsort].addr = a; + if (ISSORTMASK(n)) { + *cp++ = n; + net = cp; + while (*cp && *cp != ';' && + isascii(*cp) && !isspace(*cp)) + cp++; + n = *cp; + *cp = 0; + if (inetaton(net, &a)) { + ircd_res.sort_list[nsort].mask = a.s_addr; + } else { + ircd_res.sort_list[nsort].mask = + ircd_net_mask(ircd_res.sort_list[nsort].addr); + } + } else { + ircd_res.sort_list[nsort].mask = + ircd_net_mask(ircd_res.sort_list[nsort].addr); + } + nsort++; + } + *cp = n; + } + continue; + } +#endif + if (MATCH(buf, "options")) { + ircd_res_setoptions(buf + sizeof("options") - 1, "conf"); + continue; + } + } + if (nserv > 1) + ircd_res.nscount = nserv; +#ifdef RESOLVSORT + ircd_res.nsort = nsort; +#endif + (void) fclose(fp); + } + if (ircd_res.defdname[0] == 0 && + gethostname(buf, sizeof(ircd_res.defdname) - 1) == 0 && + (cp = strchr(buf, '.')) != NULL) + strcpy(ircd_res.defdname, cp + 1); + + /* find components of local domain that might be searched */ + if (havesearch == 0) { + pp = ircd_res.dnsrch; + *pp++ = ircd_res.defdname; + *pp = NULL; + +#ifndef RFC1535 + dots = 0; + for (cp = ircd_res.defdname; *cp; cp++) + dots += (*cp == '.'); + + cp = ircd_res.defdname; + while (pp < ircd_res.dnsrch + MAXDFLSRCH) { + if (dots < LOCALDOMAINPARTS) + break; + cp = strchr(cp, '.') + 1; /* we know there is one */ + *pp++ = cp; + dots--; + } + *pp = NULL; +#ifdef DEBUG + if (ircd_res.options & RES_DEBUG) { + printf(";; res_init()... default dnsrch list:\n"); + for (pp = ircd_res.dnsrch; *pp; pp++) + printf(";;\t%s\n", *pp); + printf(";;\t..END..\n"); + } +#endif /* DEBUG */ +#endif /* !RFC1535 */ + } + + if ((cp = getenv("RES_OPTIONS")) != NULL) + ircd_res_setoptions(cp, "env"); + ircd_res.options |= RES_INIT; + return (0); +} + +static void +ircd_res_setoptions(options, source) + char *options, *source; +{ + char *cp = options; + int i; + +#ifdef DEBUG + if (ircd_res.options & RES_DEBUG) + printf(";; ircd_res_setoptions(\"%s\", \"%s\")...\n", + options, source); +#endif + while (*cp) { + /* skip leading and inner runs of spaces */ + while (*cp == ' ' || *cp == '\t') + cp++; + /* search for and process individual options */ + if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { + i = atoi(cp + sizeof("ndots:") - 1); + if (i <= RES_MAXNDOTS) + ircd_res.ndots = i; + else + ircd_res.ndots = RES_MAXNDOTS; +#ifdef DEBUG + if (ircd_res.options & RES_DEBUG) + printf(";;\tndots=%d\n", ircd_res.ndots); +#endif + } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { +#ifdef DEBUG + if (!(ircd_res.options & RES_DEBUG)) { + printf(";; ircd_res_setoptions(\"%s\", \"%s\")..\n", + options, source); + ircd_res.options |= RES_DEBUG; + } + printf(";;\tdebug\n"); +#endif + } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { + ircd_res.options |= RES_USE_INET6; + } else { + /* XXX - print a warning here? */ + } + /* skip to next run of spaces */ + while (*cp && *cp != ' ' && *cp != '\t') + cp++; + } +} + +#ifdef RESOLVSORT +/* XXX - should really support CIDR which means explicit masks always. */ +static u_int32_t +ircd_net_mask(in) /* XXX - should really use system's version of this */ + struct in_addr in; +{ + register u_int32_t i = ntohl(in.s_addr); + + if (IN_CLASSA(i)) + return (htonl(IN_CLASSA_NET)); + else if (IN_CLASSB(i)) + return (htonl(IN_CLASSB_NET)); + return (htonl(IN_CLASSC_NET)); +} +#endif + +#ifdef NEXT +static int +ircd_netinfo_res_init(haveenv, havesearch) + int *haveenv; + int *havesearch; +{ + register int n; + void *domain, *parent; + ni_id dir; + ni_status status; + ni_namelist nl; + int nserv = 0; +#ifdef RESOLVSORT + int nsort = 0; +#endif + + status = ni_open(NULL, ".", &domain); + if (status == NI_OK) { + ni_setreadtimeout(domain, NI_TIMEOUT); + ni_setabort(domain, 1); + + /* climb the NetInfo hierarchy to find a resolver directory */ + while (status == NI_OK) { + status = ni_pathsearch(domain, &dir, NI_PATH_RESCONF); + if (status == NI_OK) { + /* found a resolver directory */ + + if (*haveenv == 0) { + /* get the default domain name */ + status = ni_lookupprop(domain, &dir, "domain", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + (void)strncpy(ircd_res.defdname, + nl.ni_namelist_val[0], + sizeof(ircd_res.defdname) - 1); + ircd_res.defdname[sizeof(ircd_res.defdname) - 1] = '\0'; + ni_namelist_free(&nl); + *havesearch = 0; + } + + /* get search list */ + status = ni_lookupprop(domain, &dir, "search", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + (void)strncpy(ircd_res.defdname, + nl.ni_namelist_val[0], + sizeof(ircd_res.defdname) - 1); + ircd_res.defdname[sizeof(ircd_res.defdname) - 1] = '\0'; + /* copy */ + for (n = 0; + n < nl.ni_namelist_len && n < MAXDNSRCH; + n++) { + /* duplicate up to MAXDNSRCH servers */ + char *cp = nl.ni_namelist_val[n]; + ircd_res.dnsrch[n] = + strcpy((char *)malloc(strlen(cp) + 1), cp); + } + ni_namelist_free(&nl); + *havesearch = 1; + } + } + + /* get list of nameservers */ + status = ni_lookupprop(domain, &dir, "nameserver", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + /* copy up to MAXNS servers */ + for (n = 0; + n < nl.ni_namelist_len && nserv < MAXNS; + n++) { + struct in_addr a; + + if (inetaton(nl.ni_namelist_val[n], &a)) { + ircd_res.nsaddr_list[nserv].sin_addr = a; + ircd_res.nsaddr_list[nserv].sin_family = AF_INET; + ircd_res.nsaddr_list[nserv].sin_port = + htons(NAMESERVER_PORT); + nserv++; + } + } + ni_namelist_free(&nl); + } + + if (nserv > 1) + ircd_res.nscount = nserv; + +#ifdef RESOLVSORT + /* get sort order */ + status = ni_lookupprop(domain, &dir, "sortlist", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + + /* copy up to MAXRESOLVSORT address/netmask pairs */ + for (n = 0; + n < nl.ni_namelist_len && nsort < MAXRESOLVSORT; + n++) { + char ch; + char *cp; + const char *sp; + struct in_addr a; + + cp = NULL; + for (sp = sort_mask; *sp; sp++) { + char *cp1; + cp1 = strchr(nl.ni_namelist_val[n], *sp); + if (cp && cp1) + cp = (cp < cp1)? cp : cp1; + else if (cp1) + cp = cp1; + } + if (cp != NULL) { + ch = *cp; + *cp = '\0'; + break; + } + if (inetaton(nl.ni_namelist_val[n], &a)) { + ircd_res.sort_list[nsort].addr = a; + if (*cp && ISSORTMASK(ch)) { + *cp++ = ch; + if (inetaton(cp, &a)) { + ircd_res.sort_list[nsort].mask = a.s_addr; + } else { + ircd_res.sort_list[nsort].mask = + ircd_net_mask(ircd_res.sort_list[nsort].addr); + } + } else { + ircd_res.sort_list[nsort].mask = + ircd_net_mask(ircd_res.sort_list[nsort].addr); + } + nsort++; + } + } + ni_namelist_free(&nl); + } + + ircd_res.nsort = nsort; +#endif + + /* get resolver options */ + status = ni_lookupprop(domain, &dir, "options", &nl); + if (status == NI_OK && nl.ni_namelist_len > 0) { + ircd_res_setoptions(nl.ni_namelist_val[0], "conf"); + ni_namelist_free(&nl); + } + + ni_free(domain); + return(1); /* using DNS configuration from NetInfo */ + } + + status = ni_open(domain, "..", &parent); + ni_free(domain); + if (status == NI_OK) + domain = parent; + } + } + return(0); /* if not using DNS configuration from NetInfo */ +} +#endif /* NEXT */ + +u_int +ircd_res_randomid() +{ + struct timeval now; + + gettimeofday(&now, NULL); + return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); +} diff --git a/ircd/res_init_ext.h b/ircd/res_init_ext.h new file mode 100644 index 0000000..8537269 --- /dev/null +++ b/ircd/res_init_ext.h @@ -0,0 +1,39 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/res_init_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/res_init.c. + */ + +/* External definitions for global variables. + */ +#ifndef RES_INIT_C +extern struct __res_state ircd_res; +#endif /* RES_INIT_C */ + +/* External definitions for global functions. + */ +#ifndef RES_INIT_C +#define EXTERN extern +#else /* RES_INIT_C */ +#define EXTERN +#endif /* RES_INIT_C */ +EXTERN int ircd_res_init(); +EXTERN u_int ircd_res_randomid(); +#undef EXTERN diff --git a/ircd/res_mkquery.c b/ircd/res_mkquery.c new file mode 100644 index 0000000..a0fb2fc --- /dev/null +++ b/ircd/res_mkquery.c @@ -0,0 +1,178 @@ +/* + * ++Copyright++ 1985, 1993 + * - + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93"; +static char rcsid[] = "$Id: res_mkquery.c,v 1.4 1997/09/03 17:45:55 kalt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include "os.h" +#include "s_defines.h" +#define RES_MKQUERY_C +#include "s_externs.h" +#undef RES_MKQUERY_C + +/* + * Form all types of queries. + * Returns the size of the result or -1. + */ +int +ircd_res_mkquery(op, dname, class, type, data, datalen, newrr_in, buf, buflen) + int op; /* opcode of query */ + const char *dname; /* domain name */ + int class, type; /* class and type of query */ + const u_char *data; /* resource record data */ + int datalen; /* length of data */ + const u_char *newrr_in; /* new rr for modify or append */ + u_char *buf; /* buffer to put query */ + int buflen; /* size of buffer */ +{ + register HEADER *hp; + register u_char *cp; + register int n; + u_char *dnptrs[20], **dpp, **lastdnptr; + + if ((ircd_res.options & RES_INIT) == 0 && ircd_res_init() == -1) { + h_errno = NETDB_INTERNAL; + return (-1); + } +#ifdef DEBUG + if (ircd_res.options & RES_DEBUG) + printf(";; res_mkquery(%d, %s, %d, %d)\n", + op, dname, class, type); +#endif + /* + * Initialize header fields. + */ + if ((buf == NULL) || (buflen < HFIXEDSZ)) + return (-1); + bzero(buf, HFIXEDSZ); + hp = (HEADER *) buf; + hp->id = htons(++ircd_res.id); + hp->opcode = op; + hp->rd = (ircd_res.options & RES_RECURSE) != 0; + hp->rcode = NOERROR; + cp = buf + HFIXEDSZ; + buflen -= HFIXEDSZ; + dpp = dnptrs; + *dpp++ = buf; + *dpp++ = NULL; + lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0]; + /* + * perform opcode specific processing + */ + switch (op) { + case QUERY: /*FALLTHROUGH*/ + case NS_NOTIFY_OP: + if ((buflen -= QFIXEDSZ) < 0) + return (-1); + if ((n = ircd_dn_comp(dname, cp, buflen, dnptrs, lastdnptr)) < 0) + return (-1); + cp += n; + buflen -= n; + ircd__putshort(type, cp); + cp += INT16SZ; + ircd__putshort(class, cp); + cp += INT16SZ; + hp->qdcount = htons(1); + if (op == QUERY || data == NULL) + break; + /* + * Make an additional record for completion domain. + */ + buflen -= RRFIXEDSZ; + n = ircd_dn_comp((char *)data, cp, buflen, dnptrs, lastdnptr); + if (n < 0) + return (-1); + cp += n; + buflen -= n; + ircd__putshort(T_NULL, cp); + cp += INT16SZ; + ircd__putshort(class, cp); + cp += INT16SZ; + ircd__putlong(0, cp); + cp += INT32SZ; + ircd__putshort(0, cp); + cp += INT16SZ; + hp->arcount = htons(1); + break; + + case IQUERY: + /* + * Initialize answer section + */ + if (buflen < 1 + RRFIXEDSZ + datalen) + return (-1); + *cp++ = '\0'; /* no domain name */ + ircd__putshort(type, cp); + cp += INT16SZ; + ircd__putshort(class, cp); + cp += INT16SZ; + ircd__putlong(0, cp); + cp += INT32SZ; + ircd__putshort(datalen, cp); + cp += INT16SZ; + if (datalen) { + bcopy(data, cp, datalen); + cp += datalen; + } + hp->ancount = htons(1); + break; + + default: + return (-1); + } + return (cp - buf); +} diff --git a/ircd/res_mkquery_ext.h b/ircd/res_mkquery_ext.h new file mode 100644 index 0000000..7441ead --- /dev/null +++ b/ircd/res_mkquery_ext.h @@ -0,0 +1,35 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/res_mkquery_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/res_mkquery.c. + */ + +/* External definitions for global functions. + */ +#ifndef RES_MKQUERY_C +#define EXTERN extern +#else /* RES_MKQUERY_C */ +#define EXTERN +#endif /* RES_MKQUERY_C */ +EXTERN int ircd_res_mkquery __P((int op, const char *dname, int class, + int type, const u_char *data, int datalen, + const u_char *newrr_in, u_char *buf, + int buflen)); +#undef EXTERN diff --git a/ircd/resolv_def.h b/ircd/resolv_def.h new file mode 100644 index 0000000..3cc74eb --- /dev/null +++ b/ircd/resolv_def.h @@ -0,0 +1,220 @@ +/* + * ++Copyright++ 1983, 1987, 1989, 1993 + * - + * Copyright (c) 1983, 1987, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * - + * Portions Copyright (c) 1993 by Digital Equipment Corporation. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies, and that + * the name of Digital Equipment Corporation not be used in advertising or + * publicity pertaining to distribution of the document or software without + * specific, written prior permission. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT + * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR + * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS + * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + * - + * --Copyright-- + */ + +/* + * @(#)resolv.h 8.1 (Berkeley) 6/2/93 + * $Id: resolv_def.h,v 1.5 1999/01/20 01:33:08 kalt Exp $ + */ + +/* + * Revision information. This is the release date in YYYYMMDD format. + * It can change every day so the right thing to do with it is use it + * in preprocessor commands such as "#if (__RES > 19931104)". Do not + * compare for equality; rather, use it to determine whether your resolver + * is new enough to contain a certain feature. + */ + +#define __RES 19960801 + +/* + * Global defines and variables for resolver stub. + */ +#define MAXNS 3 /* max # name servers we'll track */ +#define MAXDFLSRCH 3 /* # default domain levels to try */ +#define MAXDNSRCH 6 /* max # domains in search path */ +#define LOCALDOMAINPARTS 2 /* min levels in name that is "local" */ + +#define RES_TIMEOUT 5 /* min. seconds between retries */ +#define MAXRESOLVSORT 10 /* number of net to sort on */ +#define RES_MAXNDOTS 15 /* should reflect bit field size */ + +struct __res_state { + int retrans; /* retransmition time interval */ + int retry; /* number of times to retransmit */ + u_long options; /* option flags - see below. */ + int nscount; /* number of name servers */ + struct sockaddr_in + nsaddr_list[MAXNS]; /* address of name server */ +#define nsaddr nsaddr_list[0] /* for backward compatibility */ + u_short id; /* current message id */ + char *dnsrch[MAXDNSRCH+1]; /* components of domain to search */ + char defdname[256]; /* default domain (deprecated) */ + u_long pfcode; /* RES_PRF_ flags - see below. */ + unsigned ndots:4; /* threshold for initial abs. query */ + unsigned nsort:4; /* number of elements in sort_list[] */ + char unused[3]; + struct { + struct in_addr addr; + u_int32_t mask; + } sort_list[MAXRESOLVSORT]; + char pad[72]; /* on an i386 this means 512b total */ +}; + +/* + * Resolver options (keep these in synch with res_debug.c, please) + */ +#define RES_INIT 0x00000001 /* address initialized */ +#define RES_DEBUG 0x00000002 /* print debug messages */ +#define RES_AAONLY 0x00000004 /* authoritative answers only (!IMPL)*/ +#define RES_USEVC 0x00000008 /* use virtual circuit */ +#define RES_PRIMARY 0x00000010 /* query primary server only (!IMPL) */ +#define RES_IGNTC 0x00000020 /* ignore trucation errors */ +#define RES_RECURSE 0x00000040 /* recursion desired */ +#define RES_DEFNAMES 0x00000080 /* use default domain name */ +#define RES_STAYOPEN 0x00000100 /* Keep TCP socket open */ +#define RES_DNSRCH 0x00000200 /* search up local domain tree */ +#define RES_INSECURE1 0x00000400 /* type 1 security disabled */ +#define RES_INSECURE2 0x00000800 /* type 2 security disabled */ +#define RES_NOALIASES 0x00001000 /* shuts off HOSTALIASES feature */ +#define RES_USE_INET6 0x00002000 /* use/map IPv6 in gethostbyname() */ + +#define RES_DEFAULT (RES_RECURSE | RES_DEFNAMES | RES_DNSRCH) + +/* + * Resolver "pfcode" values. Used by dig. + */ +#define RES_PRF_STATS 0x00000001 +/* 0x00000002 */ +#define RES_PRF_CLASS 0x00000004 +#define RES_PRF_CMD 0x00000008 +#define RES_PRF_QUES 0x00000010 +#define RES_PRF_ANS 0x00000020 +#define RES_PRF_AUTH 0x00000040 +#define RES_PRF_ADD 0x00000080 +#define RES_PRF_HEAD1 0x00000100 +#define RES_PRF_HEAD2 0x00000200 +#define RES_PRF_TTLID 0x00000400 +#define RES_PRF_HEADX 0x00000800 +#define RES_PRF_QUERY 0x00001000 +#define RES_PRF_REPLY 0x00002000 +#define RES_PRF_INIT 0x00004000 +/* 0x00008000 */ + +/* hooks are still experimental as of 4.9.2 */ +#if defined(INET6) && defined(__GNUC__) + +#else + +typedef enum { res_goahead, res_nextns, res_modified, res_done, res_error } + res_sendhookact; + +typedef res_sendhookact (*res_send_qhook)__P((struct SOCKADDR_IN * const *ns, + const u_char **query, + int *querylen, + u_char *ans, + int anssiz, + int *resplen)); + +typedef res_sendhookact (*res_send_rhook)__P((const struct SOCKADDR_IN *ns, + const u_char *query, + int querylen, + u_char *ans, + int anssiz, + int *resplen)); +#endif + +struct res_sym { + int number; /* Identifying number, like T_MX */ + char * name; /* Its symbolic name, like "MX" */ + char * humanname; /* Its fun name, like "mail exchanger" */ +}; + +/* Private routines shared between libc/net, named, nslookup and others. */ +#define res_hnok __res_hnok +#define res_ownok __res_ownok +#define res_mailok __res_mailok +#define res_dnok __res_dnok +#define sym_ston __sym_ston +#define sym_ntos __sym_ntos +#define sym_ntop __sym_ntop +#define b64_ntop __b64_ntop +#define b64_pton __b64_pton +#define loc_ntoa __loc_ntoa +#define loc_aton __loc_aton +#define dn_skipname __dn_skipname +#define fp_resstat __fp_resstat +#define fp_query __fp_query +#define fp_nquery __fp_nquery +#define hostalias __hostalias +#define putlong __putlong +#define putshort __putshort +#define p_class __p_class +#define p_time __p_time +#define p_type __p_type +#define p_query __p_query +#define p_cdnname __p_cdnname +#define p_cdname __p_cdname +#define p_fqnname __p_fqnname +#define p_fqname __p_fqname +#define p_rr __p_rr +#define p_option __p_option +#define p_secstodate __p_secstodate +#define dn_count_labels __dn_count_labels +#define dn_comp __dn_comp +#define res_randomid __res_randomid +#define res_isourserver __res_isourserver +#define res_nameinquery __res_nameinquery +#define res_queriesmatch __res_queriesmatch +#define res_close __res_close + +#ifdef BIND_RES_POSIX3 +#define dn_expand __dn_expand +#define res_init __res_init +#define res_query __res_query +#define res_search __res_search +#define res_querydomain __res_querydomain +#define res_mkquery __res_mkquery +#define res_send __res_send +#endif diff --git a/ircd/s_auth.c b/ircd/s_auth.c new file mode 100644 index 0000000..89d19ed --- /dev/null +++ b/ircd/s_auth.c @@ -0,0 +1,804 @@ +/************************************************************************ + * 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 rcsid[] = "@(#)$Id: s_auth.c,v 1.43 1999/07/02 16:38:21 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_AUTH_C +#include "s_externs.h" +#undef S_AUTH_C + +/* + * set_clean_username + * + * As non OTHER type of usernames retrieved via ident lookup are forced as + * usernames for the user, one has to be careful not to allow potentially + * damaging characters in the username. + * This procedure fills up cptr->username based on cptr->auth + * Characters disallowed: + * leading : for obvious reasons + * spaces for obvious reasons + * @ because of how get_sockhost() is implemented, + * and because it's used from attached_Iline() + * [ /trace parsing is impossible + */ +static void +set_clean_username(cptr) +aClient *cptr; +{ + int i = 0, dirty = 0; + char *s; + + if (cptr->auth == NULL) + return; + s = cptr->auth; + if (index(cptr->auth, '[') || index(cptr->auth, '@') || + strlen(cptr->auth) > USERLEN) + dirty = 1; + else if (cptr->auth[0] == ':') + { + dirty = 1; + s += 1; + } + else + { + char *r = cptr->auth; + + while (*r) + if (isspace(*(r++))) + break; + if (*r) + dirty = 1; + } + if (dirty) + cptr->username[i++] = '-'; + while (i < USERLEN && *s) + { + if (*s != '@' && *s != '[' && !isspace(*s)) + cptr->username[i++] = *s; + s += 1; + } + cptr->username[i] = '\0'; + if (!strcmp(cptr->username, cptr->auth)) + { + MyFree(cptr->auth); + cptr->auth = cptr->username; + } + else + { + istat.is_authmem += sizeof(cptr->auth); + istat.is_auth += 1; + } +} + +#if defined(USE_IAUTH) + +u_char iauth_options = 0; +u_int iauth_spawn = 0; +char *iauth_version = NULL; + +static aExtCf *iauth_conf = NULL; +static aExtData *iauth_stats = NULL; + +/* + * sendto_iauth + * + * Send the buffer to the authentication slave process. + * Return 0 if everything went well, -1 otherwise. + */ +#if ! USE_STDARG +int +sendto_iauth(pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) +char *pattern, *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8, *p9, *p10; +#else +int +vsendto_iauth(char *pattern, va_list va) +#endif +{ + static char abuf[BUFSIZ]; + +#if ! USE_STDARG + sprintf(abuf, pattern, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#else + vsprintf(abuf, pattern, va); +#endif + strcat(abuf, "\n"); + + if (adfd < 0) + return -1; + if (write(adfd, abuf, strlen(abuf)) != strlen(abuf)) + { + sendto_flag(SCH_AUTH, "Aiiie! lost slave authentication process"); + close(adfd); + adfd = -1; + start_iauth(0); + return -1; + } + return 0; +} + +# if USE_STDARG +int +sendto_iauth(char *pattern, ...) +{ + int i; + + va_list va; + va_start(va, pattern); + i = vsendto_iauth(pattern, va); + va_end(va); + return i; +} +# endif + +/* + * read_iauth + * + * read and process data from the authentication slave process. + */ +void +read_iauth() +{ + static char obuf[READBUF_SIZE+1], last = '?'; + static int olen = 0, ia_dbg = 0; + char buf[READBUF_SIZE+1], *start, *end, tbuf[BUFSIZ]; + aClient *cptr; + int i; + + if (adfd == -1) + { + olen = 0; + return; + } + while (1) + { + if (olen) + bcopy(obuf, buf, olen); + if ((i = recv(adfd, buf+olen, READBUF_SIZE-olen, 0)) <= 0) + { + if (errno != EAGAIN && errno != EWOULDBLOCK) + { + sendto_flag(SCH_AUTH, "Aiiie! lost slave authentication process (errno = %d)", errno); + close(adfd); + adfd = -1; + start_iauth(0); + } + break; + } + olen += i; + buf[olen] = '\0'; + start = buf; + while (end = index(start, '\n')) + { + *end++ = '\0'; + last = *start; + if (*start == '>') + { + sendto_flag(SCH_AUTH, "%s", start+1); + start = end; + continue; + } + if (*start == 'G') + { + ia_dbg = atoi(start+2); + if (ia_dbg) + sendto_flag(SCH_AUTH,"ia_dbg = %d",ia_dbg); + start = end; + continue; + } + if (*start == 'O') /* options */ + { + iauth_options = 0; + if (strchr(start+2, 'A')) + iauth_options |= XOPT_EARLYPARSE; + if (strchr(start+2, 'R')) + iauth_options |= XOPT_REQUIRED; + if (strchr(start+2, 'T')) + iauth_options |= XOPT_NOTIMEOUT; + if (strchr(start+2, 'W')) + iauth_options |= XOPT_EXTWAIT; + if (iauth_options) + sendto_flag(SCH_AUTH, "iauth options: %x", + iauth_options); + start = end; + continue; + } + if (*start == 'V') /* version */ + { + if (iauth_version) + MyFree(iauth_version); + iauth_version = mystrdup(start+2); + sendto_flag(SCH_AUTH, "iauth version %s running.", + iauth_version); + start = end; + continue; + } + if (*start == 'a') + { + aExtCf *ectmp; + + while (ectmp = iauth_conf) + { + iauth_conf = iauth_conf->next; + MyFree(ectmp->line); + MyFree(ectmp); + } + /* little lie.. ;) */ + sendto_flag(SCH_AUTH, "New iauth configuration."); + start = end; + continue; + } + if (*start == 'A') + { + aExtCf **ectmp = &iauth_conf; + + while (*ectmp) + ectmp = &((*ectmp)->next); + *ectmp = (aExtCf *) MyMalloc(sizeof(aExtCf)); + (*ectmp)->line = mystrdup(start+2); + (*ectmp)->next = NULL; + start = end; + continue; + } + if (*start == 's') + { + aExtData *ectmp; + + while (ectmp = iauth_stats) + { + iauth_stats = iauth_stats->next; + MyFree(ectmp->line); + MyFree(ectmp); + } + iauth_stats = (aExtData *) + MyMalloc(sizeof(aExtData)); + iauth_stats->line = MyMalloc(60); + sprintf(iauth_stats->line, + "iauth modules statistics (%s)", + myctime(timeofday)); + iauth_stats->next = (aExtData *) + MyMalloc(sizeof(aExtData)); + iauth_stats->next->line = MyMalloc(60); + sprintf(iauth_stats->next->line, + "spawned: %d, current options: %X (%.11s)", + iauth_spawn, iauth_options, + (iauth_version) ? iauth_version : "???"); + iauth_stats->next->next = NULL; + start = end; + continue; + } + if (*start == 'S') + { + aExtData **ectmp = &iauth_stats; + + while (*ectmp) + ectmp = &((*ectmp)->next); + *ectmp = (aExtData *) MyMalloc(sizeof(aExtData)); + (*ectmp)->line = mystrdup(start+2); + (*ectmp)->next = NULL; + start = end; + continue; + } + if (*start != 'U' && *start != 'u' && *start != 'o' && + *start != 'K' && *start != 'k' && + *start != 'D') + { + sendto_flag(SCH_AUTH, "Garbage from iauth [%s]", + start); + sendto_iauth("-1 E Garbage [%s]", start); + /* + ** The above should never happen, but i've seen it + ** occasionnally, so let's try to get more info + ** about it! -kalt + */ + sendto_flag(SCH_AUTH, + "last=%u start=%x end=%x buf=%x olen=%d i=%d", + last, start, end, buf, olen, i); + sendto_iauth( + "-1 E last=%u start=%x end=%x buf=%x olen=%d i=%d", + last, start, end, buf, olen, i); + start = end; + continue; + } + if ((cptr = local[i = atoi(start+2)]) == NULL) + { + /* this is fairly common and can be ignored */ + if (ia_dbg) + { + sendto_flag(SCH_AUTH, "Client %d is gone.", + i); + sendto_iauth("%d E Gone [%s]", i, start); + } + start = end; + continue; + } + sprintf(tbuf, "%c %d %s %u ", start[0], i, + inetntoa((char *)&cptr->ip), cptr->port); + if (strncmp(tbuf, start, strlen(tbuf))) + { + /* this is fairly common and can be ignored */ + if (ia_dbg) + { + sendto_flag(SCH_AUTH, + "Client mismatch: %d [%s] != [%s]", + i, start, tbuf); + sendto_iauth("%d E Mismatch [%s] != [%s]", + i, start, tbuf); + } + start = end; + continue; + } + if (start[0] == 'U') + { + if (*(start+strlen(tbuf)) == '\0') + { + sendto_flag(SCH_AUTH, + "Null U message! %d [%s]", + i, start); + sendto_iauth("%d E Null U [%s]", i, start); + start = end; + continue; + } + if (cptr->auth != cptr->username) + { + istat.is_authmem -= sizeof(cptr->auth); + istat.is_auth -= 1; + MyFree(cptr->auth); + } + cptr->auth = mystrdup(start+strlen(tbuf)); + set_clean_username(cptr); + cptr->flags |= FLAGS_GOTID; + } + else if (start[0] == 'u') + { + if (*(start+strlen(tbuf)) == '\0') + { + sendto_flag(SCH_AUTH, + "Null u message! %d [%s]", + i, start); + sendto_iauth("%d E Null u [%s]", i, start); + start = end; + continue; + } + if (cptr->auth != cptr->username) + { + istat.is_authmem -= sizeof(cptr->auth); + istat.is_auth -= 1; + MyFree(cptr->auth); + } + cptr->auth = MyMalloc(strlen(start+strlen(tbuf)) + + 2); + *cptr->auth = '-'; + strcpy(cptr->auth+1, start+strlen(tbuf)); + set_clean_username(cptr); + cptr->flags |= FLAGS_GOTID; + } + else if (start[0] == 'o') + { + if (!WaitingXAuth(cptr)) + { + sendto_flag(SCH_AUTH, + "Early o message discarded!"); + sendto_iauth("%d E Early o [%s]", i,start); + start = end; + continue; + } + if (cptr->user == NULL) + { + /* just to be safe */ + sendto_flag(SCH_AUTH, + "Ack! cptr->user is NULL"); + start = end; + continue; + } + strncpyzt(cptr->user->username, tbuf, USERLEN+1); + } + else if (start[0] == 'D') + { + /*authentication finished*/ + ClearXAuth(cptr); + SetDoneXAuth(cptr); + if (WaitingXAuth(cptr)) + { + ClearWXAuth(cptr); + register_user(cptr, cptr, cptr->name, + cptr->user->username); + } + else + ClearWXAuth(cptr); + } + else + { + /* + ** mark for kill, because it cannot be killed + ** yet: we don't even know if this is a server + ** or a user connection! + */ + if (start[0] == 'K') + cptr->exitc = EXITC_AREF; + else + cptr->exitc = EXITC_AREFQ; + /* should also check to make sure it's still + an unregistered client.. */ + /* should be extended to work after registration */ + } + start = end; + } + if (start != buf+olen) + bcopy(start, obuf, olen = (buf+olen)-start+1); + else + olen = 0; + } +} + +/* + * report_iauth_conf + * + * called from m_stats(), this is the reply to /stats a + */ +void +report_iauth_conf(sptr, to) +aClient *sptr; +char *to; +{ + aExtCf *ectmp = iauth_conf; + + if (adfd < 0) + return; + while (ectmp) + { + sendto_one(sptr, ":%s %d %s :%s", + ME, RPL_STATSIAUTH, to, ectmp->line); + ectmp = ectmp->next; + } +} + +/* + * report_iauth_stats + * + * called from m_stats(), this is part of the reply to /stats t + */ +void +report_iauth_stats(sptr, to) +aClient *sptr; +char *to; +{ + aExtData *ectmp = iauth_stats; + + while (ectmp) + { + sendto_one(sptr, ":%s %d %s :%s", + ME, RPL_STATSDEBUG, to, ectmp->line); + ectmp = ectmp->next; + } +} +#endif + +/* + * 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) +Reg aClient *cptr; +{ +#ifndef NO_IDENT + struct SOCKADDR_IN us, them; + + SOCK_LEN_TYPE ulen, tlen; + +# if defined(USE_IAUTH) + if ((iauth_options & XOPT_REQUIRED) && adfd < 0) + return; +# endif + Debug((DEBUG_NOTICE,"start_auth(%x) fd %d status %d", + cptr, cptr->fd, cptr->status)); + if ((cptr->authfd = socket(AFINET, SOCK_STREAM, 0)) == -1) + { +# ifdef USE_SYSLOG + syslog(LOG_ERR, "Unable to create auth socket for %s:%m", + get_client_name(cptr,TRUE)); +# endif + Debug((DEBUG_ERROR, "Unable to create auth socket for %s:%s", + get_client_name(cptr, TRUE), + strerror(get_sockerr(cptr)))); + ircstp->is_abad++; + return; + } + if (cptr->authfd >= (MAXCONNECTIONS - 2)) + { + sendto_flag(SCH_ERROR, "Can't allocate fd for auth on %s", + get_client_name(cptr, TRUE)); + (void)close(cptr->authfd); + return; + } + + set_non_blocking(cptr->authfd, cptr); + + /* get remote host peer - so that we get right interface -- jrg */ + tlen = ulen = sizeof(us); + if (getpeername(cptr->fd, (struct sockaddr *)&them, &tlen) < 0) + { + /* we probably don't need this error message -kalt */ + report_error("getpeername for auth request %s:%s", cptr); + close(cptr->authfd); + cptr->authfd = -1; + return; + } + them.SIN_FAMILY = AFINET; + + /* We must bind the local end to the interface that they connected + to: The local system might have more than one network address, + and RFC931 check only sends port numbers: server takes IP addresses + from query socket -- jrg */ + (void)getsockname(cptr->fd, (struct sockaddr *)&us, &ulen); + us.SIN_FAMILY = AFINET; +# if defined(USE_IAUTH) + if (adfd >= 0) + { + char abuf[BUFSIZ]; +# ifdef INET6 + sprintf(abuf, "%d C %s %u ", cptr->fd, + inetntop(AF_INET6, (char *)&them.sin6_addr, mydummy, + MYDUMMY_SIZE), ntohs(them.SIN_PORT)); + sprintf(abuf+strlen(abuf), "%s %u", + inetntop(AF_INET6, (char *)&us.sin6_addr, mydummy, + MYDUMMY_SIZE), ntohs(us.SIN_PORT)); +# else + sprintf(abuf, "%d C %s %u ", cptr->fd, + inetntoa((char *)&them.sin_addr),ntohs(them.SIN_PORT)); + sprintf(abuf+strlen(abuf), "%s %u", + inetntoa((char *)&us.sin_addr), ntohs(us.SIN_PORT)); +# endif + if (sendto_iauth(abuf) == 0) + { + close(cptr->authfd); + cptr->authfd = -1; + cptr->flags |= FLAGS_XAUTH; + return; + } + } +# endif +# ifdef INET6 + Debug((DEBUG_NOTICE,"auth(%x) from %s %x %x", + cptr, inet_ntop(AF_INET6, (char *)&us.sin6_addr, mydummy, + MYDUMMY_SIZE), us.sin6_addr.s6_addr[14], + us.sin6_addr.s6_addr[15])); +# else + Debug((DEBUG_NOTICE,"auth(%x) from %s", + cptr, inetntoa((char *)&us.sin_addr))); +# endif + them.SIN_PORT = htons(113); + us.SIN_PORT = htons(0); /* bind assigns us a port */ + if (bind(cptr->authfd, (struct SOCKADDR *)&us, ulen) >= 0) + { + (void)getsockname(cptr->fd, (struct SOCKADDR *)&us, &ulen); +# ifdef INET6 + Debug((DEBUG_NOTICE,"auth(%x) to %s", + cptr, inet_ntop(AF_INET6, (char *)&them.sin6_addr, + mydummy, MYDUMMY_SIZE))); +# else + Debug((DEBUG_NOTICE,"auth(%x) to %s", + cptr, inetntoa((char *)&them.sin_addr))); +# endif + (void)alarm((unsigned)4); + if (connect(cptr->authfd, (struct SOCKADDR *)&them, + tlen) == -1 && errno != EINPROGRESS) + { +# ifdef INET6 + Debug((DEBUG_ERROR, + "auth(%x) connect failed to %s - %d", cptr, + inet_ntop(AF_INET6, (char *)&them.sin6_addr, + mydummy, MYDUMMY_SIZE), errno)); +# else + Debug((DEBUG_ERROR, + "auth(%x) connect failed to %s - %d", cptr, + inetntoa((char *)&them.sin_addr), errno)); +# endif + ircstp->is_abad++; + /* + * No error report from this... + */ + (void)alarm((unsigned)0); + (void)close(cptr->authfd); + cptr->authfd = -1; + return; + } + (void)alarm((unsigned)0); + } + else + { + report_error("binding stream socket for auth request %s:%s", + cptr); +# ifdef INET6 + Debug((DEBUG_ERROR,"auth(%x) bind failed on %s port %d - %d", + cptr, inet_ntop(AF_INET6, (char *)&us.sin6_addr, + mydummy, MYDUMMY_SIZE), + ntohs(us.SIN_PORT), errno)); +# else + Debug((DEBUG_ERROR,"auth(%x) bind failed on %s port %d - %d", + cptr, inetntoa((char *)&us.sin_addr), + ntohs(us.SIN_PORT), errno)); +# endif + } + + cptr->flags |= (FLAGS_WRAUTH|FLAGS_AUTH); + if (cptr->authfd > highest_fd) + highest_fd = cptr->authfd; +#endif + return; +} + +/* + * 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]; + SOCK_LEN_TYPE 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; + } + + SPRINTF(authbuf, "%u , %u\r\n", + (unsigned int)ntohs(them.SIN_PORT), + (unsigned int)ntohs(us.SIN_PORT)); + +#ifdef INET6 + Debug((DEBUG_SEND, "sending [%s] to auth port %s.113", + authbuf, inet_ntop,(AF_INET6, (char *)&them.sin6_addr, + mydummy, MYDUMMY_SIZE))); +#else + Debug((DEBUG_SEND, "sending [%s] to auth port %s.113", + authbuf, inetntoa((char *)&them.sin_addr))); +#endif + 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|FLAGS_WRAUTH); + return; + } + 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) +Reg aClient *cptr; +{ + Reg char *s, *t; + Reg int len; + char ruser[513], 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. Can't 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'; + } + + if ((len > 0) && (cptr->count != (sizeof(cptr->buffer) - 1)) && + (sscanf(cptr->buffer, "%hd , %hd : USERID : %*[^:]: %512s", + &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 != ':') + *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 s %x", + locp, remp, ruser)); + 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 (len > 0) + Debug((DEBUG_INFO,"ident reply: [%s]", cptr->buffer)); + + if (!locp || !remp || !*ruser) + { + ircstp->is_abad++; + return; + } + ircstp->is_asuc++; + if (cptr->auth != cptr->username)/*impossible, but...*/ + { + istat.is_authmem -= sizeof(cptr->auth); + istat.is_auth -= 1; + MyFree(cptr->auth); + } + if (!strncmp(system, "OTHER", 5)) + { /* OTHER type of identifier */ + cptr->auth = MyMalloc(strlen(ruser) + 2); + *cptr->auth = '-'; + strcpy(cptr->auth+1, ruser); + } + else + cptr->auth = mystrdup(ruser); + set_clean_username(cptr); + cptr->flags |= FLAGS_GOTID; + Debug((DEBUG_INFO, "got username [%s]", ruser)); + return; +} diff --git a/ircd/s_auth_ext.h b/ircd/s_auth_ext.h new file mode 100644 index 0000000..4a6a3d1 --- /dev/null +++ b/ircd/s_auth_ext.h @@ -0,0 +1,52 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_auth_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_auth.c. + */ + +/* External definitions for global functions. + */ +#ifndef S_AUTH_C +# if defined(USE_IAUTH) +extern u_char iauth_options; +extern u_int iauth_spawn; +# endif +# +# define EXTERN extern +#else /* S_AUTH_C */ +# define EXTERN +#endif /* S_AUTH_C */ + +#if defined(USE_IAUTH) +# if ! USE_STDARG +EXTERN int sendto_iauth(); +# else /* USE_STDARG */ +EXTERN int vsendto_iauth (char *pattern, va_list va); +EXTERN int sendto_iauth (char *pattern, ...); +# endif +EXTERN void read_iauth(); +EXTERN void report_iauth_conf __P((aClient *, char *)); +EXTERN void report_iauth_stats __P((aClient *, char *)); +#endif +EXTERN void start_auth __P((Reg aClient *cptr)); +EXTERN void send_authports __P((aClient *cptr)); +EXTERN void read_authports __P((Reg aClient *cptr)); + +#undef EXTERN diff --git a/ircd/s_bsd.c b/ircd/s_bsd.c new file mode 100644 index 0000000..f10e459 --- /dev/null +++ b/ircd/s_bsd.c @@ -0,0 +1,3243 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_bsd.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. + */ + +/* -- Jto -- 07 Jul 1990 + * Added jlp@hamblin.byu.edu's debugtty fix + */ + +/* -- Armin -- Jun 18 1990 + * Added setdtablesize() for more socket connections + * (sequent OS Dynix only) -- maybe select()-call must be changed ... + */ + +/* -- Jto -- 13 May 1990 + * Added several fixes from msa: + * Better error messages + * Changes in check_access + * Added SO_REUSEADDR fix from zessel@informatik.uni-kl.de + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: s_bsd.c,v 1.73 1999/07/23 17:15:14 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_BSD_C +#include "s_externs.h" +#undef S_BSD_C + +#ifndef IN_LOOPBACKNET +#define IN_LOOPBACKNET 0x7f +#endif + +aClient *local[MAXCONNECTIONS]; +FdAry fdas, fdall; +int highest_fd = 0, readcalls = 0, udpfd = -1, resfd = -1, adfd = -1; +time_t timeofday; +static struct SOCKADDR_IN mysk; +static void polludp(); + +static struct SOCKADDR *connect_inet __P((aConfItem *, aClient *, int *)); +static int completed_connection __P((aClient *)); +static int check_init __P((aClient *, char *)); +static int check_ping __P((char *, int)); +static void do_dns_async __P(()); +static int set_sock_opts __P((int, aClient *)); +#ifdef UNIXPORT +static struct SOCKADDR *connect_unix __P((aConfItem *, aClient *, int *)); +static void add_unixconnection __P((aClient *, int)); +static char unixpath[256]; +#endif +static char readbuf[READBUF_SIZE]; + +#define CFLAG (CONF_CONNECT_SERVER|CONF_ZCONNECT_SERVER) +#define NFLAG CONF_NOCONNECT_SERVER + +/* + * Try and find the correct name to use with getrlimit() for setting the max. + * number of files allowed to be open by this process. + */ +#ifdef RLIMIT_FDMAX +# define RLIMIT_FD_MAX RLIMIT_FDMAX +#else +# ifdef RLIMIT_NOFILE +# define RLIMIT_FD_MAX RLIMIT_NOFILE +# else +# ifdef RLIMIT_OPEN_MAX +# define RLIMIT_FD_MAX RLIMIT_OPEN_MAX +# else +# undef RLIMIT_FD_MAX +# endif +# endif +#endif + +/* +** add_local_domain() +** Add the domain to hostname, if it is missing +** (as suggested by eps@TOASTER.SFSU.EDU) +*/ + +void add_local_domain(hname, size) +char *hname; +int size; +{ +#ifdef RES_INIT + /* try to fix up unqualified names */ + if (!index(hname, '.')) + { + if (!(ircd_res.options & RES_INIT)) + { + Debug((DEBUG_DNS,"ircd_res_init()")); + ircd_res_init(); + } + if (ircd_res.defdname[0]) + { + (void)strncat(hname, ".", size-1); + (void)strncat(hname, ircd_res.defdname, size-2); + } + } +#endif + return; +} + +/* +** Cannot use perror() within daemon. stderr is closed in +** ircd and cannot be used. And, worse yet, it might have +** been reassigned to a normal connection... +*/ + +/* +** report_error +** This a replacement for perror(). Record error to log and +** also send a copy to all *LOCAL* opers online. +** +** text is a *format* string for outputting error. It must +** contain only two '%s', the first will be replaced +** by the sockhost from the cptr, and the latter will +** be taken from sys_errlist[errno]. +** +** cptr if not NULL, is the *LOCAL* client associated with +** the error. +*/ +void report_error(text, cptr) +char *text; +aClient *cptr; +{ + Reg int errtmp = errno; /* debug may change 'errno' */ + Reg char *host; + int err; + SOCK_LEN_TYPE len = sizeof(err); + extern char *strerror(); + + host = (cptr) ? get_client_name(cptr, FALSE) : ""; + + Debug((DEBUG_ERROR, text, host, strerror(errtmp))); + + /* + * Get the *real* error from the socket (well try to anyway..). + * This may only work when SO_DEBUG is enabled but its worth the + * gamble anyway. + */ +#ifdef SO_ERROR + if (!IsMe(cptr) && cptr->fd >= 0) + if (!GETSOCKOPT(cptr->fd, SOL_SOCKET, SO_ERROR, &err, &len)) + if (err) + errtmp = err; +#endif + sendto_flag(SCH_ERROR, text, host, strerror(errtmp)); +#ifdef USE_SYSLOG + syslog(LOG_WARNING, text, host, strerror(errtmp)); +#endif + return; +} + +/* + * inetport + * + * Create a socket in the AF_INET domain, bind it to the port given in + * 'port' and listen to it. If 'ip' has a value, use it as vif to listen. + * Connections are accepted to this socket depending on the IP# mask given + * by 'ipmask'. Returns the fd of the socket created or -1 on error. + */ +int inetport(cptr, ip, ipmask, port) +aClient *cptr; +char *ipmask, *ip; +int port; +{ + static struct SOCKADDR_IN server; + int ad[4]; + SOCK_LEN_TYPE len = sizeof(server); + char ipname[20]; + + ad[0] = ad[1] = ad[2] = ad[3] = 0; + + /* + * do it this way because building ip# from separate values for each + * byte requires endian knowledge or some nasty messing. Also means + * easy conversion of "*" 0.0.0.0 or 134.* to 134.0.0.0 :-) + */ + (void)sscanf(ipmask, "%d.%d.%d.%d", &ad[0], &ad[1], &ad[2], &ad[3]); + (void)sprintf(ipname, "%d.%d.%d.%d", ad[0], ad[1], ad[2], ad[3]); + + (void)sprintf(cptr->sockhost, "%-.42s.%u", ip ? ip : ME, + (unsigned int)port); + (void)strcpy(cptr->name, ME); + DupString(cptr->auth, ipname); + /* + * At first, open a new socket + */ + if (cptr->fd == -1) + cptr->fd = socket(AFINET, SOCK_STREAM, 0); + if (cptr->fd < 0) + { + report_error("opening stream socket %s:%s", cptr); + return -1; + } + else if (cptr->fd >= MAXCLIENTS) + { + sendto_flag(SCH_ERROR, + "No more connections allowed (%s)", cptr->name); + (void)close(cptr->fd); + return -1; + } + (void)set_sock_opts(cptr->fd, cptr); + /* + * Bind a port to listen for new connections if port is non-null, + * else assume it is already open and try get something from it. + */ + if (port) + { + server.SIN_FAMILY = AFINET; +#ifdef INET6 + if (!ip || (!isxdigit(*ip) && *ip != ':')) + server.sin6_addr = in6addr_any; + else + if(!inet_pton(AF_INET6, ip, server.sin6_addr.s6_addr)) + bcopy(minus_one, server.sin6_addr.s6_addr, + IN6ADDRSZ); +#else + if (!ip || !isdigit(*ip)) + server.sin_addr.s_addr = INADDR_ANY; + else + server.sin_addr.s_addr = inetaddr(ip); +#endif + server.SIN_PORT = htons(port); + /* + * Try 10 times to bind the socket with an interval of 20 + * seconds. Do this so we don't have to keep trying manually + * to bind. Why ? Because a port that has closed often lingers + * around for a short time. + * This used to be the case. Now it no longer is. + * Could cause the server to hang for too long - avalon + */ + if (bind(cptr->fd, (SAP)&server, sizeof(server)) == -1) + { + report_error("binding stream socket %s:%s", cptr); + (void)close(cptr->fd); + return -1; + } + } + + if (getsockname(cptr->fd, (struct SOCKADDR *)&server, &len)) + { + report_error("getsockname failed for %s:%s",cptr); + (void)close(cptr->fd); + return -1; + } + + if (cptr == &me) /* KLUDGE to get it work... */ + { + char buf[1024]; + + (void)sprintf(buf, rpl_str(RPL_MYPORTIS, "*"), + ntohs(server.SIN_PORT)); + (void)write(0, buf, strlen(buf)); + } + + if (cptr->fd > highest_fd) + highest_fd = cptr->fd; +#ifdef INET6 + bcopy(server.sin6_addr.s6_addr, cptr->ip.s6_addr, IN6ADDRSZ); +#else + cptr->ip.s_addr = server.sin_addr.s_addr; /* broken on linux at least*/ +#endif + cptr->port = port; + (void)listen(cptr->fd, LISTENQUEUE); + local[cptr->fd] = cptr; + + return 0; +} + +/* + * add_listener + * + * Create a new client which is essentially the stub like 'me' to be used + * for a socket that is passive (listen'ing for connections to be accepted). + */ +int add_listener(aconf) +aConfItem *aconf; +{ + aClient *cptr; + + cptr = make_client(NULL); + cptr->flags = FLAGS_LISTEN; + cptr->acpt = cptr; + cptr->from = cptr; + cptr->firsttime = time(NULL); + SetMe(cptr); +#ifdef UNIXPORT + if (*aconf->host == '/') + { + strncpyzt(cptr->name, aconf->host, sizeof(cptr->name)); + if (unixport(cptr, aconf->host, aconf->port)) + cptr->fd = -2; + } + else +#endif + if (inetport(cptr, aconf->host, aconf->name, aconf->port)) + cptr->fd = -2; + + if (cptr->fd >= 0) + { + cptr->confs = make_link(); + cptr->confs->next = NULL; + cptr->confs->value.aconf = aconf; + add_fd(cptr->fd, &fdas); + add_fd(cptr->fd, &fdall); + set_non_blocking(cptr->fd, cptr); + } + else + free_client(cptr); + return 0; +} + +#ifdef UNIXPORT +/* + * unixport + * + * Create a socket and bind it to a filename which is comprised of the path + * (directory where file is placed) and port (actual filename created). + * Set directory permissions as rwxr-xr-x so other users can connect to the + * file which is 'forced' to rwxrwxrwx (different OS's have different need of + * modes so users can connect to the socket). + */ +int unixport(cptr, path, port) +aClient *cptr; +char *path; +int port; +{ + struct sockaddr_un un; + + if ((cptr->fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + { + report_error("error opening unix domain socket %s:%s", cptr); + return -1; + } + else if (cptr->fd >= MAXCLIENTS) + { + sendto_flag(SCH_ERROR, + "No more connections allowed (%s)", cptr->name); + (void)close(cptr->fd); + return -1; + } + + un.sun_family = AF_UNIX; + (void)mkdir(path, 0755); + SPRINTF(unixpath, "%s/%d", path, port); + (void)unlink(unixpath); + strncpyzt(un.sun_path, unixpath, sizeof(un.sun_path)); + (void)strcpy(cptr->name, ME); + errno = 0; + get_sockhost(cptr, unixpath); + + if (bind(cptr->fd, (SAP)&un, strlen(unixpath)+2) == -1) + { + report_error("error binding unix socket %s:%s", cptr); + (void)close(cptr->fd); + return -1; + } + if (cptr->fd > highest_fd) + highest_fd = cptr->fd; + (void)listen(cptr->fd, LISTENQUEUE); + (void)chmod(path, 0755); + (void)chmod(unixpath, 0777); + cptr->flags |= FLAGS_UNIX; + cptr->port = 0; + local[cptr->fd] = cptr; + + return 0; +} +#endif + +/* + * close_listeners + * + * Close and free all clients which are marked as having their socket open + * and in a state where they can accept connections. Unix sockets have + * the path to the socket unlinked for cleanliness. + */ +void close_listeners() +{ + Reg aClient *cptr; + Reg int i; + Reg aConfItem *aconf; + + /* + * close all 'extra' listening ports we have and unlink the file + * name if it was a unix socket. + */ + for (i = highest_fd; i >= 0; i--) + { + if (!(cptr = local[i])) + continue; + if (cptr == &me || !IsListening(cptr)) + continue; + aconf = cptr->confs->value.aconf; + + if (IsIllegal(aconf) && aconf->clients == 0) + { +#ifdef UNIXPORT + if (IsUnixSocket(cptr)) + { + SPRINTF(unixpath, "%s/%d", + aconf->host, aconf->port); + (void)unlink(unixpath); + } +#endif + close_connection(cptr); + } + } +} + +void +start_iauth(rcvdsig) +int rcvdsig; +{ +#if defined(USE_IAUTH) + static time_t last = 0; + static char first = 1; + int sp[2], fd; + + if ((bootopt & BOOT_NOIAUTH) != 0) + return; + if (adfd >= 0) + { + if (rcvdsig) + sendto_flag(SCH_AUTH, + "iauth is already running, restart canceled"); + return; + } + if ((time(NULL) - last) > 90 || rcvdsig) + { + sendto_flag(SCH_AUTH, "Starting iauth..."); + last = time(NULL); + read_iauth(); /* to reset olen */ + iauth_spawn += 1; + } + else + return; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) < 0) + { + sendto_flag(SCH_ERROR, "socketpair() failed!"); + sendto_flag(SCH_AUTH, "Failed to restart iauth!"); + } + adfd = sp[0]; + set_non_blocking(sp[0], NULL); + set_non_blocking(sp[1], NULL); /* less to worry about in iauth */ + switch (vfork()) + { + case -1: + sendto_flag(SCH_ERROR, "vfork() failed!"); + sendto_flag(SCH_AUTH, "Failed to restart iauth!"); + close(sp[0]); close(sp[1]); + adfd = -1; + return; + case 0: + for (fd = 0; fd < MAXCONNECTIONS; fd++) + if (fd != sp[1]) + (void)close(fd); + if (sp[1] != 0) + { + (void)dup2(sp[1], 0); + close(sp[1]); + } + if (execl(IAUTH_PATH, IAUTH, NULL) < 0) + _exit(-1); /* should really not happen.. */ + default: + close(sp[1]); + } + + if (first) + first = 0; + else + { + int i; + aClient *cptr; + + for (i = 0; i <= highest_fd; i++) + { + if (!(cptr = local[i])) + continue; + if (IsServer(cptr) || IsService(cptr)) + continue; + sendto_iauth("%d O", i); + } + } +#endif +} + +/* + * init_sys + */ +void init_sys() +{ + Reg int fd; + +#ifdef RLIMIT_FD_MAX + struct rlimit limit; + + if (!getrlimit(RLIMIT_FD_MAX, &limit)) + { + if (limit.rlim_max < MAXCONNECTIONS) + { + (void)fprintf(stderr, "ircd fd table is too big\n"); + (void)fprintf(stderr, "Hard Limit: %d IRC max: %d\n", + (int) limit.rlim_max, MAXCONNECTIONS); + (void)fprintf(stderr, + "Fix MAXCONNECTIONS and recompile.\n"); + exit(-1); + } + limit.rlim_cur = limit.rlim_max; /* make soft limit the max */ + if (setrlimit(RLIMIT_FD_MAX, &limit) == -1) + { + (void)fprintf(stderr, "error setting max fd's to %d\n", + (int) limit.rlim_cur); + exit(-1); + } + } +#endif +#if ! USE_POLL +# ifdef sequent +# ifndef DYNIXPTX + int fd_limit; + + fd_limit = setdtablesize(MAXCONNECTIONS + 1); + if (fd_limit < MAXCONNECTIONS) + { + (void)fprintf(stderr,"ircd fd table too big\n"); + (void)fprintf(stderr,"Hard Limit: %d IRC max: %d\n", + fd_limit, MAXCONNECTIONS); + (void)fprintf(stderr,"Fix MAXCONNECTIONS\n"); + exit(-1); + } +# endif +# endif +#endif /* USE_POLL */ + +#if defined(PCS) || defined(DYNIXPTX) || defined(SVR3) + char logbuf[BUFSIZ]; + + (void)setvbuf(stderr,logbuf,_IOLBF,sizeof(logbuf)); +#else +# if defined(HPUX) + (void)setvbuf(stderr, NULL, _IOLBF, 0); +# else +# if !defined(SVR4) + (void)setlinebuf(stderr); +# endif +# endif +#endif + + bzero((char *)&fdas, sizeof(fdas)); + bzero((char *)&fdall, sizeof(fdall)); + fdas.highest = fdall.highest = -1; + + for (fd = 3; fd < MAXCONNECTIONS; fd++) + { + (void)close(fd); + local[fd] = NULL; + } + local[1] = NULL; + (void) fclose(stdout); + (void)close(1); + + if (bootopt & BOOT_TTY) /* debugging is going to a tty */ + goto init_dgram; + if (!(bootopt & BOOT_DEBUG)) + (void)close(2); + + if (((bootopt & BOOT_CONSOLE) || isatty(0)) && + !(bootopt & (BOOT_INETD|BOOT_OPER))) + { +#ifndef __CYGWIN32__ + if (fork()) + exit(0); +#endif +#ifdef TIOCNOTTY + if ((fd = open("/dev/tty", O_RDWR)) >= 0) + { + (void)ioctl(fd, TIOCNOTTY, (char *)NULL); + (void)close(fd); + } +#endif +#if defined(HPUX) || defined(SVR4) || defined(DYNIXPTX) || \ + defined(_POSIX_SOURCE) || defined(SGI) + (void)setsid(); +#else + (void)setpgrp(0, (int)getpid()); +#endif + (void)close(0); /* fd 0 opened by inetd */ + local[0] = NULL; + } +init_dgram: + resfd = init_resolver(0x1f); + + start_iauth(0); +} + +void write_pidfile() +{ + int fd; + char buff[20]; + (void)truncate(IRCDPID_PATH, 0); + if ((fd = open(IRCDPID_PATH, O_CREAT|O_WRONLY, 0600))>=0) + { + bzero(buff, sizeof(buff)); + (void)sprintf(buff,"%5d\n", (int)getpid()); + if (write(fd, buff, strlen(buff)) == -1) + Debug((DEBUG_NOTICE,"Error writing to pid file %s", + IRCDPID_PATH)); + (void)close(fd); + return; + } +# ifdef DEBUGMODE + else + Debug((DEBUG_NOTICE,"Error opening pid file %s", + IRCDPID_PATH)); +# endif +} + +/* + * Initialize the various name strings used to store hostnames. This is set + * from either the server's sockhost (if client fd is a tty or localhost) + * or from the ip# converted into a string. 0 = success, -1 = fail. + */ +static int check_init(cptr, sockn) +Reg aClient *cptr; +Reg char *sockn; +{ + struct SOCKADDR_IN sk; + SOCK_LEN_TYPE len = sizeof(struct SOCKADDR_IN); + +#ifdef UNIXPORT + if (IsUnixSocket(cptr)) + { + strncpyzt(sockn, cptr->acpt->sockhost, HOSTLEN+1); + get_sockhost(cptr, sockn); + return 0; + } +#endif + + /* If descriptor is a tty, special checking... */ + if (isatty(cptr->fd)) + { + strncpyzt(sockn, me.sockhost, HOSTLEN); + bzero((char *)&sk, sizeof(struct SOCKADDR_IN)); + } + else if (getpeername(cptr->fd, (SAP)&sk, &len) == -1) + { + report_error("connect failure: %s %s", cptr); + return -1; + } +#ifdef INET6 + inetntop(AF_INET6, (char *)&sk.sin6_addr, sockn, MYDUMMY_SIZE); + Debug((DEBUG_DNS,"sockn %x",sockn)); + Debug((DEBUG_DNS,"sockn %s",sockn)); +#else + (void)strcpy(sockn, (char *)inetntoa((char *)&sk.sin_addr)); +#endif +#ifdef INET6 + if (IN6_IS_ADDR_LOOPBACK(&sk.SIN_ADDR)) +#else + if (inetnetof(sk.SIN_ADDR) == IN_LOOPBACKNET) +#endif + { + cptr->hostp = me.hostp; + } + bcopy((char *)&sk.SIN_ADDR, (char *)&cptr->ip, sizeof(struct IN_ADDR)); + cptr->port = (int)(ntohs(sk.SIN_PORT)); + + return 0; +} + +/* + * Ordinary client access check. Look for conf lines which have the same + * status as the flags passed. + * 0 = Success + * -1 = Bad socket. + * -2 = Access denied + */ +int check_client(cptr) +Reg aClient *cptr; +{ + static char sockname[HOSTLEN+1]; + Reg struct hostent *hp = NULL; + Reg int i; + +#ifdef INET6 + Debug((DEBUG_DNS, "ch_cl: check access for %s[%s]", + cptr->name, inet_ntop(AF_INET6, (char *)&cptr->ip, mydummy, + MYDUMMY_SIZE))); +#else + Debug((DEBUG_DNS, "ch_cl: check access for %s[%s]", + cptr->name, inetntoa((char *)&cptr->ip))); +#endif + + if (check_init(cptr, sockname)) + return -1; + + if (!IsUnixSocket(cptr)) + hp = cptr->hostp; + /* + * Verify that the host to ip mapping is correct both ways and that + * the ip#(s) for the socket is listed for the host. + * We shouldn't check it for localhost, because hp is fake in that + * case. -Toor + */ + if (hp && (hp != me.hostp)) + { + for (i = 0; hp->h_addr_list[i]; i++) + if (!bcmp(hp->h_addr_list[i], (char *)&cptr->ip, + sizeof(struct IN_ADDR))) + break; + if (!hp->h_addr_list[i]) + { +#ifdef INET6 + sendto_flag(SCH_ERROR, + "IP# Mismatch: %s != %s[%08x%08x%08x%08x]", + inetntop(AF_INET6, (char *)&cptr->ip, + mydummy,MYDUMMY_SIZE),hp->h_name, + ((unsigned long *)hp->h_addr)[0], + ((unsigned long *)hp->h_addr)[1], + ((unsigned long *)hp->h_addr)[2], + ((unsigned long *)hp->h_addr)[3]); +#else + sendto_flag(SCH_ERROR, "IP# Mismatch: %s != %s[%08x]", + inetntoa((char *)&cptr->ip), hp->h_name, + *((unsigned long *)hp->h_addr)); +#endif + hp = NULL; + } + } + + if ((i = attach_Iline(cptr, hp, sockname))) + { + Debug((DEBUG_DNS,"ch_cl: access denied: %s[%s]", + cptr->name, sockname)); + return i; + } + + Debug((DEBUG_DNS, "ch_cl: access ok: %s[%s]", + cptr->name, sockname)); + +#ifdef INET6 + if (IN6_IS_ADDR_LOOPBACK(&cptr->ip) || IsUnixSocket(cptr) || + (cptr->ip.s6_laddr[0]==mysk.sin6_addr.s6_laddr[0] && + cptr->ip.s6_laddr[1]==mysk.sin6_addr.s6_laddr[1]) +/* || + IN6_ARE_ADDR_SAMEPREFIX(&cptr->ip, &mysk.SIN_ADDR)) + about the same, I think NOT */ + ) +#else + if (inetnetof(cptr->ip) == IN_LOOPBACKNET || IsUnixSocket(cptr) || + inetnetof(cptr->ip) == inetnetof(mysk.SIN_ADDR)) +#endif + { + + ircstp->is_loc++; + cptr->flags |= FLAGS_LOCAL; + } + return 0; +} + +/* + * check_server_init(), check_server() + * check access for a server given its name (passed in cptr struct). + * Must check for all C/N lines which have a name which matches the + * name given and a host which matches. A host alias which is the + * same as the server name is also acceptable in the host field of a + * C/N line. + * 0 = Success + * -1 = Access denied + * -2 = Bad socket. + */ +int check_server_init(cptr) +aClient *cptr; +{ + Reg char *name; + Reg aConfItem *c_conf = NULL, *n_conf = NULL; + struct hostent *hp = NULL; + Link *lp; + + name = cptr->name; + Debug((DEBUG_DNS, "sv_cl: check access for %s[%s]", + name, cptr->sockhost)); + + if (IsUnknown(cptr) && !attach_confs(cptr, name, CFLAG|NFLAG)) + { + Debug((DEBUG_DNS,"No C/N lines for %s", name)); + return -1; + } + lp = cptr->confs; + /* + * We initiated this connection so the client should have a C and N + * line already attached after passing through the connec_server() + * function earlier. + */ + if (IsConnecting(cptr) || IsHandshake(cptr)) + { + c_conf = find_conf(lp, name, CFLAG); + n_conf = find_conf(lp, name, NFLAG); + if (!c_conf || !n_conf) + { + sendto_flag(SCH_ERROR, "Connecting Error: %s[%s]", + name, cptr->sockhost); + det_confs_butmask(cptr, 0); + return -1; + } + } +#ifdef UNIXPORT + if (IsUnixSocket(cptr)) + { + if (!c_conf) + c_conf = find_conf(lp, name, CFLAG); + if (!n_conf) + n_conf = find_conf(lp, name, NFLAG); + } +#endif + + /* + ** If the servername is a hostname, either an alias (CNAME) or + ** real name, then check with it as the host. Use gethostbyname() + ** to check for servername as hostname. + */ + if (!IsUnixSocket(cptr) && !cptr->hostp) + { + Reg aConfItem *aconf; + + aconf = count_cnlines(lp); + if (aconf) + { + Reg char *s; + Link lin; + + /* + ** Do a lookup for the CONF line *only* and not + ** the server connection else we get stuck in a + ** nasty state since it takes a SERVER message to + ** get us here and we can't interrupt that very + ** well. + */ + lin.value.aconf = aconf; + lin.flags = ASYNC_CONF; + nextdnscheck = 1; + if ((s = index(aconf->host, '@'))) + s++; + else + s = aconf->host; + Debug((DEBUG_DNS,"sv_ci:cache lookup (%s)",s)); + hp = gethost_byname(s, &lin); + } + } + return check_server(cptr, hp, c_conf, n_conf, 0); +} + +int check_server(cptr, hp, c_conf, n_conf, estab) +aClient *cptr; +Reg aConfItem *n_conf, *c_conf; +Reg struct hostent *hp; +int estab; +{ + Reg char *name; + char abuff[HOSTLEN+USERLEN+2]; + char sockname[HOSTLEN+1], fullname[HOSTLEN+1]; + Link *lp = cptr->confs; + int i; + + if (check_init(cptr, sockname)) + return -2; + +check_serverback: + if (hp) + { + for (i = 0; hp->h_addr_list[i]; i++) + if (!bcmp(hp->h_addr_list[i], (char *)&cptr->ip, + sizeof(struct IN_ADDR))) + break; + if (!hp->h_addr_list[i]) + { +#ifdef INET6 + sendto_flag(SCH_ERROR, + "IP# Mismatch: %s != %s[%08x%08x%08x%08x]", + inetntop(AF_INET6, (char *)&cptr->ip, + mydummy,MYDUMMY_SIZE),hp->h_name, + ((unsigned long *)hp->h_addr)[0], + ((unsigned long *)hp->h_addr)[1], + ((unsigned long *)hp->h_addr)[2], + ((unsigned long *)hp->h_addr)[3]); +#else + sendto_flag(SCH_ERROR, "IP# Mismatch: %s != %s[%08x]", + inetntoa((char *)&cptr->ip), hp->h_name, + *((unsigned long *)hp->h_addr)); +#endif + hp = NULL; + } + } + else if (cptr->hostp) + { + hp = cptr->hostp; + goto check_serverback; + } + + if (hp) + /* + * if we are missing a C or N line from above, search for + * it under all known hostnames we have for this ip#. + */ + for (i=0,name = hp->h_name; name ; name = hp->h_aliases[i++]) + { + strncpyzt(fullname, name, sizeof(fullname)); + add_local_domain(fullname, HOSTLEN-strlen(fullname)); + Debug((DEBUG_DNS, "sv_cl: gethostbyaddr: %s->%s", + sockname, fullname)); + SPRINTF(abuff, "%s@%s", cptr->username, fullname); + if (!c_conf) + c_conf = find_conf_host(lp, abuff, CFLAG); + if (!n_conf) + n_conf = find_conf_host(lp, abuff, NFLAG); + if (c_conf && n_conf) + { + get_sockhost(cptr, fullname); + break; + } + } + name = cptr->name; + + /* + * Check for C and N lines with the hostname portion the ip number + * of the host the server runs on. This also checks the case where + * there is a server connecting from 'localhost'. + */ + if (IsUnknown(cptr) && (!c_conf || !n_conf)) + { + SPRINTF(abuff, "%s@%s", cptr->username, sockname); + if (!c_conf) + c_conf = find_conf_host(lp, abuff, CFLAG); + if (!n_conf) + n_conf = find_conf_host(lp, abuff, NFLAG); + } + /* + * Attach by IP# only if all other checks have failed. + * It is quite possible to get here with the strange things that can + * happen when using DNS in the way the irc server does. -avalon + */ + if (!hp) + { + if (!c_conf) + c_conf = find_conf_ip(lp, (char *)&cptr->ip, + cptr->username, CFLAG); + if (!n_conf) + n_conf = find_conf_ip(lp, (char *)&cptr->ip, + cptr->username, NFLAG); + } + else + for (i = 0; hp->h_addr_list[i]; i++) + { + if (!c_conf) + c_conf = find_conf_ip(lp, hp->h_addr_list[i], + cptr->username, CFLAG); + if (!n_conf) + n_conf = find_conf_ip(lp, hp->h_addr_list[i], + cptr->username, NFLAG); + } + /* + * detach all conf lines that got attached by attach_confs() + */ + det_confs_butmask(cptr, 0); + /* + * if no C or no N lines, then deny access + */ + if (!c_conf || !n_conf) + { + get_sockhost(cptr, sockname); + Debug((DEBUG_DNS, "sv_cl: access denied: %s[%s@%s] c %x n %x", + name, cptr->auth, cptr->sockhost, + c_conf, n_conf)); + return -1; + } + /* + * attach the C and N lines to the client structure for later use. + */ + (void)attach_conf(cptr, n_conf); + (void)attach_conf(cptr, c_conf); + (void)attach_confs(cptr, name, CONF_HUB|CONF_LEAF); + +#ifdef INET6 + if ((AND16(c_conf->ipnum.s6_addr) == 255) && !IsUnixSocket(cptr)) +#else + if ((c_conf->ipnum.s_addr == -1) && !IsUnixSocket(cptr)) +#endif + bcopy((char *)&cptr->ip, (char *)&c_conf->ipnum, + sizeof(struct IN_ADDR)); + if (!IsUnixSocket(cptr)) + get_sockhost(cptr, c_conf->host); + + Debug((DEBUG_DNS,"sv_cl: access ok: %s[%s]", + name, cptr->sockhost)); + if (estab) + return m_server_estab(cptr); + return 0; +} + +/* +** completed_connection +** Complete non-blocking connect()-sequence. Check access and +** terminate connection, if trouble detected. +** +** Return TRUE, if successfully completed +** FALSE, if failed and ClientExit +*/ +static int completed_connection(cptr) +aClient *cptr; +{ + aConfItem *aconf; + + SetHandshake(cptr); + + aconf = find_conf(cptr->confs, cptr->name, CFLAG); + if (!aconf) + { + sendto_flag(SCH_NOTICE, + "Lost C-Line for %s", get_client_name(cptr,FALSE)); + return -1; + } + if (!BadPtr(aconf->passwd)) +#ifndef ZIP_LINKS + sendto_one(cptr, "PASS %s %s IRC|%s %s", aconf->passwd, + pass_version, serveropts, + (bootopt & BOOT_STRICTPROT) ? "P" : ""); +#else + sendto_one(cptr, "PASS %s %s IRC|%s %s%s", aconf->passwd, + pass_version, serveropts, + (bootopt & BOOT_STRICTPROT) ? "P" : "", + (aconf->status == CONF_ZCONNECT_SERVER) ? "Z" : ""); +#endif + + aconf = find_conf(cptr->confs, cptr->name, CONF_NOCONNECT_SERVER); + if (!aconf) + { + sendto_flag(SCH_NOTICE, + "Lost N-Line for %s", get_client_name(cptr,FALSE)); + return -1; + } + sendto_one(cptr, "SERVER %s 1 :%s", + my_name_for_link(ME, aconf->port), me.info); + if (!IsDead(cptr)) + { + start_auth(cptr); +#if defined(USE_IAUTH) + /* + ** This could become a bug.. but I don't think iauth needs the + ** hostname/aliases in this case. -kalt + */ + sendto_iauth("%d d", cptr->fd); +#endif + } + + return (IsDead(cptr)) ? -1 : 0; +} + +int hold_server(cptr) +aClient *cptr; +{ + return -1; /* needs to be fixed, don't forget virtual hosts */ + +#if 0 /* code and variables declarations are removed, this + avoids compiler warnings */ + + struct SOCKADDR_IN sin; + aConfItem *aconf; + aClient *acptr; + int fd; + +#ifdef ZIP_LINKS + /* + * reconnecting will not work with compressed links, + * unless someones fixes reconnect and implements what's needed + * to have it work for compressed links. -krys + */ + return -1; +#else + if (!IsServer(cptr) || + !(aconf = find_conf_name(cptr->name, CFLAG))) + return -1; + + if (!aconf->port) + return -1; + + fd = socket(AFINET, SOCK_STREAM, 0); + + if (fd >= MAXCLIENTS) + { + (void)close(fd); + sendto_flag(SCH_ERROR, + "Can't reconnect - all connections in use"); + return -1; + } + + cptr->flags |= FLAGS_HELD; + (void)close(cptr->fd); + del_fd(cptr->fd, &fdall); + del_fd(cptr->fd, &fdas); + cptr->fd = -2; + + acptr = make_client(NULL); + acptr->fd = fd; + acptr->port = aconf->port; + set_non_blocking(acptr->fd, acptr); + (void)set_sock_opts(acptr->fd, acptr); + bzero((char *)&sin, sizeof(sin)); + sin.SIN_FAMILY = AFINET; + sin.SIN_PORT = htons(aconf->port); + bcopy((char *)&cptr->ip, (char *)&sin.SIN_ADDR, sizeof(cptr->ip)); + bcopy((char *)&cptr->ip, (char *)&acptr->ip, sizeof(cptr->ip)); + + if (connect(acptr->fd, (SAP)&sin, sizeof(sin)) < 0 && + errno != EINPROGRESS) + { + report_error("Connect to host %s failed: %s", acptr); /*buggy*/ + (void)close(acptr->fd); + MyFree((char *)acptr); + return -1; + } + + acptr->status = STAT_RECONNECT; + if (acptr->fd > highest_fd) + highest_fd = acptr->fd; + add_fd(acptr->fd, &fdall); + local[acptr->fd] = acptr; + acptr->acpt = &me; + add_client_to_list(acptr); + (void)strcpy(acptr->name, cptr->name); + /* broken syntax + sendto_one(acptr, "PASS %s %s", aconf->passwd, pass_version); + */ + sendto_one(acptr, "RECONNECT %s %d", acptr->name, cptr->sendM); + sendto_flag(SCH_NOTICE, "Reconnecting to %s", acptr->name); + Debug((DEBUG_NOTICE, "Reconnect %s %#x via %#x %d", cptr->name, cptr, + acptr, acptr->fd)); + return 0; +#endif +#endif +} + +/* +** close_connection +** Close the physical connection. This function must make +** MyConnect(cptr) == FALSE, and set cptr->from == NULL. +*/ +void close_connection(cptr) +aClient *cptr; +{ + Reg aConfItem *aconf; + Reg int i,j; +#ifdef SO_LINGER + struct linger sockling; + + sockling.l_onoff = 0; +#endif + + if (IsServer(cptr)) + { + ircstp->is_sv++; + ircstp->is_sbs += cptr->sendB; + ircstp->is_sbr += cptr->receiveB; + ircstp->is_sks += cptr->sendK; + ircstp->is_skr += cptr->receiveK; + ircstp->is_sti += timeofday - cptr->firsttime; + if (ircstp->is_sbs > 1023) + { + ircstp->is_sks += (ircstp->is_sbs >> 10); + ircstp->is_sbs &= 0x3ff; + } + if (ircstp->is_sbr > 1023) + { + ircstp->is_skr += (ircstp->is_sbr >> 10); + ircstp->is_sbr &= 0x3ff; + } + } + else if (IsClient(cptr)) + { + ircstp->is_cl++; + ircstp->is_cbs += cptr->sendB; + ircstp->is_cbr += cptr->receiveB; + ircstp->is_cks += cptr->sendK; + ircstp->is_ckr += cptr->receiveK; + ircstp->is_cti += timeofday - cptr->firsttime; + if (ircstp->is_cbs > 1023) + { + ircstp->is_cks += (ircstp->is_cbs >> 10); + ircstp->is_cbs &= 0x3ff; + } + if (ircstp->is_cbr > 1023) + { + ircstp->is_ckr += (ircstp->is_cbr >> 10); + ircstp->is_cbr &= 0x3ff; + } + } + else + ircstp->is_ni++; + + /* + * remove outstanding DNS queries. + */ + del_queries((char *)cptr); + /* + * If the connection has been up for a long amount of time, schedule + * a 'quick' reconnect, else reset the next-connect cycle. + */ + if ((aconf = find_conf_exact(cptr->name, cptr->username, + cptr->sockhost, CFLAG))) + { + /* + * Reschedule a faster reconnect, if this was a automaticly + * connected configuration entry. (Note that if we have had + * a rehash in between, the status has been changed to + * CONF_ILLEGAL). But only do this if it was a "good" link. + */ + aconf->hold = timeofday; + aconf->hold += (aconf->hold - cptr->since > HANGONGOODLINK) ? + HANGONRETRYDELAY : ConfConFreq(aconf); + if (nextconnect > aconf->hold) + nextconnect = aconf->hold; + } + + if (cptr->authfd >= 0) + { +#ifdef SO_LINGER + if (cptr->exitc == EXITC_PING) + if (SETSOCKOPT(cptr->authfd, SOL_SOCKET, SO_LINGER, + &sockling, sockling)) + report_error("setsockopt(SO_LINGER) %s:%s", + cptr); +#endif + (void)close(cptr->authfd); + } + + if ((i = cptr->fd) >= 0) + { +#if defined(USE_IAUTH) + sendto_iauth("%d D", cptr->fd); +#endif + flush_connections(i); + if (IsServer(cptr) || IsListening(cptr)) + { + del_fd(i, &fdas); +#ifdef ZIP_LINKS + /* + ** the connection might have zip data (even if + ** FLAGS_ZIP is not set) + */ + zip_free(cptr); +#endif + } + else if (IsClient(cptr)) + { +#ifdef SO_LINGER + if (cptr->exitc == EXITC_PING) + if (SETSOCKOPT(i, SOL_SOCKET, SO_LINGER, + &sockling, sockling)) + report_error("setsockopt(SO_LINGER) %s:%s", + cptr); +#endif + } + del_fd(i, &fdall); + local[i] = NULL; + (void)close(i); + + /* + * fd remap to keep local[i] filled at the bottom. + * don't *ever* move descriptors for + * + log file + * + sockets bound to listen() ports + * --Yegg + */ + if (i >= 0 && (j = highest_fd) > i) + { + while (!local[j]) + j--; + if (j > i && local[j] && + !(IsLog(local[j]) || IsMe(local[j]))) + { + if (dup2(j,i) == -1) + return; + local[i] = local[j]; + local[i]->fd = i; + local[j] = NULL; + (void)close(j); + del_fd(j, &fdall); + add_fd(i, &fdall); + if (IsServer(local[i]) || IsMe(local[i])) + { + del_fd(j, &fdas); + add_fd(i, &fdas); + } + while (!local[highest_fd]) + highest_fd--; +#if defined(USE_IAUTH) + sendto_iauth("%d R %d", j, i); +#endif + } + } + cptr->fd = -2; + DBufClear(&cptr->sendQ); + DBufClear(&cptr->recvQ); + bzero(cptr->passwd, sizeof(cptr->passwd)); + /* + * clean up extra sockets from P-lines which have been + * discarded. + */ + if (cptr->acpt != &me) + { + aconf = cptr->acpt->confs->value.aconf; + if (aconf->clients > 0) + aconf->clients--; + if (!aconf->clients && IsIllegal(aconf)) + close_connection(cptr->acpt); + } + } + + det_confs_butmask(cptr, 0); + cptr->from = NULL; /* ...this should catch them! >:) --msa */ + return; +} + +/* +** set_sock_opts +*/ +static int set_sock_opts(fd, cptr) +int fd; +aClient *cptr; +{ + int opt, ret = 0; +#ifdef SO_REUSEADDR + opt = 1; + if (SETSOCKOPT(fd, SOL_SOCKET, SO_REUSEADDR, &opt, opt) < 0) + report_error("setsockopt(SO_REUSEADDR) %s:%s", cptr); +#endif +#if defined(SO_DEBUG) && defined(DEBUGMODE) && 0 +/* Solaris 2.x with SO_DEBUG writes to syslog by default */ +#if ! SOLARIS_2 || defined(USE_SYSLOG) + opt = 1; + if (SETSOCKOPT(fd, SOL_SOCKET, SO_DEBUG, &opt, opt) < 0) + report_error("setsockopt(SO_DEBUG) %s:%s", cptr); +#endif /* SOLARIS_2 */ +#endif +#ifdef SO_USELOOPBACK + opt = 1; + if (SETSOCKOPT(fd, SOL_SOCKET, SO_USELOOPBACK, &opt, opt) < 0) + report_error("setsockopt(SO_USELOOPBACK) %s:%s", cptr); +#endif +#ifdef SO_RCVBUF + opt = 8192; + if (SETSOCKOPT(fd, SOL_SOCKET, SO_RCVBUF, &opt, opt) < 0) + report_error("setsockopt(SO_RCVBUF) %s:%s", cptr); +#endif +#ifdef SO_SNDBUF +# ifdef _SEQUENT_ +/* seems that Sequent freezes up if the receving buffer is a different size + * to the sending buffer (maybe a tcp window problem too). + */ +# endif + opt = 8192; + if (SETSOCKOPT(fd, SOL_SOCKET, SO_SNDBUF, &opt, opt) < 0) + report_error("setsockopt(SO_SNDBUF) %s:%s", cptr); +# ifdef SO_SNDLOWAT + /* + * Setting the low water mark should improve performence by avoiding + * early returns from select()/poll(). It shouldn't delay sending + * data, provided that io_loop() combines read_message() and + * flush_fdary/connections() calls properly. -kalt + * This call isn't always implemented, even when defined.. so be quiet + * about errors. -kalt + */ + opt = 8192; + SETSOCKOPT(fd, SOL_SOCKET, SO_SNDLOWAT, &opt, opt); +# endif +#endif +#if defined(IP_OPTIONS) && defined(IPPROTO_IP) && !defined(AIX) && \ + !defined(SUN_GSO_BUG) && !defined(INET6) + /* + * Mainly to turn off and alert us to source routing, here. + * Method borrowed from Wietse Venema's TCP wrapper. + */ + { + if (!IsUnixSocket(cptr) && !IsListening(cptr)) + { + u_char opbuf[256], *t = opbuf; + char *s = readbuf; + + opt = sizeof(opbuf); + if (GETSOCKOPT(fd, IPPROTO_IP, IP_OPTIONS, t, &opt) == -1) + report_error("getsockopt(IP_OPTIONS) %s:%s", cptr); + else if (opt > 0) + { + for (; opt > 0; opt--, s+= 3) + (void)sprintf(s, " %02x", *t++); + *s = '\0'; + sendto_flag(SCH_NOTICE, + "Connection %s with IP opts%s", + get_client_name(cptr, TRUE), readbuf); + Debug((DEBUG_NOTICE, + "Connection %s with IP opts%s", + get_client_name(cptr, TRUE), readbuf)); + ret = -1; + } + } + } +#endif + return ret; +} + +int get_sockerr(cptr) +aClient *cptr; +{ + int errtmp = errno, err = 0; + SOCK_LEN_TYPE len = sizeof(err); + +#ifdef SO_ERROR + if (cptr->fd >= 0) + if (!GETSOCKOPT(cptr->fd, SOL_SOCKET, SO_ERROR, &err, &len)) + if (err) + errtmp = err; +#endif + return errtmp; +} + +/* +** set_non_blocking +** Set the client connection into non-blocking mode. If your +** system doesn't support this, you can make this a dummy +** function (and get all the old problems that plagued the +** blocking version of IRC--not a problem if you are a +** lightly loaded node...) +*/ +void set_non_blocking(fd, cptr) +int fd; +aClient *cptr; +{ + int res, nonb = 0; + + /* + ** NOTE: consult ALL your relevant manual pages *BEFORE* changing + ** these ioctl's. There are quite a few variations on them, + ** as can be seen by the PCS one. They are *NOT* all the same. + ** Heed this well. - Avalon. + */ +#if NBLOCK_POSIX + nonb |= O_NONBLOCK; +#endif +#if NBLOCK_BSD + nonb |= O_NDELAY; +#endif +#if NBLOCK_SYSV + /* This portion of code might also apply to NeXT. -LynX */ + res = 1; + + if (ioctl (fd, FIONBIO, &res) < 0) + report_error("ioctl(fd,FIONBIO) failed for %s:%s", cptr); +#else + if ((res = fcntl(fd, F_GETFL, 0)) == -1) + report_error("fcntl(fd, F_GETFL) failed for %s:%s",cptr); + else if (fcntl(fd, F_SETFL, res | nonb) == -1) + report_error("fcntl(fd, F_SETL, nonb) failed for %s:%s",cptr); +#endif + return; +} + +#ifdef CLONE_CHECK +/* + * check_clones + * adapted by jecete 4 IRC Ptnet + */ +static int check_clones(cptr) +aClient *cptr; +{ + struct abacklog { + struct IN_ADDR ip; + time_t PT; + struct abacklog *next; + }; + static struct abacklog *backlog = NULL; + register struct abacklog **blscn = &backlog, + *blptr; + register int count = 0; + + /* First, ditch old entries */ + while (*blscn != NULL) + { + if ((*blscn)->PT+CLONE_PERIOD < timeofday) + { + blptr= *blscn; + *blscn=blptr->next; + MyFree((char *)blptr); + } + else + blscn = &(*blscn)->next; + } + /* Now add new item to the list */ + blptr = (struct abacklog *) MyMalloc(sizeof(struct abacklog)); +#ifdef INET6 + bcopy(cptr->ip.s6_addr, blptr->ip.s6_addr, IN6ADDRSZ); +#else + blptr->ip.s_addr = cptr->ip.s_addr; +#endif + blptr->PT = timeofday; + blptr->next = backlog; + backlog = blptr; + + /* Count the number of entries from the same host */ + blptr = backlog; + while (blptr != NULL) + { +#ifdef INET6 + if (bcmp(blptr->ip.s6_addr, cptr->ip.s6_addr, IN6ADDRSZ) == 0) +#else + if (blptr->ip.s_addr == cptr->ip.s_addr) +#endif + count++; + blptr = blptr->next; + } + return (count); +} +#endif + +/* + * Creates a client which has just connected to us on the given fd. + * The sockhost field is initialized with the ip# of the host. + * The client is added to the linked list of clients but isnt added to any + * hash tables yet since it doesnt have a name. + */ +aClient *add_connection(cptr, fd) +aClient *cptr; +int fd; +{ + Link lin; + aClient *acptr; + aConfItem *aconf = NULL; + acptr = make_client(NULL); + + aconf = cptr->confs->value.aconf; + /* Removed preliminary access check. Full check is performed in + * m_server and m_user instead. Also connection time out help to + * get rid of unwanted connections. + */ + if (isatty(fd)) /* If descriptor is a tty, special checking... */ + get_sockhost(acptr, cptr->sockhost); + else + { + struct SOCKADDR_IN addr; + SOCK_LEN_TYPE len = sizeof(struct SOCKADDR_IN); + + if (getpeername(fd, (SAP)&addr, &len) == -1) + { +#if defined(linux) + if (errno != ENOTCONN) +#endif + report_error("Failed in connecting to %s :%s", + cptr); +add_con_refuse: + ircstp->is_ref++; + acptr->fd = -2; + free_client(acptr); + (void)close(fd); + return NULL; + } + /* don't want to add "Failed in connecting to" here.. */ + if (aconf && IsIllegal(aconf)) + goto add_con_refuse; + /* Copy ascii address to 'sockhost' just in case. Then we + * have something valid to put into error messages... + */ +#ifdef INET6 + inetntop(AF_INET6, (char *)&addr.sin6_addr, mydummy, + MYDUMMY_SIZE); + get_sockhost(acptr, (char *)mydummy); +#else + get_sockhost(acptr, (char *)inetntoa((char *)&addr.sin_addr)); +#endif + bcopy ((char *)&addr.SIN_ADDR, (char *)&acptr->ip, + sizeof(struct IN_ADDR)); + acptr->port = ntohs(addr.SIN_PORT); + + lin.flags = ASYNC_CLIENT; + lin.value.cptr = acptr; +#ifdef INET6 + Debug((DEBUG_DNS, "lookup %s", + inet_ntop(AF_INET6, (char *)&addr.sin6_addr, + mydummy, MYDUMMY_SIZE))); +#else + Debug((DEBUG_DNS, "lookup %s", + inetntoa((char *)&addr.sin_addr))); +#endif + acptr->hostp = gethost_byaddr((char *)&acptr->ip, &lin); + if (!acptr->hostp) + SetDNS(acptr); + nextdnscheck = 1; + } + +#ifdef CLONE_CHECK + if (check_clones(acptr) > CLONE_MAX) + { + sendto_flag(SCH_LOCAL, "Rejecting connection from %s[%s].", + (acptr->hostp) ? acptr->hostp->h_name : "", + acptr->sockhost); + sendto_flog(acptr, " ?Clone? ", 0, "<none>", + (acptr->hostp) ? acptr->hostp->h_name : + acptr->sockhost); + del_queries((char *)acptr); +# ifdef INET6 + (void)sendto(acptr->fd, + "ERROR :Too rapid connections from your host\r\n", + 46, 0, 0, 0); +# else + (void)send(acptr->fd, + "ERROR :Too rapid connections from your host\r\n", + 46, 0); +# endif + goto add_con_refuse; + } +#endif + acptr->fd = fd; + set_non_blocking(acptr->fd, acptr); + if (set_sock_opts(acptr->fd, acptr) == -1) + goto add_con_refuse; + if (aconf) + aconf->clients++; + if (fd > highest_fd) + highest_fd = fd; + local[fd] = acptr; + add_fd(fd, &fdall); + acptr->acpt = cptr; + add_client_to_list(acptr); + start_auth(acptr); +#if defined(USE_IAUTH) + if (!isatty(fd) && !DoingDNS(acptr)) + { + int i = 0; + + while (acptr->hostp->h_aliases[i]) + sendto_iauth("%d A %s", acptr->fd, + acptr->hostp->h_aliases[i++]); + if (acptr->hostp->h_name) + sendto_iauth("%d N %s",acptr->fd,acptr->hostp->h_name); + else if (acptr->hostp->h_aliases[0]) + sendto_iauth("%d n", acptr->fd); + } +#endif + return acptr; +} + +#ifdef UNIXPORT +static void add_unixconnection(cptr, fd) +aClient *cptr; +int fd; +{ + aClient *acptr; + aConfItem *aconf = NULL; + + acptr = make_client(NULL); + + /* Copy ascii address to 'sockhost' just in case. Then we + * have something valid to put into error messages... + */ + get_sockhost(acptr, me.sockhost); + aconf = cptr->confs->value.aconf; + if (aconf) + { + if (IsIllegal(aconf)) + { + ircstp->is_ref++; + acptr->fd = -2; + free_client(acptr); + (void)close(fd); + return; + } + else + aconf->clients++; + } + acptr->fd = fd; + if (fd > highest_fd) + highest_fd = fd; + local[fd] = acptr; + add_fd(fd, &fdall); + acptr->acpt = cptr; + SetUnixSock(acptr); + bcopy((char *)&me.ip, (char *)&acptr->ip, sizeof(struct IN_ADDR)); + + add_client_to_list(acptr); + set_non_blocking(acptr->fd, acptr); + (void)set_sock_opts(acptr->fd, acptr); + return; +} +#endif + +/* +** read_listener +** +** Accept incoming connections, extracted from read_message() 98/12 -kalt +** Up to 10 connections will be accepted, unless SLOW_ACCEPT is defined. +*/ +static void +read_listener(cptr) +aClient *cptr; +{ + int fdnew, max = 10; + +#if defined(SLOW_ACCEPT) + max = 1; +#endif + while (max--) + { + /* + ** There may be many reasons for error return, but in otherwise + ** correctly working environment the probable cause is running + ** out of file descriptors (EMFILE, ENFILE or others?). The + ** man pages for accept don't seem to list these as possible, + ** although it's obvious that it may happen here. + ** Thus no specific errors are tested at this point, just + ** assume that connections cannot be accepted until some old + ** is closed first. + */ + if ((fdnew = accept(cptr->fd, NULL, NULL)) < 0) + { + if (errno != EWOULDBLOCK) + report_error("Cannot accept connections %s:%s", + cptr); + break; + } + ircstp->is_ac++; + if (fdnew >= MAXCLIENTS) + { + ircstp->is_ref++; + sendto_flag(SCH_ERROR, "All connections in use. (%s)", + get_client_name(cptr, TRUE)); + find_bounce(NULL, 0, fdnew); +#ifdef INET6 + (void)sendto(fdnew, + "ERROR :All connections in use\r\n", + 32, 0, 0, 0); +#else + (void)send(fdnew, "ERROR :All connections in use\r\n", + 32, 0); +#endif + (void)close(fdnew); + continue; + } + /* + * Use of add_connection (which never fails :) meLazy + * Never say never. MrMurphy visited here. -Vesa + */ +#ifdef UNIXPORT + if (IsUnixSocket(cptr)) + add_unixconnection(cptr, fdnew); + else +#endif + if (!add_connection(cptr, fdnew)) + continue; + nextping = timeofday; /* isn't this abusive? -kalt */ + istat.is_unknown++; + } +} + +/* +** client_packet +** +** Process data from receive buffer to client. +** Extracted from read_packet() 960804/291p3/Vesa +*/ +static int client_packet(cptr) +Reg aClient *cptr; +{ + Reg int dolen = 0; + + while (DBufLength(&cptr->recvQ) && !NoNewLine(cptr) && + ((cptr->status < STAT_UNKNOWN) || + (cptr->since - timeofday < MAXPENALTY))) + { + /* + ** If it has become registered as a Service or Server + ** then skip the per-message parsing below. + */ + if (IsService(cptr) || IsServer(cptr)) + { + dolen = dbuf_get(&cptr->recvQ, readbuf, + sizeof(readbuf)); + if (dolen <= 0) + break; + dolen = dopacket(cptr, readbuf, dolen); + if (dolen == 2 && cptr->since == cptr->lasttime) + cptr->since += 5; + if (dolen) + return dolen; + break; + } + dolen = dbuf_getmsg(&cptr->recvQ, readbuf, + sizeof(readbuf)); + /* + ** Devious looking...whats it do ? well..if a client + ** sends a *long* message without any CR or LF, then + ** dbuf_getmsg fails and we pull it out using this + ** loop which just gets the next 512 bytes and then + ** deletes the rest of the buffer contents. + ** -avalon + */ + while (dolen <= 0) + { + if (dolen < 0) + return exit_client(cptr, cptr, &me, + "dbuf_getmsg fail"); + if (DBufLength(&cptr->recvQ) < 510) + { /* hmm? */ + cptr->flags |= FLAGS_NONL; + break; + } + dolen = dbuf_get(&cptr->recvQ, readbuf, 511); + if (dolen > 0 && DBufLength(&cptr->recvQ)) + DBufClear(&cptr->recvQ); + } + + /* Is it okay not to test for other return values? -krys */ + if (dolen > 0 && + (dopacket(cptr, readbuf, dolen) == FLUSH_BUFFER)) + return FLUSH_BUFFER; + } + return 1; +} + +/* +** read_packet +** +** Read a 'packet' of data from a connection and process it. Read in 8k +** chunks to give a better performance rating (for server connections). +** Do some tricky stuff for client connections to make sure they don't do +** any flooding >:-) -avalon +*/ +static int read_packet(cptr, msg_ready) +Reg aClient *cptr; +int msg_ready; +{ + Reg int length = 0, done; + + if (msg_ready && + !(IsPerson(cptr) && DBufLength(&cptr->recvQ) > 6090)) + { + errno = 0; +#ifdef INET6 + length = recvfrom(cptr->fd, readbuf, sizeof(readbuf), 0, 0, 0); +#else + length = recv(cptr->fd, readbuf, sizeof(readbuf), 0); +#endif +#if defined(DEBUGMODE) && defined(DEBUG_READ) + if (length > 0) + Debug((DEBUG_READ, + "recv = %d bytes from %d[%s]:[%*.*s]\n", + length, cptr->fd, cptr->name, length, length, + readbuf)); +#endif + + Debug((DEBUG_DEBUG, "Received %d(%d-%s) bytes from %d %s", + length, errno, strerror(errno), + cptr->fd, get_client_name(cptr, TRUE))); + cptr->lasttime = timeofday; + if (cptr->lasttime > cptr->since) + cptr->since = cptr->lasttime; + cptr->flags &= ~(FLAGS_PINGSENT|FLAGS_NONL); + /* + * If not ready, fake it so it isnt closed + */ + if (length == -1 && + ((errno == EWOULDBLOCK) || (errno == EAGAIN))) + return 1; + if (length <= 0) + return length; + } + else if (msg_ready) + return exit_client(cptr, cptr, &me, "EOF From Client"); + + /* + ** For server connections, we process as many as we can without + ** worrying about the time of day or anything :) + */ + if (IsServer(cptr) || IsConnecting(cptr) || IsHandshake(cptr) || + IsService(cptr)) + { + if (length > 0) + { + done = dopacket(cptr, readbuf, length); + if (done && done != 2) + return done; + } + } + else + { + /* + ** Before we even think of parsing what we just read, stick + ** it on the end of the receive queue and do it when its + ** turn comes around. + */ + if (length && dbuf_put(&cptr->recvQ, readbuf, length) < 0) + return exit_client(cptr, cptr, &me, "dbuf_put fail"); + + if (IsPerson(cptr) && + DBufLength(&cptr->recvQ) > CLIENT_FLOOD) + { + cptr->exitc = EXITC_FLOOD; + return exit_client(cptr, cptr, &me, "Excess Flood"); + } + + return client_packet(cptr); + } + return 1; +} + + +/* + * Check all connections for new connections and input data that is to be + * processed. Also check for connections with data queued and whether we can + * write it out. + */ +int read_message(delay, fdp, ro) +time_t delay; /* Don't ever use ZERO here, unless you mean to poll and then + * you have to have sleep/wait somewhere else in the code.--msa + * Actually, ZERO is NOT ZERO anymore.. see below -kalt + */ +FdAry *fdp; +int ro; +{ +#if ! USE_POLL +# define SET_READ_EVENT( thisfd ) FD_SET( thisfd, &read_set) +# define SET_WRITE_EVENT( thisfd ) FD_SET( thisfd, &write_set) +# define CLR_READ_EVENT( thisfd ) FD_CLR( thisfd, &read_set) +# define CLR_WRITE_EVENT( thisfd ) FD_CLR( thisfd, &write_set) +# define TST_READ_EVENT( thisfd ) FD_ISSET( thisfd, &read_set) +# define TST_WRITE_EVENT( thisfd ) FD_ISSET( thisfd, &write_set) + + fd_set read_set, write_set; + int highfd = -1; +#else +/* most of the following use pfd */ +# define POLLSETREADFLAGS (POLLIN|POLLRDNORM) +# define POLLREADFLAGS (POLLSETREADFLAGS|POLLHUP|POLLERR) +# define POLLSETWRITEFLAGS (POLLOUT|POLLWRNORM) +# define POLLWRITEFLAGS (POLLOUT|POLLWRNORM|POLLHUP|POLLERR) + +# define SET_READ_EVENT( thisfd ){ CHECK_PFD( thisfd );\ + pfd->events |= POLLSETREADFLAGS;} +# define SET_WRITE_EVENT( thisfd ){ CHECK_PFD( thisfd );\ + pfd->events |= POLLSETWRITEFLAGS;} + +# define CLR_READ_EVENT( thisfd ) pfd->revents &= ~POLLSETREADFLAGS +# define CLR_WRITE_EVENT( thisfd ) pfd->revents &= ~POLLSETWRITEFLAGS +# define TST_READ_EVENT( thisfd ) pfd->revents & POLLREADFLAGS +# define TST_WRITE_EVENT( thisfd ) pfd->revents & POLLWRITEFLAGS + +# define CHECK_PFD( thisfd ) \ + if ( pfd->fd != thisfd ) { \ + pfd = &poll_fdarray[nbr_pfds++];\ + pfd->fd = thisfd; \ + pfd->events = 0; \ + } + + struct pollfd poll_fdarray[MAXCONNECTIONS]; + struct pollfd * pfd = poll_fdarray; + struct pollfd * res_pfd = NULL; + struct pollfd * udp_pfd = NULL; + struct pollfd * ad_pfd = NULL; + aClient * authclnts[MAXCONNECTIONS]; /* mapping of auth fds to client ptrs */ + int nbr_pfds = 0; +#endif + + aClient *cptr; + int nfds, ret = 0; + struct timeval wait; + time_t delay2 = delay; + int res, length, fd, i; + int auth; + + for (res = 0;;) + { +#if ! USE_POLL + FD_ZERO(&read_set); + FD_ZERO(&write_set); +#else + /* set up such that CHECK_FD works */ + nbr_pfds = 0; + pfd = poll_fdarray; + pfd->fd = -1; + res_pfd = NULL; + udp_pfd = NULL; + ad_pfd = NULL; +#endif /* USE_POLL */ + auth = 0; + +#if USE_POLL + if ( auth == 0 ) + bzero((char *) authclnts, sizeof( authclnts )); +#endif + for (i = fdp->highest; i >= 0; i--) + { + if (!(cptr = local[fd = fdp->fd[i]]) || + IsLog(cptr) || IsHeld(cptr)) + continue; + Debug((DEBUG_L11, "fd %d cptr %#x %d %#x %s", + fd, cptr, cptr->status, cptr->flags, + get_client_name(cptr,TRUE))); + /* authentication fd's */ + if (DoingAuth(cptr)) + { + auth++; + SET_READ_EVENT(cptr->authfd); + Debug((DEBUG_NOTICE,"auth on %x %d", cptr, + fd)); + if (cptr->flags & FLAGS_WRAUTH) + SET_WRITE_EVENT(cptr->authfd); +#if USE_POLL + authclnts[cptr->authfd] = cptr; +#else + if (cptr->authfd > highfd) + highfd = cptr->authfd; +#endif + } + /* + ** if any of these is true, data won't be parsed + ** so no need to check for anything! + */ +#if defined(USE_IAUTH) + if (DoingDNS(cptr) || DoingAuth(cptr) || + WaitingXAuth(cptr) || + (DoingXAuth(cptr) && + !(iauth_options & XOPT_EARLYPARSE))) +#else + if (DoingDNS(cptr) || DoingAuth(cptr)) +#endif + continue; +#if ! USE_POLL + if (fd > highfd) + highfd = fd; +#endif + /* + ** Checking for new connections is only done up to + ** once per second. + */ + if (IsListening(cptr)) + { + if (timeofday > cptr->lasttime + 1 && ro == 0) + { + SET_READ_EVENT( fd ); + } + else if (delay2 > 1) + delay2 = 1; + continue; + } + + /* + ** This is very approximate, it should take + ** cptr->since into account. -kalt + */ + if (DBufLength(&cptr->recvQ) && delay2 > 2) + delay2 = 1; + + if (IsRegisteredUser(cptr)) + { + if (cptr->since - timeofday < MAXPENALTY+1) + SET_READ_EVENT( fd ); + } + else if (DBufLength(&cptr->recvQ) < 4088) + SET_READ_EVENT( fd ); + + /* + ** If we have anything in the sendQ, check if there is + ** room to write data. + */ + if (DBufLength(&cptr->sendQ) || IsConnecting(cptr) || +#ifdef ZIP_LINKS + ((cptr->flags & FLAGS_ZIP) && + (cptr->zip->outcount > 0)) || +#endif + IsReconnect(cptr)) + if (IsServer(cptr) || IsConnecting(cptr) || + ro == 0) + SET_WRITE_EVENT( fd ); + } + + if (udpfd >= 0) + { + SET_READ_EVENT(udpfd); +#if ! USE_POLL + if (udpfd > highfd) + highfd = udpfd; +#else + udp_pfd = pfd; +#endif + } + if (resfd >= 0) + { + SET_READ_EVENT(resfd); +#if ! USE_POLL + if (resfd > highfd) + highfd = resfd; +#else + res_pfd = pfd; +#endif + } +#if defined(USE_IAUTH) + if (adfd >= 0) + { + SET_READ_EVENT(adfd); +# if ! USE_POLL + if (adfd > highfd) + highfd = adfd; +# else + ad_pfd = pfd; +# endif + } +#endif + Debug((DEBUG_L11, "udpfd %d resfd %d adfd %d", udpfd, resfd, + adfd)); +#if ! USE_POLL + Debug((DEBUG_L11, "highfd %d", highfd)); +#endif + + wait.tv_sec = MIN(delay2, delay); + wait.tv_usec = (delay == 0) ? 200000 : 0; +#if ! USE_POLL + nfds = select(highfd + 1, (SELECT_FDSET_TYPE *)&read_set, + (SELECT_FDSET_TYPE *)&write_set, 0, &wait); +#else + nfds = poll( poll_fdarray, nbr_pfds, + wait.tv_sec * 1000 + wait.tv_usec/1000 ); +#endif + ret = nfds; + if (nfds == -1 && errno == EINTR) + return -1; + else if (nfds >= 0) + break; +#if ! USE_POLL + report_error("select %s:%s", &me); +#else + report_error("poll %s:%s", &me); +#endif + res++; + if (res > 5) + restart("too many select()/poll() errors"); + sleep(10); + timeofday = time(NULL); + } /* for(res=0;;) */ + + timeofday = time(NULL); + if (nfds > 0 && +#if ! USE_POLL + resfd >= 0 && +#else + (pfd = res_pfd) && +#endif + TST_READ_EVENT(resfd)) + { + CLR_READ_EVENT(resfd); + nfds--; + do_dns_async(); + } + if (nfds > 0 && +#if ! USE_POLL + udpfd >= 0 && +#else + (pfd = udp_pfd) && +#endif + TST_READ_EVENT(udpfd)) + { + CLR_READ_EVENT(udpfd); + nfds--; + polludp(); + } +#if defined(USE_IAUTH) + if (nfds > 0 && +# if ! USE_POLL + adfd >= 0 && +# else + (pfd = ad_pfd) && +# endif + TST_READ_EVENT(adfd)) + { + CLR_READ_EVENT(adfd); + nfds--; + read_iauth(); + } +#endif + +#if ! USE_POLL + for (i = fdp->highest; i >= 0; i--) +#else + for (pfd = poll_fdarray, i = 0; i < nbr_pfds; i++, pfd++ ) +#endif + { +#if ! USE_POLL + if (!(cptr = local[fd = fdp->fd[i]])) + continue; +#else + fd = pfd->fd; + if ((cptr = authclnts[fd])) + { +#endif + /* + * check for the auth fd's + */ + if (auth > 0 && nfds > 0 +#if ! USE_POLL + && cptr->authfd >= 0 +#endif + ) + { + auth--; + if (TST_WRITE_EVENT(cptr->authfd)) + { + nfds--; + send_authports(cptr); + } + else if (TST_READ_EVENT(cptr->authfd)) + { + nfds--; + read_authports(cptr); + } + continue; + } +#if USE_POLL + } + fd = pfd->fd; + if (!(cptr = local[fd])) + continue; +#else + fd = cptr->fd; +#endif + /* + * accept connections + */ + if (TST_READ_EVENT(fd) && IsListening(cptr)) + { + CLR_READ_EVENT(fd); + cptr->lasttime = timeofday; + read_listener(cptr); + continue; + } + if (IsMe(cptr)) + continue; + if (TST_WRITE_EVENT(fd)) + { + int write_err = 0; + /* + ** ...room for writing, empty some queue then... + */ + if (IsConnecting(cptr)) + write_err = completed_connection(cptr); + if (!write_err) + (void)send_queued(cptr); + if (IsDead(cptr) || write_err) + { +deadsocket: + if (TST_READ_EVENT(fd)) + CLR_READ_EVENT(fd); + cptr->exitc = EXITC_ERROR; + (void)exit_client(cptr, cptr, &me, + strerror(get_sockerr(cptr))); + continue; + } + } + length = 1; /* for fall through case */ + if (!NoNewLine(cptr) || TST_READ_EVENT(fd)) + { + if (!DoingAuth(cptr)) + length = read_packet(cptr, TST_READ_EVENT(fd)); + } + readcalls++; + if (length == FLUSH_BUFFER) + continue; + else if (length > 0) + flush_connections(cptr->fd); + if (IsDead(cptr)) + goto deadsocket; + if (length > 0) + continue; + + /* Ghost! Unknown users are tagged in parse() since 2.9. + * Let's not drop the uplink but just the ghost's message. + */ + if (length == -3) + continue; + + /* + ** NB: This following section has been modified to *expect* + ** cptr to be valid (ie if (length == FLUSH_BUFFER) is + ** above and stays there). - avalon 24/9/94 + */ + /* + ** ...hmm, with non-blocking sockets we might get + ** here from quite valid reasons, although.. why + ** would select report "data available" when there + ** wasn't... so, this must be an error anyway... --msa + ** actually, EOF occurs when read() returns 0 and + ** in due course, select() returns that fd as ready + ** for reading even though it ends up being an EOF. -avalon + */ + Debug((DEBUG_ERROR, "READ ERROR: fd = %d %d %d", + cptr->fd, errno, length)); + + if (IsServer(cptr) || IsHandshake(cptr)) + { + int timeconnected = timeofday - cptr->firsttime; + + if (length == 0) + sendto_flag(SCH_NOTICE, + "Server %s closed the connection (%d, %2d:%02d:%02d)", + get_client_name(cptr, FALSE), + timeconnected / 86400, + (timeconnected % 86400) / 3600, + (timeconnected % 3600)/60, + timeconnected % 60); + else /* this must be for -1 */ + { + report_error("Lost connection to %s:%s",cptr); + sendto_flag(SCH_NOTICE, + "%s had been connected for %d, %2d:%02d:%02d", + get_client_name(cptr, FALSE), + timeconnected / 86400, + (timeconnected % 86400) / 3600, + (timeconnected % 3600)/60, + timeconnected % 60); + if (hold_server(cptr) == 0) + continue; + } + } + (void)exit_client(cptr, cptr, &me, length >= 0 ? + "EOF From client" : + strerror(get_sockerr(cptr))); + } /* for(i) */ + return ret; +} + +/* + * connect_server + */ +int connect_server(aconf, by, hp) +aConfItem *aconf; +aClient *by; +struct hostent *hp; +{ + Reg struct SOCKADDR *svp; + Reg aClient *cptr, *c2ptr; + Reg char *s; + int i, len; + +#ifdef INET6 + Debug((DEBUG_NOTICE,"Connect to %s[%s] @%s", + aconf->name, aconf->host, + inet_ntop(AF_INET6, (char *)&aconf->ipnum, mydummy, + MYDUMMY_SIZE))); +#else + Debug((DEBUG_NOTICE,"Connect to %s[%s] @%s", + aconf->name, aconf->host, + inetntoa((char *)&aconf->ipnum))); +#endif + + if ((c2ptr = find_server(aconf->name, NULL))) + { + sendto_flag(SCH_NOTICE, "Server %s already present from %s", + aconf->name, get_client_name(c2ptr, TRUE)); + if (by && IsPerson(by) && !MyClient(by)) + sendto_one(by, + ":%s NOTICE %s :Server %s already present from %s", + ME, by->name, aconf->name, + get_client_name(c2ptr, TRUE)); + return -1; + } + + /* + * If we don't know the IP# for this host and it is a hostname and + * not a ip# string, then try and find the appropriate host record. + */ + if (!aconf->ipnum.S_ADDR && *aconf->host != '/') + { + Link lin; + + lin.flags = ASYNC_CONNECT; + lin.value.aconf = aconf; + nextdnscheck = 1; + s = (char *)index(aconf->host, '@'); + s++; /* should NEVER be NULL */ +#ifdef INET6 + if (!inet_pton(AF_INET6, s, aconf->ipnum.s6_addr)) +#else + if ((aconf->ipnum.s_addr = inetaddr(s)) == -1) +#endif + { +#ifdef INET6 + bzero(aconf->ipnum.s6_addr, IN6ADDRSZ); +#else + aconf->ipnum.s_addr = 0; +#endif + hp = gethost_byname(s, &lin); + Debug((DEBUG_NOTICE, "co_sv: hp %x ac %x na %s ho %s", + hp, aconf, aconf->name, s)); + if (!hp) + return 0; + bcopy(hp->h_addr, (char *)&aconf->ipnum, + sizeof(struct IN_ADDR)); + } + } + cptr = make_client(NULL); + cptr->hostp = hp; + /* + * Copy these in so we have something for error detection. + */ + strncpyzt(cptr->name, aconf->name, sizeof(cptr->name)); + strncpyzt(cptr->sockhost, aconf->host, HOSTLEN+1); + +#ifdef UNIXPORT + if (*aconf->host == '/') /* (/ starts a 2), Unix domain -- dl*/ + svp = connect_unix(aconf, cptr, &len); + else + svp = connect_inet(aconf, cptr, &len); +#else + svp = connect_inet(aconf, cptr, &len); +#endif + + if (!svp) + { + if (cptr->fd != -1) + (void)close(cptr->fd); + cptr->fd = -2; + free_client(cptr); + return -1; + } + + set_non_blocking(cptr->fd, cptr); + (void)set_sock_opts(cptr->fd, cptr); + (void)signal(SIGALRM, dummy); + (void)alarm(4); + if (connect(cptr->fd, (SAP)svp, len) < 0 && errno != EINPROGRESS) + { + i = errno; /* other system calls may eat errno */ + (void)alarm(0); + report_error("Connect to host %s failed: %s",cptr); + if (by && IsPerson(by) && !MyClient(by)) + sendto_one(by, + ":%s NOTICE %s :Connect to host %s failed.", + ME, by->name, cptr); + (void)close(cptr->fd); + cptr->fd = -2; + free_client(cptr); + errno = i; + if (errno == EINTR) + errno = ETIMEDOUT; + return -1; + } + (void)alarm(0); + + /* Attach config entries to client here rather than in + * completed_connection. This to avoid null pointer references + * when name returned by gethostbyaddr matches no C lines + * (could happen in 2.6.1a when host and servername differ). + * No need to check access and do gethostbyaddr calls. + * There must at least be one as we got here C line... meLazy + */ + (void)attach_confs_host(cptr, aconf->host, CFLAG|NFLAG); + + if (!find_conf_host(cptr->confs, aconf->host, NFLAG) || + !find_conf_host(cptr->confs, aconf->host, CFLAG)) + { + sendto_flag(SCH_NOTICE, + "Host %s is not enabled for connecting:no C/N-line", + aconf->host); + if (by && IsPerson(by) && !MyClient(by)) + sendto_one(by, + ":%s NOTICE %s :Connect to host %s failed.", + ME, by->name, cptr); + det_confs_butmask(cptr, 0); + (void)close(cptr->fd); + cptr->fd = -2; + free_client(cptr); + return(-1); + } + /* + ** The socket has been connected or connect is in progress. + */ + (void)make_server(cptr); + if (by && IsPerson(by)) + { + (void)strcpy(cptr->serv->by, by->name); + cptr->serv->user = by->user; + by->user->refcnt++; + } + else + (void)strcpy(cptr->serv->by, "AutoConn."); + cptr->serv->up = ME; + cptr->serv->nline = aconf; + if (cptr->fd > highest_fd) + highest_fd = cptr->fd; + add_fd(cptr->fd, &fdall); + local[cptr->fd] = cptr; + cptr->acpt = &me; + SetConnecting(cptr); + + get_sockhost(cptr, aconf->host); + add_client_to_list(cptr); + nextping = timeofday; + istat.is_unknown++; + + return 0; +} + +static struct SOCKADDR *connect_inet(aconf, cptr, lenp) +Reg aConfItem *aconf; +Reg aClient *cptr; +int *lenp; +{ + static struct SOCKADDR_IN server; + Reg struct hostent *hp; + aClient *acptr; + int i; + + /* + * Might as well get sockhost from here, the connection is attempted + * with it so if it fails its useless. + */ + cptr->fd = socket(AFINET, SOCK_STREAM, 0); + if (cptr->fd >= MAXCLIENTS) + { + sendto_flag(SCH_NOTICE, + "No more connections allowed (%s)", cptr->name); + return NULL; + } + mysk.SIN_PORT = 0; + bzero((char *)&server, sizeof(server)); + server.SIN_FAMILY = AFINET; + get_sockhost(cptr, aconf->host); + + if (cptr->fd == -1) + { + report_error("opening stream socket to server %s:%s", cptr); + return NULL; + } + /* + ** Bind to a local IP# (with unknown port - let unix decide) so + ** we have some chance of knowing the IP# that gets used for a host + ** with more than one IP#. + ** With VIFs, M:line defines outgoing IP# and initialises mysk. + */ + if (bind(cptr->fd, (SAP)&mysk, sizeof(mysk)) == -1) + { + report_error("error binding to local port for %s:%s", cptr); + return NULL; + } + /* + * By this point we should know the IP# of the host listed in the + * conf line, whether as a result of the hostname lookup or the ip# + * being present instead. If we don't know it, then the connect fails. + */ +#ifdef INET6 + if (isdigit(*aconf->host) && (AND16(aconf->ipnum.s6_addr) == 255)) + if (!inet_pton(AF_INET6, aconf->host,aconf->ipnum.s6_addr)) + bcopy(minus_one, aconf->ipnum.s6_addr, IN6ADDRSZ); + if (AND16(aconf->ipnum.s6_addr) == 255) +#else + if (isdigit(*aconf->host) && (aconf->ipnum.s_addr == -1)) + aconf->ipnum.s_addr = inetaddr(aconf->host); + if (aconf->ipnum.s_addr == -1) +#endif + { + hp = cptr->hostp; + if (!hp) + { + Debug((DEBUG_FATAL, "%s: unknown host", aconf->host)); + return NULL; + } + bcopy(hp->h_addr, (char *)&aconf->ipnum, + sizeof(struct IN_ADDR)); + } + bcopy((char *)&aconf->ipnum, (char *)&server.SIN_ADDR, + sizeof(struct IN_ADDR)); + bcopy((char *)&aconf->ipnum, (char *)&cptr->ip, + sizeof(struct IN_ADDR)); + cptr->port = (aconf->port > 0) ? aconf->port : portnum; + server.SIN_PORT = htons(cptr->port); + /* + * Look for a duplicate IP#,port pair among already open connections + * (This caters for unestablished connections). + */ + for (i = highest_fd; i >= 0; i--) + if ((acptr = local[i]) && + !bcmp((char *)&cptr->ip, (char *)&acptr->ip, + sizeof(cptr->ip)) && server.SIN_PORT == acptr->port) + return NULL; + *lenp = sizeof(server); + return (struct SOCKADDR *)&server; +} + +#ifdef UNIXPORT +/* connect_unix + * + * Build a socket structure for cptr so that it can connet to the unix + * socket defined by the conf structure aconf. + */ +static struct SOCKADDR *connect_unix(aconf, cptr, lenp) +aConfItem *aconf; +aClient *cptr; +int *lenp; +{ + static struct sockaddr_un sock; + + if ((cptr->fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + { + report_error("Unix domain connect to host %s failed: %s", cptr); + return NULL; + } + else if (cptr->fd >= MAXCLIENTS) + { + sendto_flag(SCH_NOTICE, + "No more connections allowed (%s)", cptr->name); + return NULL; + } + + get_sockhost(cptr, aconf->host); + strncpyzt(sock.sun_path, aconf->host + 2, sizeof(sock.sun_path)); + sock.sun_family = AF_UNIX; + *lenp = strlen(sock.sun_path) + 2; + + SetUnixSock(cptr); + return (struct sockaddr *)&sock; +} +#endif + +/* + * The following section of code performs summoning of users to irc. + */ +#if defined(ENABLE_SUMMON) || defined(ENABLE_USERS) +int utmp_open() +{ +#ifdef O_NOCTTY + return (open(UTMP, O_RDONLY|O_NOCTTY)); +#else + return (open(UTMP, O_RDONLY)); +#endif +} + +int utmp_read(fd, name, line, host, hlen) +int fd, hlen; +char *name, *line, *host; +{ + struct utmp ut; + while (read(fd, (char *)&ut, sizeof (struct utmp)) + == sizeof (struct utmp)) + { + strncpyzt(name, ut.ut_name, 9); + strncpyzt(line, ut.ut_line, 10); +#ifdef USER_PROCESS +# if defined(HPUX) || defined(AIX) + strncpyzt(host,(ut.ut_host[0]) ? (ut.ut_host) : ME, 16); +# else + strncpyzt(host, ME, 9); +# endif + if (ut.ut_type == USER_PROCESS) + return 0; +#else + strncpyzt(host, (ut.ut_host[0]) ? (ut.ut_host) : ME, + hlen); + if (ut.ut_name[0]) + return 0; +#endif + } + return -1; +} + +int utmp_close(fd) +int fd; +{ + return(close(fd)); +} + +#ifdef ENABLE_SUMMON +void summon(who, namebuf, linebuf, chname) +aClient *who; +char *namebuf, *linebuf, *chname; +{ + static char wrerr[] = "NOTICE %s :Write error. Couldn't summon."; + int fd; + char line[120]; + struct tm *tp; + + tp = localtime(&timeofday); + if (strlen(linebuf) > (size_t) 9) + { + sendto_one(who,"NOTICE %s :Serious fault in SUMMON.", + who->name); + sendto_one(who, + "NOTICE %s :linebuf too long. Inform Administrator", + who->name); + return; + } + /* + * Following line added to prevent cracking to e.g. /dev/kmem if + * UTMP is for some silly reason writable to everyone... + */ + if ((linebuf[0] != 't' || linebuf[1] != 't' || linebuf[2] != 'y') + && (linebuf[0] != 'c' || linebuf[1] != 'o' || linebuf[2] != 'n') +#ifdef HPUX + && (linebuf[0] != 'p' || linebuf[1] != 't' || linebuf[2] != 'y' || + linebuf[3] != '/') +#endif + ) + { + sendto_one(who, + "NOTICE %s :Looks like mere mortal souls are trying to", + who->name); + sendto_one(who,"NOTICE %s :enter the twilight zone... ", + who->name); + Debug((0, "%s (%s@%s, nick %s, %s)", + "FATAL: major security hack. Notify Administrator !", + who->username, who->user->host, + who->name, who->info)); + return; + } + + SPRINTF(line,"/dev/%s", linebuf); + (void)alarm(5); +#ifdef O_NOCTTY + if ((fd = open(line, O_WRONLY | O_NDELAY | O_NOCTTY)) == -1) +#else + if ((fd = open(line, O_WRONLY | O_NDELAY)) == -1) +#endif + { + (void)alarm(0); + sendto_one(who, + "NOTICE %s :%s seems to have disabled summoning...", + who->name, namebuf); + return; + } +#if !defined(O_NOCTTY) && defined(TIOCNOTTY) + (void)ioctl(fd, TIOCNOTTY, NULL); +#endif + (void)alarm(0); + (void)sprintf(line,"\n\r\007Message from IRC_Daemon@%s at %d:%02d\n\r", + ME, tp->tm_hour, tp->tm_min); + if (write(fd, line, strlen(line)) != strlen(line)) + { + (void)alarm(0); + (void)close(fd); + sendto_one(who, wrerr, who->name); + return; + } + (void)alarm(0); + (void)strcpy(line, "ircd: You are being summoned to Internet Relay \ +Chat on\n\r"); + (void)alarm(5); + if (write(fd, line, strlen(line)) != strlen(line)) + { + (void)alarm(0); + (void)close(fd); + sendto_one(who, wrerr, who->name); + return; + } + (void)alarm(0); + SPRINTF(line, "ircd: Channel %s, by %s@%s (%s) %s\n\r", chname, + who->user->username, who->user->host, who->name, who->info); + (void)alarm(5); + if (write(fd, line, strlen(line)) != strlen(line)) + { + (void)alarm(0); + (void)close(fd); + sendto_one(who, wrerr, who->name); + return; + } + (void)alarm(0); + (void)strcpy(line,"ircd: Respond with irc\n\r"); + (void)alarm(5); + if (write(fd, line, strlen(line)) != strlen(line)) + { + (void)alarm(0); + (void)close(fd); + sendto_one(who, wrerr, who->name); + return; + } + (void)close(fd); + (void)alarm(0); + sendto_one(who, rpl_str(RPL_SUMMONING, who->name), namebuf); + return; +} +# endif +#endif /* ENABLE_SUMMON */ + +/* +** find the real hostname for the host running the server (or one which +** matches the server's name) and its primary IP#. Hostname is stored +** in the client structure passed as a pointer. +*/ +void get_my_name(cptr, name, len) +aClient *cptr; +char *name; +int len; +{ + static char tmp[HOSTLEN+1]; + struct hostent *hp; + char *cname = cptr->name; + aConfItem *aconf; + + /* + ** Setup local socket structure to use for binding to. + */ + bzero((char *)&mysk, sizeof(mysk)); + mysk.SIN_FAMILY = AFINET; + + if ((aconf = find_me())->passwd && isdigit(*aconf->passwd)) +#ifdef INET6 + if(!inet_pton(AF_INET6, aconf->passwd, mysk.sin6_addr.s6_addr)) + bcopy(minus_one, mysk.sin6_addr.s6_addr, IN6ADDRSZ); +#else + mysk.sin_addr.s_addr = inetaddr(aconf->passwd); +#endif + + if (gethostname(name, len) == -1) + return; + name[len] = '\0'; + + /* assume that a name containing '.' is a FQDN */ + if (!index(name,'.')) + add_local_domain(name, len - strlen(name)); + + /* + ** If hostname gives another name than cname, then check if there is + ** a CNAME record for cname pointing to hostname. If so accept + ** cname as our name. meLazy + */ + if (BadPtr(cname)) + return; + if ((hp = gethostbyname(cname)) || (hp = gethostbyname(name))) + { + char *hname; + int i = 0; + + for (hname = hp->h_name; hname; hname = hp->h_aliases[i++]) + { + strncpyzt(tmp, hname, sizeof(tmp)); + add_local_domain(tmp, sizeof(tmp) - strlen(tmp)); + + /* + ** Copy the matching name over and store the + ** 'primary' IP# as 'myip' which is used + ** later for making the right one is used + ** for connecting to other hosts. + */ + if (!mycmp(ME, tmp)) + break; + } + if (mycmp(ME, tmp)) + strncpyzt(name, hp->h_name, len); + else + strncpyzt(name, tmp, len); + if (!aconf->passwd) + bcopy(hp->h_addr, (char *)&mysk.SIN_ADDR, + sizeof(struct IN_ADDR)); + Debug((DEBUG_DEBUG,"local name is %s", + get_client_name(&me,TRUE))); + } + return; +} + +/* +** setup a UDP socket and listen for incoming packets +*/ +int setup_ping(aconf) +aConfItem *aconf; +{ + struct SOCKADDR_IN from; + int on = 1; + + if (udpfd != -1) + return udpfd; + bzero((char *)&from, sizeof(from)); + if (aconf->passwd && isdigit(*aconf->passwd)) +#ifdef INET6 + if(!inet_pton(AF_INET6, aconf->passwd,from.sin6_addr.s6_addr)) + bcopy(minus_one, from.sin6_addr.s6_addr, IN6ADDRSZ); +#else + from.sin_addr.s_addr = inetaddr(aconf->passwd); +#endif + else +#ifdef INET6 + from.SIN_ADDR = in6addr_any; +#else + from.sin_addr.s_addr = htonl(INADDR_ANY); /* hmmpf */ +#endif + from.SIN_PORT = htons((u_short) aconf->port); + from.SIN_FAMILY = AFINET; + + if ((udpfd = socket(AFINET, SOCK_DGRAM, 0)) == -1) + { + Debug((DEBUG_ERROR, "socket udp : %s", strerror(errno))); + return -1; + } + if (SETSOCKOPT(udpfd, SOL_SOCKET, SO_REUSEADDR, &on, on) == -1) + { +#ifdef USE_SYSLOG + syslog(LOG_ERR, "setsockopt udp fd %d : %m", udpfd); +#endif + Debug((DEBUG_ERROR, "setsockopt so_reuseaddr : %s", + strerror(errno))); + (void)close(udpfd); + return udpfd = -1; + } + on = 0; + (void) SETSOCKOPT(udpfd, SOL_SOCKET, SO_BROADCAST, &on, on); + if (bind(udpfd, (SAP)&from, sizeof(from))==-1) + { +#ifdef USE_SYSLOG + syslog(LOG_ERR, "bind udp.%d fd %d : %m", + ntohs(from.SIN_PORT), udpfd); +#endif + Debug((DEBUG_ERROR, "bind : %s", strerror(errno))); + (void)close(udpfd); + return udpfd = -1; + } + if (fcntl(udpfd, F_SETFL, FNDELAY)==-1) + { + Debug((DEBUG_ERROR, "fcntl fndelay : %s", strerror(errno))); + (void)close(udpfd); + return udpfd = -1; + } + Debug((DEBUG_INFO, "udpfd = %d, port %d", udpfd,ntohs(from.SIN_PORT))); + return udpfd; +} + + +void send_ping(aconf) +aConfItem *aconf; +{ + Ping pi; + struct SOCKADDR_IN sin; + aCPing *cp = aconf->ping; + +#ifdef INET6 + if (!aconf->ipnum.s6_addr || AND16(aconf->ipnum.s6_addr) == 255 || !cp->port) +#else + if (!aconf->ipnum.s_addr || aconf->ipnum.s_addr == -1 || !cp->port) +#endif + return; + if (aconf->class->conFreq == 0) /* avoid flooding */ + return; + pi.pi_cp = aconf; + pi.pi_id = htonl(PING_CPING); + pi.pi_seq = cp->lseq++; + cp->seq++; + /* + * Only recognise stats from the last 20 minutes as significant... + * Try and fake sliding along a "window" here. + */ + if (cp->seq > 1 && cp->seq * aconf->class->conFreq > 1200) + { + if (cp->recvd) + { + cp->ping -= (cp->ping / cp->recvd); + if (cp->recvd == cp->seq) + cp->recvd--; + } + else + cp->ping = 0; + cp->seq--; + } + + bzero((char *)&sin, sizeof(sin)); +#ifdef INET6 + bcopy(aconf->ipnum.s6_addr, sin.sin6_addr.s6_addr, IN6ADDRSZ); +#else + sin.sin_addr.s_addr = aconf->ipnum.s_addr; +#endif + sin.SIN_PORT = htons(cp->port); + sin.SIN_FAMILY = AFINET; + (void)gettimeofday(&pi.pi_tv, NULL); +#ifdef INET6 + Debug((DEBUG_SEND,"Send ping to %s,%d fd %d, %d bytes", + inet_ntop(AF_INET6, (char *)&aconf->ipnum,mydummy,MYDUMMY_SIZE), + cp->port, udpfd, sizeof(pi))); +#else + Debug((DEBUG_SEND,"Send ping to %s,%d fd %d, %d bytes", + inetntoa((char *)&aconf->ipnum), + cp->port, udpfd, sizeof(pi))); +#endif + (void)sendto(udpfd, (char *)&pi, sizeof(pi), 0,(SAP)&sin,sizeof(sin)); +} + +static int check_ping(buf, len) +char *buf; +int len; +{ + Ping pi; + aConfItem *aconf; + struct timeval tv; + double d; + aCPing *cp = NULL; + u_long rtt; + + (void)gettimeofday(&tv, NULL); + + if (len < sizeof(pi) + 8) + return -1; + + bcopy(buf, (char *)&pi, sizeof(pi)); /* ensure nice byte align. */ + + for (aconf = conf; aconf; aconf = aconf->next) + if (pi.pi_cp == aconf && (cp = aconf->ping)) + break; + if (!aconf || match(aconf->name, buf + sizeof(pi))) + return -1; + + cp->recvd++; + cp->lrecvd++; + rtt = ((tv.tv_sec - pi.pi_tv.tv_sec) * 1000 + + (tv.tv_usec - pi.pi_tv.tv_usec) / 1000); + cp->ping += rtt; + cp->rtt += rtt; + if (cp->rtt > 1000000) + { + cp->ping = (cp->rtt /= cp->lrecvd); + cp->recvd = cp->lrecvd = 1; + cp->seq = cp->lseq = 1; + } + d = (double)cp->recvd / (double)cp->seq; + d = pow(d, (double)20.0); + d = (double)cp->ping / (double)cp->recvd / d; + if (d > 10000.0) + d = 10000.0; + aconf->pref = (int) (d * 100.0); + + return 0; +} + +/* + * max # of pings set to 15/sec. + */ +static void polludp() +{ + static time_t last = 0; + static int cnt = 0, mlen = 0, lasterr = 0; + Reg char *s; + struct SOCKADDR_IN from; + Ping pi; + int n; + SOCK_LEN_TYPE fromlen = sizeof(from); + + /* + * find max length of data area of packet. + */ + if (!mlen) + { + mlen = sizeof(readbuf) - strlen(ME) - strlen(version); + mlen -= 6; + if (mlen < 0) + mlen = 0; + } + Debug((DEBUG_DEBUG,"udp poll")); + + n = recvfrom(udpfd, readbuf, mlen, 0, (SAP)&from, &fromlen); + if (n == -1) + { + ircstp->is_udperr++; + if ((errno == EWOULDBLOCK) || (errno == EAGAIN)) + return; + else + { + report_error("udp port recvfrom (%s): %s", &me); + return; + } + } + + if (timeofday == last) + { + if (++cnt > 14) + { + if (timeofday > lasterr + 30) + { + sendto_flag(SCH_NOTICE, + "udp packet dropped: %d bytes from %s.%d", +#ifdef INET6 + n, inetntop(AF_INET6, + (char *)&from.sin6_addr, mydummy, + MYDUMMY_SIZE), +#else + n,inetntoa((char *)&from.sin_addr), +#endif + ntohs(from.SIN_PORT)); + lasterr = timeofday; + } + ircstp->is_udpdrop++; + return; + } + } + else + cnt = 0, last = timeofday; + +#ifdef INET6 + Debug((DEBUG_NOTICE, "udp (%d) %d bytes from %s,%d", cnt, n, + inet_ntop(AF_INET6, (char *)&from.sin6_addr, mydummy, + MYDUMMY_SIZE), + ntohs(from.SIN_PORT))); +#else + Debug((DEBUG_NOTICE, "udp (%d) %d bytes from %s,%d", cnt, n, + inetntoa((char *)&from.sin_addr), + ntohs(from.SIN_PORT))); +#endif + + readbuf[n] = '\0'; + ircstp->is_udpok++; + if (n < 8) + return; + + bcopy(s = readbuf, (char *)&pi, MIN(n, sizeof(pi))); + pi.pi_id = ntohl(pi.pi_id); + Debug((DEBUG_INFO, "\tpi_id %#x pi_seq %d pi_cp %#x", + pi.pi_id, pi.pi_seq, pi.pi_cp)); + + if ((pi.pi_id == (PING_CPING|PING_REPLY) || + pi.pi_id == (PING_CPING|(PING_REPLY << 24))) && n >= sizeof(pi)) + { + check_ping(s, n); + return; + } + else if (pi.pi_id & PING_REPLY) + return; + /* + * attach my name and version for the reply + */ + pi.pi_id |= PING_REPLY; + pi.pi_id = htonl(pi.pi_id); + bcopy((char *)&pi, s, MIN(n, sizeof(pi))); + s += n; + (void)strcpy(s, ME); + s += strlen(s)+1; + (void)strcpy(s, version); + s += strlen(s); + (void)sendto(udpfd, readbuf, s-readbuf, 0, (SAP)&from ,sizeof(from)); + return; +} + +/* + * do_dns_async + * + * Called when the fd returned from init_resolver() has been selected for + * reading. + */ +static void do_dns_async() +{ + static Link ln; + aClient *cptr; + aConfItem *aconf; + struct hostent *hp; + int bytes, pkts; + + pkts = 0; + + do { + ln.flags = -1; + hp = get_res((char *)&ln); + + Debug((DEBUG_DNS,"%#x = get_res(%d,%#x)", hp, ln.flags, + ln.value.cptr)); + + switch (ln.flags) + { + case ASYNC_NONE : + /* + * no reply was processed that was outstanding or + * had a client still waiting. + */ + break; + case ASYNC_CLIENT : + if ((cptr = ln.value.cptr)) + { + del_queries((char *)cptr); + ClearDNS(cptr); + cptr->hostp = hp; +#if defined(USE_IAUTH) + if (hp) + { + int i = 0; + + while (hp->h_aliases[i]) + sendto_iauth("%d A %s", + cptr->fd, + hp->h_aliases[i++]); + if (hp->h_name) + sendto_iauth("%d N %s", + cptr->fd, hp->h_name); + else if (hp->h_aliases[0]) + sendto_iauth("%d n", cptr->fd); + } + else + sendto_iauth("%d d", cptr->fd); + if (iauth_options & XOPT_EXTWAIT) + cptr->lasttime = timeofday; +#endif + } + break; + case ASYNC_CONNECT : + aconf = ln.value.aconf; + if (hp && aconf) + { + bcopy(hp->h_addr, (char *)&aconf->ipnum, + sizeof(struct IN_ADDR)); + (void)connect_server(aconf, NULL, hp); + } + else + sendto_flag(SCH_ERROR, + "Connect to %s failed: host lookup", + (aconf) ? aconf->host : "unknown"); + break; + case ASYNC_CONF : + aconf = ln.value.aconf; + if (hp && aconf) + bcopy(hp->h_addr, (char *)&aconf->ipnum, + sizeof(struct IN_ADDR)); + break; + default : + break; + } + pkts++; + if (ioctl(resfd, FIONREAD, &bytes) == -1) + bytes = 0; + } while ((bytes > 0) && (pkts < 10)); +} diff --git a/ircd/s_bsd_ext.h b/ircd/s_bsd_ext.h new file mode 100644 index 0000000..6209e8e --- /dev/null +++ b/ircd/s_bsd_ext.h @@ -0,0 +1,77 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_bsd_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_bsd.c. + */ + +/* External definitions for global variables. + */ +#ifndef S_BSD_C +extern aClient *local[]; +extern FdAry fdas, fdaa, fdall; +extern int highest_fd, readcalls, udpfd, resfd, adfd; +extern time_t timeofday; +#endif /* S_BSD_C */ + +/* External definitions for global functions. + */ +#ifndef S_BSD_C +#define EXTERN extern +#else /* S_BSD_C */ +#define EXTERN +#endif /* S_BSD_C */ +EXTERN void add_local_domain __P((char *hname, int size)); +EXTERN void report_error __P((char *text, aClient *cptr)); +EXTERN int inetport __P((aClient *cptr, char *ip, char *ipmask, int port)); +EXTERN int add_listener __P((aConfItem *aconf)); +EXTERN void close_listeners(); +EXTERN void start_iauth __P((int)); +EXTERN void init_sys(); +EXTERN void write_pidfile(); +EXTERN int check_client __P((Reg aClient *cptr)); +EXTERN int check_server_init __P((aClient *cptr)); +EXTERN int check_server __P((aClient *cptr, Reg struct hostent *hp, + Reg aConfItem *c_conf, Reg aConfItem *n_conf, + int estab)); +EXTERN int hold_server __P((aClient *cptr)); +EXTERN void close_connection __P((aClient *cptr)); +EXTERN int get_sockerr __P((aClient *cptr)); +EXTERN void set_non_blocking __P((int fd, aClient *cptr)); +EXTERN aClient *add_connection __P((aClient *cptr, int fd)); +EXTERN int read_message __P((time_t delay, FdAry *fdp, int ro)); +EXTERN int connect_server __P((aConfItem *aconf, aClient *by, + struct hostent *hp)); +EXTERN void get_my_name __P((aClient *cptr, char *name, int len)); +EXTERN int setup_ping __P((aConfItem *aconf)); +EXTERN void send_ping __P((aConfItem *aconf)); +#if defined(ENABLE_SUMMON) || defined(ENABLE_USERS) +EXTERN int utmp_open(); +EXTERN int utmp_read __P((int fd, char *name, char *line, char *host, + int hlen)); +EXTERN int utmp_close(int fd); +#ifdef ENABLE_SUMMON +EXTERN void summon __P((aClient *who, char *namebuf, char *linebuf, + char *chname)); +#endif /* ENABLE_SUMMON */ +#endif /* ENABLE_SUMMON || ENABLE_USERS */ +#ifdef UNIXPORT +EXTERN int unixport __P((aClient *cptr, char *path, int port)); +#endif +#undef EXTERN diff --git a/ircd/s_conf.c b/ircd/s_conf.c new file mode 100644 index 0000000..2abbbd3 --- /dev/null +++ b/ircd/s_conf.c @@ -0,0 +1,1684 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_conf.c + * Copyright (C) 1990 Jarkko Oikarinen and + * University of Oulu, Computing Center + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* -- avalon -- 20 Feb 1992 + * Reversed the order of the params for attach_conf(). + * detach_conf() and attach_conf() are now the same: + * function_conf(aClient *, aConfItem *) + */ + +/* -- Jto -- 20 Jun 1990 + * Added gruner's overnight fix.. + */ + +/* -- Jto -- 16 Jun 1990 + * Moved matches to ../common/match.c + */ + +/* -- Jto -- 03 Jun 1990 + * Added Kill fixes from gruner@lan.informatik.tu-muenchen.de + * Added jarlek's msgbase fix (I still don't understand it... -- Jto) + */ + +/* -- Jto -- 13 May 1990 + * Added fixes from msa: + * Comments and return value to init_conf() + */ + +/* + * -- Jto -- 12 May 1990 + * Added close() into configuration file (was forgotten...) + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: s_conf.c,v 1.42 1999/05/01 21:29:13 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_CONF_C +#include "s_externs.h" +#undef S_CONF_C + +static int check_time_interval __P((char *, char *)); +static int lookup_confhost __P((aConfItem *)); + +aConfItem *conf = NULL; +aConfItem *kconf = NULL; + +/* + * remove all conf entries from the client except those which match + * the status field mask. + */ +void det_confs_butmask(cptr, mask) +aClient *cptr; +int mask; +{ + Reg Link *tmp, *tmp2; + + for (tmp = cptr->confs; tmp; tmp = tmp2) + { + tmp2 = tmp->next; + if ((tmp->value.aconf->status & mask) == 0) + (void)detach_conf(cptr, tmp->value.aconf); + } +} + +/* + * Match address by #IP bitmask (10.11.12.128/27) + */ +int match_ipmask(mask, cptr) +char *mask; +aClient *cptr; +{ + int i1, i2, i3, i4, m; + u_long lmask, baseip; + char *at; + + if (at = index(mask, '@')) + mask = at + 1; + if (sscanf(mask, "%d.%d.%d.%d/%d", &i1, &i2, &i3, &i4, &m) != 5 || + m < 1 || m > 31) { + sendto_flag(SCH_LOCAL, "Ignoring bad mask: %s", mask); + return -1; + } + lmask = htonl((u_long)0xffffffffL << (32 - m)); /* /24->0xffffff00ul */ + baseip = htonl(i1 * 0x1000000 + i2 * 0x10000 + i3 * 0x100 + i4); +#ifdef INET6 + return 1; +/* return ((cptr->ip.s6_addr & lmask) == baseip) ? 0 : 1;*/ +#else + return ((cptr->ip.s_addr & lmask) == baseip) ? 0 : 1; +#endif +} + +/* + * find the first (best) I line to attach. + */ +int attach_Iline(cptr, hp, sockhost) +aClient *cptr; +Reg struct hostent *hp; +char *sockhost; +{ + Reg aConfItem *aconf; + Reg char *hname; + Reg int i; + static char uhost[HOSTLEN+USERLEN+3]; + static char fullname[HOSTLEN+1]; + + for (aconf = conf; aconf; aconf = aconf->next) + { + if ((aconf->status != CONF_CLIENT) && + (aconf->status != CONF_RCLIENT)) + continue; + if (aconf->port && aconf->port != cptr->acpt->port) + continue; + if (!aconf->host || !aconf->name) + goto attach_iline; + if (hp) + for (i = 0, hname = hp->h_name; hname; + hname = hp->h_aliases[i++]) + { + strncpyzt(fullname, hname, + sizeof(fullname)); + add_local_domain(fullname, + HOSTLEN - strlen(fullname)); + Debug((DEBUG_DNS, "a_il: %s->%s", + sockhost, fullname)); + if (index(aconf->name, '@')) + { + (void)strcpy(uhost, cptr->username); + (void)strcat(uhost, "@"); + } + else + *uhost = '\0'; + (void)strncat(uhost, fullname, + sizeof(uhost) - strlen(uhost)); + if (!match(aconf->name, uhost)) + goto attach_iline; + } + + if (index(aconf->host, '@')) + { + strncpyzt(uhost, cptr->username, sizeof(uhost)); + (void)strcat(uhost, "@"); + } + else + *uhost = '\0'; + (void)strncat(uhost, sockhost, sizeof(uhost) - strlen(uhost)); + if (strchr(aconf->host, '/')) /* 1.2.3.0/24 */ + { + if (match_ipmask(aconf->host, cptr)) + continue; + } else if (match(aconf->host, uhost)) /* 1.2.3.* */ + continue; + if (*aconf->name == '\0' && hp) + { + strncpyzt(uhost, hp->h_name, sizeof(uhost)); + add_local_domain(uhost, sizeof(uhost) - strlen(uhost)); + } +attach_iline: + if (aconf->status & CONF_RCLIENT) + SetRestricted(cptr); + get_sockhost(cptr, uhost); + if ((i = attach_conf(cptr, aconf)) < -1) + find_bounce(cptr, ConfClass(aconf), -1); + return i; + } + find_bounce(cptr, 0, -2); + return -2; /* used in register_user() */ +} + +/* + * Find the single N line and return pointer to it (from list). + * If more than one then return NULL pointer. + */ +aConfItem *count_cnlines(lp) +Reg Link *lp; +{ + Reg aConfItem *aconf, *cline = NULL, *nline = NULL; + + for (; lp; lp = lp->next) + { + aconf = lp->value.aconf; + if (!(aconf->status & CONF_SERVER_MASK)) + continue; + if ((aconf->status == CONF_CONNECT_SERVER || + aconf->status == CONF_ZCONNECT_SERVER) && !cline) + cline = aconf; + else if (aconf->status == CONF_NOCONNECT_SERVER && !nline) + nline = aconf; + } + return nline; +} + +/* +** detach_conf +** Disassociate configuration from the client. +** Also removes a class from the list if marked for deleting. +*/ +int detach_conf(cptr, aconf) +aClient *cptr; +aConfItem *aconf; +{ + Reg Link **lp, *tmp; + + lp = &(cptr->confs); + + while (*lp) + { + if ((*lp)->value.aconf == aconf) + { + if ((aconf) && (Class(aconf))) + { + if (aconf->status & CONF_CLIENT_MASK) + if (ConfLinks(aconf) > 0) + --ConfLinks(aconf); + if (ConfMaxLinks(aconf) == -1 && + ConfLinks(aconf) == 0) + { + free_class(Class(aconf)); + Class(aconf) = NULL; + } + } + if (aconf && !--aconf->clients && IsIllegal(aconf)) + free_conf(aconf); + tmp = *lp; + *lp = tmp->next; + free_link(tmp); + istat.is_conflink--; + return 0; + } + else + lp = &((*lp)->next); + } + return -1; +} + +static int is_attached(aconf, cptr) +aConfItem *aconf; +aClient *cptr; +{ + Reg Link *lp; + + for (lp = cptr->confs; lp; lp = lp->next) + if (lp->value.aconf == aconf) + break; + + return (lp) ? 1 : 0; +} + +/* +** attach_conf +** Associate a specific configuration entry to a *local* +** client (this is the one which used in accepting the +** connection). Note, that this automaticly changes the +** attachment if there was an old one... +*/ +int attach_conf(cptr, aconf) +aConfItem *aconf; +aClient *cptr; +{ + Reg Link *lp; + + if (is_attached(aconf, cptr)) + return 1; + if (IsIllegal(aconf)) + return -1; + if ((aconf->status & (CONF_LOCOP | CONF_OPERATOR | CONF_CLIENT | + CONF_RCLIENT))) + { + if (aconf->clients >= ConfMaxLinks(aconf) && + ConfMaxLinks(aconf) > 0) + return -3; /* Use this for printing error message */ + } + if ((aconf->status & (CONF_CLIENT | CONF_RCLIENT))) + { + int hcnt = 0, ucnt = 0; + + /* check on local/global limits per host and per user@host */ + + /* + ** local limits first to save CPU if any is hit. + ** host check is done on the IP address. + ** user check is done on the IDENT reply. + */ + if (ConfMaxHLocal(aconf) > 0 || ConfMaxUHLocal(aconf) > 0) { + Reg aClient *acptr; + Reg int i; + + for (i = highest_fd; i >= 0; i--) + if ((acptr = local[i]) && (cptr != acptr) && + !IsListening(acptr) && + !bcmp((char *)&cptr->ip,(char *)&acptr->ip, + sizeof(cptr->ip))) + { + hcnt++; + if (!strncasecmp(acptr->auth, + cptr->auth, USERLEN)) + ucnt++; + } + if (ConfMaxHLocal(aconf) > 0 && + hcnt >= ConfMaxHLocal(aconf)) + return -4; /* for error message */ + if (ConfMaxUHLocal(aconf) > 0 && + ucnt >= ConfMaxUHLocal(aconf)) + return -5; /* for error message */ + } + /* + ** Global limits + ** host check is done on the hostname (IP if unresolved) + ** user check is done on username + */ + if (ConfMaxHGlobal(aconf) > 0 || ConfMaxUHGlobal(aconf) > 0) + { + Reg aClient *acptr; + Reg int ghcnt = hcnt, gucnt = ucnt; + + for (acptr = client; acptr; acptr = acptr->next) + { + if (!IsPerson(acptr)) + continue; + if (MyConnect(acptr) && + (ConfMaxHLocal(aconf) > 0 || + ConfMaxUHLocal(aconf) > 0)) + continue; + if (!strcmp(cptr->sockhost, acptr->user->host)) + { + if (ConfMaxHGlobal(aconf) > 0 && + ++ghcnt >= ConfMaxHGlobal(aconf)) + return -6; + if (ConfMaxUHGlobal(aconf) > 0 && + !strcmp(cptr->user->username, + acptr->user->username) && + (++gucnt >=ConfMaxUHGlobal(aconf))) + return -7; + } + } + } + } + + lp = make_link(); + istat.is_conflink++; + lp->next = cptr->confs; + lp->value.aconf = aconf; + cptr->confs = lp; + aconf->clients++; + if (aconf->status & CONF_CLIENT_MASK) + ConfLinks(aconf)++; + return 0; +} + + +aConfItem *find_admin() + { + Reg aConfItem *aconf; + + for (aconf = conf; aconf; aconf = aconf->next) + if (aconf->status & CONF_ADMIN) + break; + + return (aconf); + } + +aConfItem *find_me() + { + Reg aConfItem *aconf; + for (aconf = conf; aconf; aconf = aconf->next) + if (aconf->status & CONF_ME) + break; + + return (aconf); + } + +/* + * attach_confs + * Attach a CONF line to a client if the name passed matches that for + * the conf file (for non-C/N lines) or is an exact match (C/N lines + * only). The difference in behaviour is to stop C:*::* and N:*::*. + */ +aConfItem *attach_confs(cptr, name, statmask) +aClient *cptr; +char *name; +int statmask; +{ + Reg aConfItem *tmp; + aConfItem *first = NULL; + int len = strlen(name); + + if (!name || len > HOSTLEN) + return NULL; + for (tmp = conf; tmp; tmp = tmp->next) + { + if ((tmp->status & statmask) && !IsIllegal(tmp) && + ((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0) && + tmp->name && !match(tmp->name, name)) + { + if (!attach_conf(cptr, tmp) && !first) + first = tmp; + } + else if ((tmp->status & statmask) && !IsIllegal(tmp) && + (tmp->status & (CONF_SERVER_MASK|CONF_HUB)) && + tmp->name && !mycmp(tmp->name, name)) + { + if (!attach_conf(cptr, tmp) && !first) + first = tmp; + } + } + return (first); +} + +/* + * Added for new access check meLazy + */ +aConfItem *attach_confs_host(cptr, host, statmask) +aClient *cptr; +char *host; +int statmask; +{ + Reg aConfItem *tmp; + aConfItem *first = NULL; + int len = strlen(host); + + if (!host || len > HOSTLEN) + return NULL; + + for (tmp = conf; tmp; tmp = tmp->next) + { + if ((tmp->status & statmask) && !IsIllegal(tmp) && + (tmp->status & CONF_SERVER_MASK) == 0 && + (!tmp->host || match(tmp->host, host) == 0)) + { + if (!attach_conf(cptr, tmp) && !first) + first = tmp; + } + else if ((tmp->status & statmask) && !IsIllegal(tmp) && + (tmp->status & CONF_SERVER_MASK) && + (tmp->host && mycmp(tmp->host, host) == 0)) + { + if (!attach_conf(cptr, tmp) && !first) + first = tmp; + } + } + return (first); +} + +/* + * find a conf entry which matches the hostname and has the same name. + */ +aConfItem *find_conf_exact(name, user, host, statmask) +char *name, *host, *user; +int statmask; +{ + Reg aConfItem *tmp; + char userhost[USERLEN+HOSTLEN+3]; + + SPRINTF(userhost, "%s@%s", user, host); + + for (tmp = conf; tmp; tmp = tmp->next) + { + if (!(tmp->status & statmask) || !tmp->name || !tmp->host || + mycmp(tmp->name, name)) + continue; + /* + ** Accept if the *real* hostname (usually sockecthost) + ** socket host) matches *either* host or name field + ** of the configuration. + */ + if (match(tmp->host, userhost)) + continue; + if (tmp->status & (CONF_OPERATOR|CONF_LOCOP)) + { + if (tmp->clients < MaxLinks(Class(tmp))) + return tmp; + else + continue; + } + else + return tmp; + } + return NULL; +} + +aConfItem *find_conf_name(name, statmask) +char *name; +int statmask; +{ + Reg aConfItem *tmp; + + for (tmp = conf; tmp; tmp = tmp->next) + { + /* + ** Accept if the *real* hostname (usually sockecthost) + ** matches *either* host or name field of the configuration. + */ + if ((tmp->status & statmask) && + (!tmp->name || match(tmp->name, name) == 0)) + return tmp; + } + return NULL; +} + +aConfItem *find_conf(lp, name, statmask) +char *name; +Link *lp; +int statmask; +{ + Reg aConfItem *tmp; + int namelen = name ? strlen(name) : 0; + + if (namelen > HOSTLEN) + return (aConfItem *) 0; + + for (; lp; lp = lp->next) + { + tmp = lp->value.aconf; + if ((tmp->status & statmask) && + (((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) && + tmp->name && !mycmp(tmp->name, name)) || + ((tmp->status & (CONF_SERVER_MASK|CONF_HUB)) == 0 && + tmp->name && !match(tmp->name, name)))) + return tmp; + } + return NULL; +} + +/* + * Added for new access check meLazy + */ +aConfItem *find_conf_host(lp, host, statmask) +Reg Link *lp; +char *host; +Reg int statmask; +{ + Reg aConfItem *tmp; + int hostlen = host ? strlen(host) : 0; + + if (hostlen > HOSTLEN || BadPtr(host)) + return (aConfItem *)NULL; + for (; lp; lp = lp->next) + { + tmp = lp->value.aconf; + if (tmp->status & statmask && + (!(tmp->status & CONF_SERVER_MASK || tmp->host) || + (tmp->host && !match(tmp->host, host)))) + return tmp; + } + return NULL; +} + +/* + * find_conf_ip + * + * Find a conf line using the IP# stored in it to search upon. + * Added 1/8/92 by Avalon. + */ +aConfItem *find_conf_ip(lp, ip, user, statmask) +char *ip, *user; +Link *lp; +int statmask; +{ + Reg aConfItem *tmp; + Reg char *s; + + for (; lp; lp = lp->next) + { + tmp = lp->value.aconf; + if (!(tmp->status & statmask)) + continue; + s = index(tmp->host, '@'); + *s = '\0'; + if (match(tmp->host, user)) + { + *s = '@'; + continue; + } + *s = '@'; + if (!bcmp((char *)&tmp->ipnum, ip, sizeof(struct IN_ADDR))) + return tmp; + } + return NULL; +} + +/* + * find_conf_entry + * + * - looks for a match on all given fields. + */ +aConfItem *find_conf_entry(aconf, mask) +aConfItem *aconf; +u_int mask; +{ + Reg aConfItem *bconf; + + for (bconf = conf, mask &= ~CONF_ILLEGAL; bconf; bconf = bconf->next) + { + if (!(bconf->status & mask) || (bconf->port != aconf->port)) + continue; + + if ((BadPtr(bconf->host) && !BadPtr(aconf->host)) || + (BadPtr(aconf->host) && !BadPtr(bconf->host))) + continue; + if (!BadPtr(bconf->host) && mycmp(bconf->host, aconf->host)) + continue; + + if ((BadPtr(bconf->passwd) && !BadPtr(aconf->passwd)) || + (BadPtr(aconf->passwd) && !BadPtr(bconf->passwd))) + continue; + if (!BadPtr(bconf->passwd) && + mycmp(bconf->passwd, aconf->passwd)) + continue; + + if ((BadPtr(bconf->name) && !BadPtr(aconf->name)) || + (BadPtr(aconf->name) && !BadPtr(bconf->name))) + continue; + if (!BadPtr(bconf->name) && mycmp(bconf->name, aconf->name)) + continue; + break; + } + return bconf; +} + +/* + * rehash + * + * Actual REHASH service routine. Called with sig == 0 if it has been called + * as a result of an operator issuing this command, else assume it has been + * called as a result of the server receiving a HUP signal. + */ +int rehash(cptr, sptr, sig) +aClient *cptr, *sptr; +int sig; +{ + Reg aConfItem **tmp = &conf, *tmp2 = NULL; + Reg aClass *cltmp; + Reg aClient *acptr; + Reg int i; + int ret = 0; + + if (sig == 1) + { + sendto_flag(SCH_NOTICE, + "Got signal SIGHUP, reloading ircd.conf file"); +#ifdef ULTRIX + if (fork() > 0) + exit(0); + write_pidfile(); +#endif + } + + for (i = 0; i <= highest_fd; i++) + if ((acptr = local[i]) && !IsMe(acptr)) + { + /* + * Nullify any references from client structures to + * this host structure which is about to be freed. + * Could always keep reference counts instead of + * this....-avalon + */ + acptr->hostp = NULL; +#if defined(R_LINES_REHASH) && !defined(R_LINES_OFTEN) + if (find_restrict(acptr)) + { + sendto_flag(SCH_NOTICE, + "Restricting %s, closing lp", + get_client_name(acptr,FALSE)); + acptr->exitc = EXITC_RLINE; + if (exit_client(cptr,acptr,&me,"R-lined") == + FLUSH_BUFFER) + ret = FLUSH_BUFFER; + } +#endif + } + + while ((tmp2 = *tmp)) + if (tmp2->clients || tmp2->status & CONF_LISTEN_PORT) + { + /* + ** Configuration entry is still in use by some + ** local clients, cannot delete it--mark it so + ** that it will be deleted when the last client + ** exits... + */ + if (!(tmp2->status & (CONF_LISTEN_PORT|CONF_CLIENT))) + { + *tmp = tmp2->next; + tmp2->next = NULL; + } + else + tmp = &tmp2->next; + tmp2->status |= CONF_ILLEGAL; + } + else + { + *tmp = tmp2->next; + free_conf(tmp2); + } + + tmp = &kconf; + while ((tmp2 = *tmp)) + { + *tmp = tmp2->next; + free_conf(tmp2); + } + + /* + * We don't delete the class table, rather mark all entries + * for deletion. The table is cleaned up by check_class. - avalon + */ + for (cltmp = NextClass(FirstClass()); cltmp; cltmp = NextClass(cltmp)) + MaxLinks(cltmp) = -1; + + if (sig != 2) + flush_cache(); + (void) initconf(0); + close_listeners(); + + /* + * flush out deleted I and P lines although still in use. + */ + for (tmp = &conf; (tmp2 = *tmp); ) + if (!(tmp2->status & CONF_ILLEGAL)) + tmp = &tmp2->next; + else + { + *tmp = tmp2->next; + tmp2->next = NULL; + if (!tmp2->clients) + free_conf(tmp2); + } +#ifdef CACHED_MOTD + read_motd(IRCDMOTD_PATH); +#endif + rehashed = 1; + return ret; +} + +/* + * openconf + * + * returns -1 on any error or else the fd opened from which to read the + * configuration file from. This may either be the file direct or one end + * of a pipe from m4. + */ +int openconf() +{ +#ifdef M4_PREPROC + int pi[2], i; + + if (pipe(pi) == -1) + return -1; + switch(vfork()) + { + case -1 : + return -1; + case 0 : + (void)close(pi[0]); + if (pi[1] != 1) + { + (void)dup2(pi[1], 1); + (void)close(pi[1]); + } + (void)dup2(1,2); + for (i = 3; i < MAXCONNECTIONS; i++) + if (local[i]) + (void) close(i); + /* + * m4 maybe anywhere, use execvp to find it. Any error + * goes out with report_error. Could be dangerous, + * two servers running with the same fd's >:-) -avalon + */ + (void)execlp("m4", "m4", IRCDM4_PATH, configfile, 0); + report_error("Error executing m4 %s:%s", &me); + _exit(-1); + default : + (void)close(pi[1]); + return pi[0]; + } +#else + return open(configfile, O_RDONLY); +#endif +} + +/* +** initconf() +** Read configuration file. +** +** returns -1, if file cannot be opened +** 0, if file opened +*/ + +#define MAXCONFLINKS 150 + +int initconf(opt) +int opt; +{ + static char quotes[9][2] = {{'b', '\b'}, {'f', '\f'}, {'n', '\n'}, + {'r', '\r'}, {'t', '\t'}, {'v', '\v'}, + {'\\', '\\'}, { 0, 0}}; + Reg char *tmp, *s; + int fd, i; + char line[512], c[80], *tmp2 = NULL, *tmp3 = NULL, *tmp4 = NULL; + int ccount = 0, ncount = 0; + aConfItem *aconf = NULL; + + Debug((DEBUG_DEBUG, "initconf(): ircd.conf = %s", configfile)); + if ((fd = openconf()) == -1) + { +#if defined(M4_PREPROC) && !defined(USE_IAUTH) + (void)wait(0); +#endif + return -1; + } + (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ + while ((i = dgets(fd, line, sizeof(line) - 1)) > 0) + { + line[i] = '\0'; + if ((tmp = (char *)index(line, '\n'))) + *tmp = 0; + else while(dgets(fd, c, sizeof(c) - 1) > 0) + if ((tmp = (char *)index(c, '\n'))) + { + *tmp = 0; + break; + } + /* + * Do quoting of characters and # detection. + */ + for (tmp = line; *tmp; tmp++) + { + if (*tmp == '\\') + { + for (i = 0; quotes[i][0]; i++) + if (quotes[i][0] == *(tmp+1)) + { + *tmp = quotes[i][1]; + break; + } + if (!quotes[i][0]) + *tmp = *(tmp+1); + if (!*(tmp+1)) + break; + else + for (s = tmp; (*s = *(s+1)); s++) + ; + } + else if (*tmp == '#') + { + *tmp = '\0'; + break; /* Ignore the rest of the line */ + } + } + if (!*line || line[0] == '#' || line[0] == '\n' || + line[0] == ' ' || line[0] == '\t') + continue; + /* Could we test if it's conf line at all? -Vesa */ + if (line[1] != IRCDCONF_DELIMITER) + { + Debug((DEBUG_ERROR, "Bad config line: %s", line)); + continue; + } + if (aconf) + free_conf(aconf); + aconf = make_conf(); + + if (tmp2) + MyFree(tmp2); + tmp3 = tmp4 = NULL; + tmp = getfield(line); + if (!tmp) + continue; + switch (*tmp) + { + case 'A': /* Name, e-mail address of administrator */ + case 'a': /* of this server. */ + aconf->status = CONF_ADMIN; + break; + case 'B': /* Name of alternate servers */ + case 'b': + aconf->status = CONF_BOUNCE; + break; + case 'C': /* Server where I should try to connect */ + /* in case of lp failures */ + ccount++; + aconf->status = CONF_CONNECT_SERVER; + break; + case 'c': + ccount++; + aconf->status = CONF_ZCONNECT_SERVER; + break; + case 'D': /* auto connect restrictions */ + case 'd': + aconf->status = CONF_DENY; + break; + case 'H': /* Hub server line */ + case 'h': + aconf->status = CONF_HUB; + break; + case 'I': /* Just plain normal irc client trying */ + /* to connect me */ + aconf->status = CONF_CLIENT; + break; + case 'i' : /* Restricted client */ + aconf->status = CONF_RCLIENT; + break; + case 'K': /* Kill user line on irc.conf */ + aconf->status = CONF_KILL; + break; + case 'k': + aconf->status = CONF_OTHERKILL; + 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; +#if 0 + case 'U': /* Uphost, ie. host where client reading */ + case 'u': /* this should connect. */ + /* This is for client only, I must ignore this */ + /* ...U-line should be removed... --msa */ + break; +#endif + case 'V': /* Server link version requirements */ + aconf->status = CONF_VER; + break; + case 'Y': + case 'y': + aconf->status = CONF_CLASS; + break; + default: + Debug((DEBUG_ERROR, "Error in config file: %s", line)); + break; + } + if (IsIllegal(aconf)) + continue; + + for (;;) /* Fake loop, that I can use break here --msa */ + { + if ((tmp = getfield(NULL)) == NULL) + break; + DupString(aconf->host, tmp); + if ((tmp = getfield(NULL)) == NULL) + break; + DupString(aconf->passwd, tmp); + if ((tmp = getfield(NULL)) == NULL) + break; + DupString(aconf->name, tmp); + if ((tmp = getfield(NULL)) == NULL) + break; + aconf->port = 0; + if (sscanf(tmp, "0x%x", &aconf->port) != 1 || + aconf->port == 0) + aconf->port = atoi(tmp); + if (aconf->status == CONF_CONNECT_SERVER) + DupString(tmp2, tmp); + if (aconf->status == CONF_ZCONNECT_SERVER) + DupString(tmp2, tmp); + if ((tmp = getfield(NULL)) == NULL) + break; + Class(aconf) = find_class(atoi(tmp)); + /* the following are only used for Y: */ + if ((tmp3 = getfield(NULL)) == NULL) + break; + tmp4 = getfield(NULL); + break; + } + istat.is_confmem += aconf->host ? strlen(aconf->host)+1 : 0; + istat.is_confmem += aconf->passwd ? strlen(aconf->passwd)+1 :0; + istat.is_confmem += aconf->name ? strlen(aconf->name)+1 : 0; + + /* + ** Bounce line fields are mandatory + */ + if (aconf->status == CONF_BOUNCE && aconf->port == 0) + continue; + /* + ** 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) + { + if (atoi(aconf->host) >= 0) + add_class(atoi(aconf->host), + atoi(aconf->passwd), + atoi(aconf->name), aconf->port, + tmp ? atoi(tmp) : 0, +/* tmp3 ? atoi(tmp3) : 0, +** tmp3 && index(tmp3, '.') ? +** atoi(index(tmp3, '.') + 1) : 0, +** the next 3 lines should be replaced by the previous sometime in the +** future. It is only kept for "backward" compatibility and not needed, +** but I'm in good mood today -krys +*/ + tmp3 ? atoi(tmp3) : (atoi(aconf->name) > 0) ? atoi(aconf->name) : 0, + tmp3 && index(tmp3, '.') ? + atoi(index(tmp3, '.') + 1) : (atoi(aconf->name) < 0) ? -1 * atoi(aconf->name) : 0, +/* end of backward compatibility insanity */ + tmp4 ? atoi(tmp4) : 0, + tmp4 && index(tmp4, '.') ? + atoi(index(tmp4, '.') + 1) : 0); + continue; + } + /* + ** associate each conf line with a class by using a pointer + ** to the correct class record. -avalon + */ + if (aconf->status & (CONF_CLIENT_MASK|CONF_LISTEN_PORT)) + { + if (Class(aconf) == 0) + Class(aconf) = find_class(0); + if (MaxLinks(Class(aconf)) < 0) + Class(aconf) = find_class(0); + } + if (aconf->status & (CONF_LISTEN_PORT|CONF_CLIENT)) + { + aConfItem *bconf; + + if ((bconf = find_conf_entry(aconf, aconf->status))) + { + delist_conf(bconf); + bconf->status &= ~CONF_ILLEGAL; + if (aconf->status == CONF_CLIENT) + { + bconf->class->links -= bconf->clients; + bconf->class = aconf->class; + bconf->class->links += bconf->clients; + } + free_conf(aconf); + aconf = bconf; + } + else if (aconf->host && + aconf->status == CONF_LISTEN_PORT) + (void)add_listener(aconf); + } + if (aconf->status & CONF_SERVICE) + aconf->port &= SERVICE_MASK_ALL; + if (aconf->status & (CONF_SERVER_MASK|CONF_SERVICE)) + if (ncount > MAXCONFLINKS || ccount > MAXCONFLINKS || + !aconf->host || index(aconf->host, '*') || + index(aconf->host,'?') || !aconf->name) + continue; + + if (aconf->status & + (CONF_SERVER_MASK|CONF_LOCOP|CONF_OPERATOR|CONF_SERVICE)) + if (!index(aconf->host, '@') && *aconf->host != '/') + { + char *newhost; + int len = 3; /* *@\0 = 3 */ + + len += strlen(aconf->host); + newhost = (char *)MyMalloc(len); + SPRINTF(newhost, "*@%s", aconf->host); + MyFree(aconf->host); + aconf->host = newhost; + istat.is_confmem += 2; + } + if (aconf->status & CONF_SERVER_MASK) + { + if (BadPtr(aconf->passwd)) + continue; + else if (!(opt & BOOT_QUICK)) + (void)lookup_confhost(aconf); + } + if (aconf->status & (CONF_CONNECT_SERVER | CONF_ZCONNECT_SERVER)) + { + aconf->ping = (aCPing *)MyMalloc(sizeof(aCPing)); + bzero((char *)aconf->ping, sizeof(*aconf->ping)); + istat.is_confmem += sizeof(*aconf->ping); + if (tmp2 && index(tmp2, '.')) + aconf->ping->port = atoi(index(tmp2, '.') + 1); + else + aconf->ping->port = aconf->port; + if (tmp2) + { + MyFree(tmp2); + tmp2 = NULL; + } + + } + /* + ** Name cannot be changed after the startup. + ** (or could be allowed, but only if all links are closed + ** first). + ** Configuration info does not override the name and port + ** if previously defined. Note, that "info"-field can be + ** changed by "/rehash". + */ + if (aconf->status == CONF_ME) + { + if (me.info != DefInfo) + MyFree(me.info); + me.info = MyMalloc(REALLEN+1); + strncpyzt(me.info, aconf->name, REALLEN+1); + if (ME[0] == '\0' && aconf->host[0]) + strncpyzt(ME, aconf->host, + sizeof(ME)); + if (aconf->port) + setup_ping(aconf); + } + (void)collapse(aconf->host); + (void)collapse(aconf->name); + Debug((DEBUG_NOTICE, + "Read Init: (%d) (%s) (%s) (%s) (%d) (%d)", + aconf->status, aconf->host, aconf->passwd, + aconf->name, aconf->port, + aconf->class ? ConfClass(aconf) : 0)); + + if (aconf->status & (CONF_KILL|CONF_OTHERKILL)) + { + aconf->next = kconf; + kconf = aconf; + } + else + { + aconf->next = conf; + conf = aconf; + } + aconf = NULL; + } + if (aconf) + free_conf(aconf); + (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ + (void)close(fd); +#if defined(M4_PREPROC) && !defined(USE_IAUTH) + (void)wait(0); +#endif + check_class(); + nextping = nextconnect = timeofday; + return 0; +} + +/* + * lookup_confhost + * Do (start) DNS lookups of all hostnames in the conf line and convert + * an IP addresses in a.b.c.d number for to IP#s. + */ +static int lookup_confhost(aconf) +Reg aConfItem *aconf; +{ + Reg char *s; + Reg struct hostent *hp; + Link ln; + + if (BadPtr(aconf->host) || BadPtr(aconf->name)) + goto badlookup; + if ((s = index(aconf->host, '@'))) + s++; + else + s = aconf->host; + /* + ** Do name lookup now on hostnames given and store the + ** ip numbers in conf structure. + */ + if (!isalpha(*s) && !isdigit(*s)) + goto badlookup; + + /* + ** Prepare structure in case we have to wait for a + ** reply which we get later and store away. + */ + ln.value.aconf = aconf; + ln.flags = ASYNC_CONF; + + if (isdigit(*s)) +#ifdef INET6 + if(!inet_pton(AF_INET6, s, aconf->ipnum.s6_addr)) + bcopy(minus_one, aconf->ipnum.s6_addr, IN6ADDRSZ); +#else + aconf->ipnum.s_addr = inetaddr(s); +#endif + else if ((hp = gethost_byname(s, &ln))) + bcopy(hp->h_addr, (char *)&(aconf->ipnum), + sizeof(struct IN_ADDR)); + +#ifdef INET6 + if (AND16(aconf->ipnum.s6_addr) == 255) +#else + if (aconf->ipnum.s_addr == -1) +#endif + goto badlookup; + return 0; +badlookup: +#ifdef INET6 + if (AND16(aconf->ipnum.s6_addr) == 255) +#else + if (aconf->ipnum.s_addr == -1) +#endif + bzero((char *)&aconf->ipnum, sizeof(struct IN_ADDR)); + Debug((DEBUG_ERROR,"Host/server name error: (%s) (%s)", + aconf->host, aconf->name)); + return -1; +} + +int find_kill(cptr, doall, comment) +aClient *cptr; +int doall; +char **comment; +{ + static char reply[256]; + char *host, *ip, *name, *ident, *check; + aConfItem *tmp; + int now; + + if (!cptr->user) + return 0; + + host = cptr->sockhost; +#ifdef INET6 + ip = (char *) inetntop(AF_INET6, (char *)&cptr->ip, mydummy, + MYDUMMY_SIZE); +#else + ip = (char *) inetntoa((char *)&cptr->ip); +#endif + if (!strcmp(host, ip)) + ip = NULL; /* we don't have a name for the ip# */ + name = cptr->user->username; + ident = cptr->auth; + + if (strlen(host) > (size_t) HOSTLEN || + (name ? strlen(name) : 0) > (size_t) HOSTLEN) + return (0); + + *reply = '\0'; + + for (tmp = kconf; tmp; tmp = tmp->next) + { + if (!doall && (BadPtr(tmp->passwd) || !isdigit(*tmp->passwd))) + continue; + if (!(tmp->status & (CONF_KILL | CONF_OTHERKILL))) + continue; /* should never happen with kconf */ + if (!tmp->host || !tmp->name) + continue; + if (tmp->status == CONF_KILL) + check = name; + else + check = ident; + /* host & IP matching.. */ + if (!ip) /* unresolved */ + { + if (strchr(tmp->host, '/')) + { + if (match_ipmask((*tmp->host == '=') ? + tmp->host+1: tmp->host, cptr)) + continue; + } + else + if (match((*tmp->host == '=') ? tmp->host+1 : + tmp->host, host)) + continue; + } + else if (*tmp->host == '=') /* numeric only */ + continue; + else /* resolved */ + if (strchr(tmp->host, '/')) + { + if (match_ipmask(tmp->host, cptr)) + continue; + } + else + if (match(tmp->host, ip) && + match(tmp->host, host)) + continue; + + /* user & port matching */ + if ((!check || match(tmp->name, check) == 0) && + (!tmp->port || (tmp->port == cptr->acpt->port))) + { + now = 0; + if (!BadPtr(tmp->passwd) && isdigit(*tmp->passwd) && + !(now = check_time_interval(tmp->passwd, reply))) + continue; + if (now == ERR_YOUWILLBEBANNED) + tmp = NULL; + break; + } + } + + if (*reply) + sendto_one(cptr, reply, ME, now, cptr->name); + else if (tmp) + sendto_one(cptr, ":%s %d %s :%s%s", ME, + ERR_YOUREBANNEDCREEP, cptr->name, + BadPtr(tmp->passwd) ? + "You are not welcome to this server" : + "You are not welcome to this server: ", + BadPtr(tmp->passwd) ? "" : tmp->passwd); + + if (tmp && !BadPtr(tmp->passwd)) + *comment = tmp->passwd; + else + *comment = NULL; + + return (tmp ? -1 : 0); +} + +/* + * For type stat, check if both name and host masks match. + * Return -1 for match, 0 for no-match. + */ +int find_two_masks(name, host, stat) +char *name, *host; +int stat; +{ + aConfItem *tmp; + + for (tmp = conf; tmp; tmp = tmp->next) + if ((tmp->status == stat) && tmp->host && tmp->name && + (match(tmp->host, host) == 0) && + (match(tmp->name, name) == 0)) + break; + return (tmp ? -1 : 0); +} + +/* + * For type stat, check if name matches and any char from key matches + * to chars in passwd field. + * Return -1 for match, 0 for no-match. + */ +int find_conf_flags(name, key, stat) +char *name, *key; +int stat; +{ + aConfItem *tmp; + int l; + + if (index(key, '/') == NULL) + return 0; + l = ((char *)index(key, '/') - key) + 1; + for (tmp = conf; tmp; tmp = tmp->next) + if ((tmp->status == stat) && tmp->passwd && tmp->name && + (strncasecmp(key, tmp->passwd, l) == 0) && + (match(tmp->name, name) == 0) && + (strpbrk(key + l, tmp->passwd + l))) + break; + return (tmp ? -1 : 0); +} + +#ifdef R_LINES +/* find_restrict works against host/name and calls an outside program + * to determine whether a client is allowed to connect. This allows + * more freedom to determine who is legal and who isn't, for example + * machine load considerations. The outside program is expected to + * return a reply line where the first word is either 'Y' or 'N' meaning + * "Yes Let them in" or "No don't let them in." If the first word + * begins with neither 'Y' or 'N' the default is to let the person on. + * It returns a value of 0 if the user is to be let through -Hoppie + */ +int find_restrict(cptr) +aClient *cptr; +{ + aConfItem *tmp; + char reply[80], temprpl[80]; + char *rplhold = reply, *host, *name, *s; + char rplchar = 'Y'; + int pi[2], rc = 0, n; + + if (!cptr->user) + return 0; + name = cptr->user->username; + host = cptr->sockhost; + Debug((DEBUG_INFO, "R-line check for %s[%s]", name, host)); + + for (tmp = conf; tmp; tmp = tmp->next) + { + if (tmp->status != CONF_RESTRICT || + (tmp->host && host && match(tmp->host, host)) || + (tmp->name && name && match(tmp->name, name))) + continue; + + if (BadPtr(tmp->passwd)) + continue; + + if (pipe(pi) == -1) + { + report_error("Error creating pipe for R-line %s:%s", + &me); + return 0; + } + switch (rc = vfork()) + { + case -1 : + report_error("Error forking for R-line %s:%s", &me); + return 0; + case 0 : + { + Reg int i; + + (void)close(pi[0]); + for (i = 2; i < MAXCONNECTIONS; i++) + if (i != pi[1]) + (void)close(i); + if (pi[1] != 2) + (void)dup2(pi[1], 2); + (void)dup2(2, 1); + if (pi[1] != 2 && pi[1] != 1) + (void)close(pi[1]); + (void)execlp(tmp->passwd, tmp->passwd, name, host, + cptr->username, 0); + _exit(-1); + } + default : + (void)close(pi[1]); + break; + } + *reply = '\0'; + (void)dgets(-1, NULL, 0); /* make sure buffer marked empty */ + while ((n = dgets(pi[0], temprpl, sizeof(temprpl)-1)) > 0) + { + temprpl[n] = '\0'; + if ((s = (char *)index(temprpl, '\n'))) + *s = '\0'; + if (strlen(temprpl) + strlen(reply) < sizeof(reply)-2) + SPRINTF(rplhold,"%s %s", rplhold, temprpl); + else + { + sendto_flag(SCH_ERROR, + "R-line %s/%s: reply too long!", + name, host); + break; + } + } + (void)dgets(-1, NULL, 0); /* make sure buffer marked empty */ + (void)close(pi[0]); + (void)kill(rc, SIGKILL); /* cleanup time */ +#if !defined(USE_IAUTH) + (void)wait(0); +#endif + + rc = 0; + while (*rplhold == ' ') + rplhold++; + rplchar = *rplhold; /* Pull out the yes or no */ + while (*rplhold != ' ') + rplhold++; + while (*rplhold == ' ') + rplhold++; + (void)strcpy(reply,rplhold); + rplhold = reply; + + if ((rc = (rplchar == 'n' || rplchar == 'N'))) + break; + } + if (rc) + { + sendto_one(cptr, ":%s %d %s :Restriction: %s", + ME, ERR_YOUREBANNEDCREEP, cptr->name, reply); + return -1; + } + return 0; +} +#endif + + +/* +** check against a set of time intervals +*/ + +static int check_time_interval(interval, reply) +char *interval, *reply; +{ + struct tm *tptr; + char *p; + int perm_min_hours, perm_min_minutes, + perm_max_hours, perm_max_minutes; + int now, perm_min, perm_max; + + tptr = localtime(&timeofday); + now = tptr->tm_hour * 60 + tptr->tm_min; + + while (interval) + { + p = (char *)index(interval, ','); + if (p) + *p = '\0'; + if (sscanf(interval, "%2d%2d-%2d%2d", + &perm_min_hours, &perm_min_minutes, + &perm_max_hours, &perm_max_minutes) != 4) + { + if (p) + *p = ','; + return(0); + } + if (p) + *(p++) = ','; + perm_min = 60 * perm_min_hours + perm_min_minutes; + perm_max = 60 * perm_max_hours + perm_max_minutes; + /* + ** The following check allows intervals over midnight ... + */ + if ((perm_min < perm_max) + ? (perm_min <= now && now <= perm_max) + : (perm_min <= now || now <= perm_max)) + { + (void)sprintf(reply, + ":%%s %%d %%s :%s %d:%02d to %d:%02d.", + "You are not allowed to connect from", + perm_min_hours, perm_min_minutes, + perm_max_hours, perm_max_minutes); + return(ERR_YOUREBANNEDCREEP); + } + if ((perm_min < perm_max) + ? (perm_min <= now + 5 && now + 5 <= perm_max) + : (perm_min <= now + 5 || now + 5 <= perm_max)) + { + (void)sprintf(reply, ":%%s %%d %%s :%d minute%s%s", + perm_min-now,(perm_min-now)>1?"s ":" ", + "and you will be denied for further access"); + return(ERR_YOUWILLBEBANNED); + } + interval = p; + } + return(0); +} + +/* +** find_bounce +** send a bounce numeric to a client. +** fd is optional, and only makes sense if positive and when cptr is NULL +** fd == -1 : not fd, class is a class number. +** fd == -2 : not fd, class isn't a class number. +*/ +void find_bounce(cptr, class, fd) +aClient *cptr; +int class, fd; + { + Reg aConfItem *aconf; + + for (aconf = conf; aconf; aconf = aconf->next) + { + if (aconf->status != CONF_BOUNCE) + continue; + + if (fd >= 0) + /* + ** early rejection, + ** connection class and hostname are unknown + */ + if (*aconf->host == '\0') + { + char rpl[BUFSIZE]; + + SPRINTF(rpl, rpl_str(RPL_BOUNCE,"unknown"), + aconf->name, aconf->port); + strcat(rpl, "\r\n"); +#ifdef INET6 + sendto(class, rpl, strlen(rpl), 0, 0, 0); +#else + send(class, rpl, strlen(rpl), 0); +#endif + return; + } + else + continue; + + /* fd < 0 */ + /* + ** "too many" type rejection, class is known. + ** check if B line is for a class #, + ** and if it is for a hostname. + */ + if (fd != -2 && + !strchr(aconf->host, '.') && isdigit(*aconf->host)) + { + if (class != atoi(aconf->host)) + continue; + } + else + if (strchr(aconf->host, '/')) + { + if (match_ipmask(aconf->host, cptr)) + continue; + } + else if (match(aconf->host, cptr->sockhost)) + continue; + + sendto_one(cptr, rpl_str(RPL_BOUNCE, cptr->name), aconf->name, + aconf->port); + return; + } + + } + +/* +** find_denied +** for a given server name, make sure no D line matches any of the +** servers currently present on the net. +*/ +aConfItem * +find_denied(name, class) + char *name; + int class; +{ + aConfItem *aconf; + + for (aconf = conf; aconf; aconf = aconf->next) + { + if (aconf->status != CONF_DENY) + continue; + if (!aconf->name) + continue; + if (match(aconf->name, name) && aconf->port != class) + continue; + if (isdigit(*aconf->passwd)) + { + aConfItem *aconf2; + int ck = atoi(aconf->passwd); + + for (aconf2 = conf; aconf2; aconf2 = aconf2->next) + { + if (aconf2->status != CONF_NOCONNECT_SERVER) + continue; + if (!aconf2->class || ConfClass(aconf2) != ck) + continue; + if (find_client(aconf2->host, NULL)) + return aconf2; + } + } + if (aconf->host) + { + aServer *asptr; + + for (asptr = svrtop; asptr; asptr = asptr->nexts) + if (aconf->host && + !match(aconf->host, asptr->bcptr->name)) + return aconf; + } + } + return NULL; +} diff --git a/ircd/s_conf_ext.h b/ircd/s_conf_ext.h new file mode 100644 index 0000000..8257254 --- /dev/null +++ b/ircd/s_conf_ext.h @@ -0,0 +1,66 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_conf_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_conf.c. + */ + +/* External definitions for global variables. + */ +#ifndef S_CONF_C +extern aConfItem *conf, *kconf; +#endif /* S_CONF_C */ + +/* External definitions for global functions. + */ +#ifndef S_CONF_C +#define EXTERN extern +#else /* S_CONF_C */ +#define EXTERN +#endif /* S_CONF_C */ +EXTERN void det_confs_butmask __P((aClient *cptr, int mask)); +EXTERN int attach_Iline __P((aClient *cptr, Reg struct hostent *hp, + char *sockhost)); +EXTERN aConfItem *count_cnlines __P((Reg Link *lp)); +EXTERN int detach_conf __P((aClient *cptr, aConfItem *aconf)); +EXTERN int attach_conf __P((aClient *cptr, aConfItem *aconf)); +EXTERN aConfItem *find_admin(); +EXTERN aConfItem *find_me(); +EXTERN aConfItem *attach_confs __P((aClient *cptr, char *name, int statmask)); +EXTERN aConfItem *attach_confs_host __P((aClient *cptr, char *host, + int statmask)); +EXTERN aConfItem *find_conf_exact __P((char *name, char *user, char *host, + int statmask)); +EXTERN aConfItem *find_conf_name __P((char *name, int statmask)); +EXTERN aConfItem *find_conf __P((Link *lp, char *name, int statmask)); +EXTERN aConfItem *find_conf_host __P((Reg Link *lp, char *host, + Reg int statmask)); +EXTERN aConfItem *find_conf_ip __P((Link *lp, char *ip, char *user, + int statmask)); +EXTERN aConfItem *find_conf_entry __P((aConfItem *aconf, u_int mask)); +EXTERN int rehash __P((aClient *cptr, aClient *sptr, int sig)); +EXTERN int openconf(); +EXTERN int initconf __P((int opt)); +EXTERN int find_kill __P((aClient *cptr, int doall, char **comment)); +EXTERN int find_two_masks __P((char *name, char *host, int stat)); +EXTERN int find_conf_flags __P((char *name, char *key, int stat)); +EXTERN int find_restrict __P((aClient *cptr)); +EXTERN void find_bounce __P((aClient *cptr, int class, int fd)); +EXTERN aConfItem *find_denied __P((char *name, int class)); +#undef EXTERN diff --git a/ircd/s_debug.c b/ircd/s_debug.c new file mode 100644 index 0000000..c3d9c4f --- /dev/null +++ b/ircd/s_debug.c @@ -0,0 +1,668 @@ +/************************************************************************ + * 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 rcsid[] = "@(#)$Id: s_debug.c,v 1.28 1999/07/11 22:11:17 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_DEBUG_C +#include "s_externs.h" +#undef S_DEBUG_C + +/* + * Option string. Must be before #ifdef DEBUGMODE. + * spaces are not allowed. + */ +char serveropts[] = { +#ifndef NO_IDENT +'a', +#endif +#ifdef CHROOTDIR +'c', +#endif +#ifdef CMDLINE_CONFIG +'C', +#endif +#ifdef DEBUGMODE +'D', +#endif +#ifdef RANDOM_NDELAY +'d', +#endif +#if defined(LOCOP_REHASH) && defined(OPER_REHASH) +'e', +#endif +#ifdef OPER_REHASH +'E', +#endif +#ifdef SLOW_ACCEPT +'f', +#endif +#ifdef CLONE_CHECK +'F', +#endif +#ifdef SUN_GSO_BUG +'g', +#endif +#ifdef HUB +'H', +#endif +#ifdef BETTER_CDELAY +'h', +#endif +#ifdef SHOW_INVISIBLE_LUSERS +'i', +#endif +#ifndef NO_DEFAULT_INVISIBLE +'I', +#endif +#if defined(LOCOP_DIE) && defined(OPER_DIE) +'j', +#endif +#ifdef OPER_DIE +'J', +#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 NPATH /* gone */ +'N', +#endif +#ifdef BETTER_NDELAY +'n', +#endif +#ifdef CRYPT_OPER_PASSWORD +'p', +#endif +#ifdef CRYPT_LINK_PASSWORD +'P', +#endif +#if defined(LOCOP_RESTART) && defined(OPER_RESTART) +'r', +#endif +#ifdef OPER_RESTART +'R', +#endif +#ifdef USE_SERVICES +'s', +#endif +#ifdef ENABLE_SUMMON +'S', +#endif +#ifdef OPER_REMOTE +'t', +#endif +#ifndef NO_PREFIX +'u', +#endif +#ifdef ENABLE_USERS +'U', +#endif +#ifdef VALLOC +'V', +#endif +#ifdef NOWRITEALARM +'w', +#endif +#ifdef UNIXPORT +'X', +#endif +#ifdef USE_SYSLOG +'Y', +#endif +#ifdef ZIP_LINKS +'Z', +#endif +#ifdef INET6 +'6', +#endif +'\0'}; + +#ifdef DEBUGMODE +static char debugbuf[2*READBUF_SIZE]; /* needs to be big.. */ + +#if ! USE_STDARG +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; +#else +void debug(int level, char *form, ...) +#endif +{ + int err = errno; + +#ifdef USE_SYSLOG + if (level == DEBUG_ERROR) + { +#if ! USE_STDARG + syslog(LOG_ERR, form, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#else +# if HAVE_VSYSLOG + va_list va; + va_start(va, form); + vsyslog(LOG_ERR, form, va); + va_end(va); +# else + va_list va; + va_start(va, form); + vsprintf(debugbuf, form, va); + va_end(va); + syslog(LOG_ERR, debugbuf); +# endif +#endif + } +#endif + if ((debuglevel >= 0) && (level <= debuglevel)) + { +#if ! USE_STDARG + (void)sprintf(debugbuf, form, + p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); +#else + va_list va; + va_start(va, form); + (void)vsprintf(debugbuf, form, va); + va_end(va); +#endif + if (local[2]) + { + local[2]->sendM++; + local[2]->sendB += strlen(debugbuf); + } + (void)fprintf(stderr, "%s", debugbuf); + (void)fputc('\n', stderr); + } + errno = err; +} +#endif /* DEBUGMODE */ + +/* + * 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; +{ +#if HAVE_GETRUSAGE + 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) + { + 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 = timeofday - 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); + if (rup && hzz) + 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 /* HAVE_GETRUSAGE */ +# if HAVE_TIMES + 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 /* HAVE_TIMES */ +#endif /* HAVE_GETRUSAGE */ + sendto_one(cptr, ":%s %d %s :DBUF alloc %d blocks %d", + me.name, RPL_STATSDEBUG, nick, istat.is_dbufuse, + istat.is_dbufnow); +#ifdef DEBUGMODE + sendto_one(cptr, ":%s %d %s :Reads %d Writes %d", + me.name, RPL_STATSDEBUG, nick, readcalls, writecalls); + 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]); +#endif + return; +} + +void send_defines(cptr, nick) +aClient *cptr; +char *nick; +{ + sendto_one(cptr, ":%s %d %s :HUB:%s MS:%d", + ME, RPL_STATSDEFINE, nick, +#ifdef HUB + "yes", +#else + "no", +#endif + MAXSERVERS); + sendto_one(cptr, + ":%s %d %s :LQ:%d MXC:%d TS:%d HRD:%d HGL:%d WWD:%d ATO:%d", + ME, RPL_STATSDEFINE, nick, LISTENQUEUE, MAXCONNECTIONS, + TIMESEC, HANGONRETRYDELAY, HANGONGOODLINK, WRITEWAITDELAY, + ACCEPTTIMEOUT); + sendto_one(cptr, ":%s %d %s :KCTL:%d DCTL:%d LDCTL: %d CF:%d MCPU:%d", + ME, RPL_STATSDEFINE, nick, KILLCHASETIMELIMIT, + DELAYCHASETIMELIMIT, LDELAYCHASETIMELIMIT, + CLIENT_FLOOD, MAXCHANNELSPERUSER); + sendto_one(cptr, ":%s %d %s :H:%d N:%d U:%d R:%d T:%d C:%d P:%d K:%d", + ME, RPL_STATSDEFINE, nick, HOSTLEN, NICKLEN, USERLEN, + REALLEN, TOPICLEN, CHANNELLEN, PASSWDLEN, KEYLEN); + sendto_one(cptr, ":%s %d %s :BS:%d MXR:%d MXB:%d MXBL:%d PY:%d", + ME, RPL_STATSDEFINE, nick, BUFSIZE, MAXRECIPIENTS, MAXBANS, + MAXBANLENGTH, MAXPENALTY); + sendto_one(cptr, ":%s %d %s :ZL:%d CM:%d CP:%d", + ME, RPL_STATSDEFINE, nick, +#ifdef ZIP_LINKS + ZIP_LEVEL, +#else + -1, +#endif +#ifdef CLONE_CHECK + CLONE_MAX, CLONE_PERIOD +#else + -1, -1 +#endif + ); +} + +void count_memory(cptr, nick, debug) +aClient *cptr; +char *nick; +int debug; +{ + extern aChannel *channel; + extern aClass *classes; + extern aConfItem *conf; + extern int _HASHSIZE, _CHANNELHASHSIZE; + + Reg aClient *acptr; + Reg Link *link; + Reg aChannel *chptr; + Reg aConfItem *aconf; + Reg aClass *cltmp; + + int lc = 0, d_lc = 0, /* local clients */ + ch = 0, d_ch = 0, /* channels */ + lcc = 0, d_lcc = 0, /* local client conf links */ + rc = 0, d_rc = 0, /* remote clients */ + us = 0, d_us = 0, /* user structs */ + chu = 0, d_chu = 0, /* channel users */ + chi = 0, d_chi = 0, /* channel invites */ + chb = 0, d_chb = 0, /* channel bans */ + chh = 0, d_chh = 0, /* channel in history */ + wwu = 0, d_wwu = 0, /* whowas users */ + cl = 0, d_cl = 0, /* classes */ + co = 0, d_co = 0; /* conf lines */ + + int usi = 0, d_usi = 0, /* users invited */ + usc = 0, d_usc = 0, /* users in channels */ + aw = 0, d_aw = 0, /* aways set */ + wwa = 0, d_wwa = 0, /* whowas aways */ + wwuw = 0, d_wwuw = 0; /* whowas uwas */ + + u_long chm = 0, d_chm = 0, /* memory used by channels */ + chhm = 0, d_chhm = 0, /* memory used by channel in history */ + chbm = 0, d_chbm = 0, /* memory used by channel bans */ + lcm = 0, d_lcm = 0, /* memory used by local clients */ + rcm = 0, d_rcm = 0, /* memory used by remote clients */ + awm = 0, d_awm = 0, /* memory used by aways */ + wwam = 0, d_wwam = 0, /* whowas away memory used */ + wwm = 0, d_wwm = 0, /* whowas array memory used */ + dm = 0, d_dm = 0, /* delay array memory used */ + com = 0, d_com = 0, /* memory used by conf lines */ + db = 0, d_db = 0, /* memory used by dbufs */ + rm = 0, d_rm = 0, /* res memory used */ + totcl = 0, d_totcl = 0, + totch = 0, d_totch = 0, + totww = 0, d_totww = 0, + tot = 0, d_tot = 0; + time_t start = 0; + + if (debug) + { + start = time(NULL); + count_whowas_memory(&d_wwu, &d_wwa, &d_wwam, &d_wwuw); + d_wwm = sizeof(aName) * ww_size; + d_dm = sizeof(aLock) * lk_size; + } + wwu = istat.is_wwusers; + wwa = istat.is_wwaways; + wwam = istat.is_wwawaysmem; + wwuw = istat.is_wwuwas; + wwm = sizeof(aName) * ww_size; + dm = sizeof(aLock) * lk_size; + + /*lc = istat.is_unknown + istat.is_myclnt + istat.is_serv;*/ + lc = istat.is_localc; + lcc = istat.is_conflink; + rc = istat.is_remc; + us = istat.is_users; + usi = istat.is_useri; + usc = istat.is_userc; + aw = istat.is_away; + awm = istat.is_awaymem; + + if (debug) + for (acptr = client; acptr; acptr = acptr->next) + { + if (MyConnect(acptr)) + { + d_lc++; + for (link =acptr->confs; link; link=link->next) + d_lcc++; + } + else + d_rc++; + if (acptr->user) + { + d_us++; + for (link = acptr->user->invited; link; + link = link->next) + d_usi++; + d_usc += acptr->user->joined; + if (acptr->user->away) + { + d_aw++; + d_awm += (strlen(acptr->user->away)+1); + } + } + } + + lcm = lc * CLIENT_LOCAL_SIZE; + rcm = rc * CLIENT_REMOTE_SIZE; + + d_lcm = d_lc * CLIENT_LOCAL_SIZE; + d_rcm = d_rc * CLIENT_REMOTE_SIZE; + + ch = istat.is_chan; + chm = istat.is_chanmem; + chh = istat.is_hchan; + chhm = istat.is_hchanmem; + chi = istat.is_invite; + chb = istat.is_bans; + chbm = istat.is_banmem + chb * sizeof(Link); + chu = istat.is_chanusers; + + if (debug) + { + for (chptr = channel; chptr; chptr = chptr->nextch) + { + if (chptr->users == 0) + { + d_chh++; + d_chhm+=strlen(chptr->chname)+sizeof(aChannel); + } + else + { + d_ch++; + d_chm += (strlen(chptr->chname) + + sizeof(aChannel)); + } + for (link = chptr->members; link; link = link->next) + d_chu++; + for (link = chptr->invites; link; link = link->next) + d_chi++; + for (link = chptr->mlist; link; link = link->next) + { + d_chb++; + d_chbm += strlen(link->value.cp) + 1; + } + } + d_chbm += d_chb * sizeof(Link); + } + + co = istat.is_conf; + com = istat.is_confmem; + cl = istat.is_class; + + if (debug) + { + for (aconf = conf; aconf; aconf = aconf->next) + { + d_co++; + d_com += aconf->host ? strlen(aconf->host)+1 : 0; + d_com += aconf->passwd ? strlen(aconf->passwd)+1 : 0; + d_com += aconf->name ? strlen(aconf->name)+1 : 0; + d_com += aconf->ping ? sizeof(*aconf->ping) : 0; + d_com += sizeof(aConfItem); + } + for (cltmp = classes; cltmp; cltmp = cltmp->next) + d_cl++; + } + + if (debug) + sendto_one(cptr, ":%s %d %s :Request processed in %u seconds", + me.name, RPL_STATSDEBUG, nick, time(NULL) - start); + + sendto_one(cptr, + ":%s %d %s :Client Local %d(%d) Remote %d(%d) Auth %d(%d)", + me.name, RPL_STATSDEBUG, nick, lc, lcm, rc, rcm, + istat.is_auth, istat.is_authmem); + if (debug + && (lc != d_lc || lcm != d_lcm || rc != d_rc || rcm != d_rcm)) + sendto_one(cptr, + ":%s %d %s :Client Local %d(%d) Remote %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, d_lc, d_lcm, d_rc, + d_rcm); + sendto_one(cptr, + ":%s %d %s :Users %d in/visible %d/%d(%d) Invites %d(%d)", + me.name, RPL_STATSDEBUG, nick, us, istat.is_user[1], + istat.is_user[0], us*sizeof(anUser), usi, + usi*sizeof(Link)); + if (debug && (us != d_us || usi != d_usi)) + sendto_one(cptr, + ":%s %d %s :Users %d(%d) Invites %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, d_us, + d_us*sizeof(anUser), d_usi, d_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); + if (debug && (usc != d_usc || aw != d_aw || awm != d_awm)) + sendto_one(cptr, + ":%s %d %s :User channels %d(%d) Aways %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, d_usc, + d_usc*sizeof(Link), d_aw, d_awm); + sendto_one(cptr, ":%s %d %s :Attached confs %d(%d)", + me.name, RPL_STATSDEBUG, nick, lcc, lcc*sizeof(Link)); + if (debug && lcc != d_lcc) + sendto_one(cptr, ":%s %d %s :Attached confs %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, d_lcc, + d_lcc*sizeof(Link)); + + totcl = lcm + rcm + us*sizeof(anUser) + usc*sizeof(Link) + awm; + totcl += lcc*sizeof(Link) + usi*sizeof(Link); + d_totcl = d_lcm + d_rcm + d_us*sizeof(anUser) + d_usc*sizeof(Link); + d_totcl += d_awm + d_lcc*sizeof(Link) + d_usi*sizeof(Link); + + sendto_one(cptr, ":%s %d %s :Conflines %d(%d)", + me.name, RPL_STATSDEBUG, nick, co, com); + if (debug && (co != d_co || com != d_com)) + sendto_one(cptr, ":%s %d %s :Conflines %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, d_co, d_com); + + sendto_one(cptr, ":%s %d %s :Classes %d(%d)", + me.name, RPL_STATSDEBUG, nick, cl, cl*sizeof(aClass)); + if (debug && cl != d_cl) + sendto_one(cptr, ":%s %d %s :Classes %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, d_cl, + d_cl*sizeof(aClass)); + + sendto_one(cptr, + ":%s %d %s :Channels %d(%d) Modes %d(%d) History %d(%d) Cache %d(%d)", + me.name, RPL_STATSDEBUG, nick, ch, chm, chb, chbm, chh, + chhm, istat.is_cchan, istat.is_cchanmem); + if (debug && (ch != d_ch || chm != d_chm || chb != d_chb + || chbm != d_chbm || chh != d_chh || chhm != d_chhm)) + sendto_one(cptr, + ":%s %d %s :Channels %d(%d) Modes %d(%d) History %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, d_ch, d_chm, d_chb, + d_chbm, d_chh, d_chhm); + sendto_one(cptr, ":%s %d %s :Channel members %d(%d) invite %d(%d)", + me.name, RPL_STATSDEBUG, nick, chu, chu*sizeof(Link), + chi, chi*sizeof(Link)); + if (debug && (chu != d_chu || chi != d_chi)) + sendto_one(cptr, + ":%s %d %s :Channel members %d(%d) invite %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, d_chu, d_chu*sizeof(Link), + d_chi, d_chi*sizeof(Link)); + + totch = chm + chhm + chbm + chu*sizeof(Link) + chi*sizeof(Link); + d_totch = d_chm + d_chhm + d_chbm + d_chu*sizeof(Link) + + d_chi*sizeof(Link); + + sendto_one(cptr, + ":%s %d %s :Whowas users %d(%d) away %d(%d) links %d(%d)", + me.name, RPL_STATSDEBUG, nick, wwu, wwu*sizeof(anUser), + wwa, wwam, wwuw, wwuw*sizeof(Link)); + if (debug && (wwu != d_wwu || wwa != d_wwa || wwam != d_wwam + || wwuw != d_wwuw)) + sendto_one(cptr, + ":%s %d %s :Whowas users %d(%d) away %d(%d) links %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, d_wwu, d_wwu*sizeof(anUser), + d_wwa, d_wwam, d_wwuw, d_wwuw*sizeof(Link)); + sendto_one(cptr, ":%s %d %s :Whowas array %d(%d) Delay array %d(%d)", + me.name, RPL_STATSDEBUG, nick, ww_size, wwm, lk_size, dm); + if (debug && (wwm != d_wwm || dm != d_dm)) + sendto_one(cptr, + ":%s %d %s :Whowas array %d(%d) Delay array %d(%d) [REAL]", + me.name, RPL_STATSDEBUG, nick, ww_size, d_wwm, lk_size, + d_dm); + + totww = wwu*sizeof(anUser) + wwam + wwm; + d_totww = d_wwu*sizeof(anUser) + d_wwam + d_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); + d_db = db = istat.is_dbufnow * sizeof(dbufbuf); + db = istat.is_dbufnow * sizeof(dbufbuf); + sendto_one(cptr, + ":%s %d %s :Dbuf blocks %u(%d) (> %u [%u]) (%u < %u) [%u]", + me.name, RPL_STATSDEBUG, nick, istat.is_dbufnow, db, + istat.is_dbuf, + (u_int) (((u_int)BUFFERPOOL) / ((u_int)sizeof(dbufbuf))), + istat.is_dbufuse, istat.is_dbufmax, istat.is_dbufmore); + + d_rm = rm = cres_mem(cptr, nick); + + tot = totww + totch + totcl + com + cl*sizeof(aClass) + db + rm; + tot += sizeof(aHashEntry) * _HASHSIZE; + tot += sizeof(aHashEntry) * _CHANNELHASHSIZE; + d_tot = d_totww + d_totch + d_totcl + d_com + d_cl*sizeof(aClass); + d_tot += d_db + d_rm; + d_tot += sizeof(aHashEntry) * _HASHSIZE; + d_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); + if (debug && tot != d_tot) + { + sendto_one(cptr, + ":%s %d %s :Total: ww %d ch %d cl %d co %d db %d [REAL]", + me.name, RPL_STATSDEBUG, nick, d_totww, d_totch, d_totcl, + d_com, d_db); + sendto_one(cptr, ":%s %d %s :TOTAL: %d [REAL]", + me.name, RPL_STATSDEBUG, nick, d_tot); + } + sendto_one(cptr, ":%s %d %s :TOTAL: %d sbrk(0)-etext: %u", + me.name, RPL_STATSDEBUG, nick, tot, + (u_long)sbrk((size_t)0)-(u_long)sbrk0); + return; +} diff --git a/ircd/s_debug_ext.h b/ircd/s_debug_ext.h new file mode 100644 index 0000000..a2b2df5 --- /dev/null +++ b/ircd/s_debug_ext.h @@ -0,0 +1,45 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_debug_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_debug.c. + */ + +/* External definitions for global variables. + */ +#ifndef S_DEBUG_C +extern char serveropts[]; +#endif /* S_DEBUG_C */ + +/* External definitions for global functions. + */ +#ifndef S_DEBUG_C +#define EXTERN extern +#else /* S_DEBUG_C */ +#define EXTERN +#endif /* S_DEBUG_C */ +#if ! USE_STDARG +EXTERN void debug(); +#else /* USE_STDARG */ +EXTERN void debug (int level, char *form, ...); +#endif /* USE_STDARG */ +EXTERN void send_usage __P((aClient *cptr, char *nick)); +EXTERN void send_defines __P((aClient *cptr, char *nick)); +EXTERN void count_memory __P((aClient *cptr, char *nick, int debug)); +#undef EXTERN diff --git a/ircd/s_defines.h b/ircd/s_defines.h new file mode 100644 index 0000000..19f0d07 --- /dev/null +++ b/ircd/s_defines.h @@ -0,0 +1,41 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_defines.h + * Copyright (C) 1997 Alain Nissen + * + * 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 includes all files defining constants, macros and types + definitions used by the IRC server. + */ + +#include "config.h" +#include "patchlevel.h" + +#include "common_def.h" +#include "dbuf_def.h" +#include "class_def.h" +#include "struct_def.h" +#include "msg_def.h" +#include "numeric_def.h" +#include "support_def.h" +#include "channel_def.h" +#include "hash_def.h" +#include "res_def.h" +#include "whowas_def.h" +#include "service_def.h" +#include "sys_def.h" +#include "resolv_def.h" +#include "nameser_def.h" diff --git a/ircd/s_err.c b/ircd/s_err.c new file mode 100644 index 0000000..319e7b5 --- /dev/null +++ b/ircd/s_err.c @@ -0,0 +1,436 @@ +/************************************************************************ + * 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. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: s_err.c,v 1.24 1999/02/22 21:38:33 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_ERR_C +#include "s_externs.h" +#undef S_ERR_C + +typedef struct { + int num_val; + char *num_form; +} Numeric; + +static char *prepbuf __P((char *, char *, char *, int, char *)); +static char numbuff[512]; + +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 aoOirw abeiIklmnoOpqrstv" }, +/* 005 */ { RPL_BOUNCE, ":Try server %s, port %d" }, + { 0, (char *)NULL } +}; + +static Numeric numeric_errors[] = { +/* 401 */ { ERR_NOSUCHNICK, "%s :No such nick/channel" }, +/* 402 */ { ERR_NOSUCHSERVER, "%s :No such server" }, +/* 403 */ { ERR_NOSUCHCHANNEL, "%s :No such channel" }, +/* 404 */ { ERR_CANNOTSENDTOCHAN, "%s :Cannot send to channel" }, +/* 405 */ { ERR_TOOMANYCHANNELS, "%s :You have joined too many channels" }, +/* 406 */ { ERR_WASNOSUCHNICK, "%s :There was no such nickname" }, +/* 407 */ { ERR_TOOMANYTARGETS, + "%s :%s recipients. %s" }, +/* 408 */ { ERR_NOSUCHSERVICE, "%s :No such service" }, +/* 409 */ { ERR_NOORIGIN, ":No origin specified" }, + { 0, (char *)NULL }, +/* 411 */ { ERR_NORECIPIENT, ":No recipient given (%s)" }, +/* 412 */ { ERR_NOTEXTTOSEND, ":No text to send" }, +/* 413 */ { ERR_NOTOPLEVEL, "%s :No toplevel domain specified" }, +/* 414 */ { ERR_WILDTOPLEVEL, "%s :Wildcard in toplevel Domain" }, +/* 415 */ { ERR_BADMASK, "%s :Bad Server/host mask" }, +/* 416 */ { ERR_TOOMANYMATCHES, "%s %s :Output too long (try locally)" }, + { 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" }, +/* 423 */ { ERR_NOADMININFO, + "%s :No administrative info available" }, +/* 424 */ { 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 :Erroneous 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 from %s@%s" }, +/* 437 */ { ERR_UNAVAILRESOURCE, + "%s :Nick/channel is temporarily unavailable" }, +/* 438 */ { 0, (char *)NULL }, /* reserved for later use -krys */ + { 0, (char *)NULL }, + { 0, (char *)NULL }, + { ERR_USERNOTINCHANNEL, "%s %s :They aren't on that channel" }, + { 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, + ":Unauthorized command (already registered)" }, +/* 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 for %s" }, +/* 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" }, +/* 477 */ { ERR_NOCHANMODES, "%s :Channel doesn't support modes" }, +/* 478 */ { ERR_BANLISTFULL, "%s %s :Channel 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, "%s :You can't kill a server!" }, +/* 484 */ { ERR_RESTRICTED, ":Your connection is restricted!" }, +/* 485 */ { ERR_UNIQOPRIVSNEEDED, + ":You're not the original channel operator" }, + { 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, ":Can't change mode for other users" }, + { 0, (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 :seconds idle" }, +/* 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" }, +/* 325 */ { RPL_UNIQOPIS, "%s %s" }, + { 0, (char *)NULL }, + { 0, (char *)NULL }, + { 0, (char *)NULL }, + { 0, (char *)NULL }, + { 0, (char *)NULL }, +/* 331 */ { RPL_NOTOPIC, "%s :No topic is set." }, +/* 332 */ { RPL_TOPIC, "%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 }, +/* 341 */ { RPL_INVITING, "%s %s" }, +/* 342 */ { RPL_SUMMONING, "%s :User summoned to irc" }, + { 0, (char *)NULL }, + { 0, (char *)NULL }, + { 0, (char *)NULL }, +/* 346 */ { RPL_INVITELIST, "%s %s" }, +/* 347 */ { RPL_ENDOFINVITELIST, "%s :End of Channel Invite List" }, +/* 348 */ { RPL_EXCEPTLIST, "%s %s" }, +/* 349 */ { RPL_ENDOFEXCEPTLIST, "%s :End of Channel Exception List" }, + { 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 %s" }, +/* 365 */ { RPL_ENDOFLINKS, "%s :End of LINKS list." }, +/* 366 */ { RPL_ENDOFNAMES, "%s :End of NAMES list." }, +/* 367 */ { RPL_BANLIST, "%s %s" }, +/* 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, ":You are service %s" }, +/* 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 :%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 V%X%s %d %d %d" }, +/* 201 */ { RPL_TRACECONNECTING, "Try. %d %s" }, +/* 202 */ { RPL_TRACEHANDSHAKE, "H.S. %d %s" }, +/* 203 */ { RPL_TRACEUNKNOWN, "???? %d %s" }, +/* 204 */ { RPL_TRACEOPERATOR, "Oper %d %s" }, +/* 205 */ { RPL_TRACEUSER, "User %d %s" }, +/* 206 */ { RPL_TRACESERVER, "Serv %d %dS %dC %s %s!%s@%s V%X%s" }, +/* 207 */ { RPL_TRACESERVICE, "Service %d %s 0x%X 0x%X" }, +/* 208 */ { RPL_TRACENEWTYPE, "<newtype> 0 %s" }, +/* 209 */ { RPL_TRACECLASS, "Class %d %d" }, +/* 210 */ { RPL_TRACERECONNECT, "Retry. %d %s" }, +/* 211 */ { RPL_STATSLINKINFO, (char *)NULL }, +/* 212 */ { RPL_STATSCOMMANDS, "%s %u %u %u" }, +/* 213 */ { RPL_STATSCLINE, "%c %s %s %s %d %d" }, +/* 214 */ { RPL_STATSNLINE, "%c %s %s %s %d %d" }, +/* 215 */ { RPL_STATSILINE, "%c %s %s %s %d %d" }, +/* 216 */ { RPL_STATSKLINE, "%c %s %s %s %d %d" }, +/* 217 */ { RPL_STATSQLINE, "%c %s %s %s %d %d" }, +/* 218 */ { RPL_STATSYLINE, "%c %d %d %d %d %ld %d.%d %d.%d" }, +/* 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, "%s %s %s 0x%X %d :%s" }, +/* 235 */ { RPL_SERVLISTEND, "%s %d :End of service listing" }, + { 0, (char *)NULL }, + { 0, (char *)NULL }, + { 0, (char *)NULL }, + { 0, (char *)NULL }, +/* 240 */ { RPL_STATSVLINE, "%c %s %s %s %d %d" }, +/* 241 */ { RPL_STATSLLINE, "%c %s %s %s %d %d" }, +/* 242 */ { RPL_STATSUPTIME, ":Server Up %d days, %d:%02d:%02d" }, +/* 243 */ { RPL_STATSOLINE, "%c %s %s %s %d %d" }, +/* 244 */ { RPL_STATSHLINE, "%c %s %s %s %d %d" }, +/* 245 */ { RPL_STATSSLINE, "%c %s %s %s 0x%X %d" }, +/* 246 */ { RPL_STATSPING, "%s %d %d %d %d" }, +/* 247 */ { RPL_STATSBLINE, "%c %s %s %s %d %d" }, + { 0, (char *)NULL }, /* RPL_STATSDEFINE */ + { 0, (char *)NULL }, /* RPL_STATSDEBUG */ +/* 250 */ { RPL_STATSDLINE, "%c %s %s %s %d %d" }, +/* 251 */ { RPL_LUSERCLIENT, + ":There are %d users and %d services on %d servers" }, +/* 252 */ { RPL_LUSEROP, "%d :operators online" }, +/* 253 */ { RPL_LUSERUNKNOWN, "%d :unknown connections" }, +/* 254 */ { RPL_LUSERCHANNELS, "%d :channels formed" }, +/* 255 */ { RPL_LUSERME, ":I have %d clients, %d services 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_TRACEEND, "%s %s.%s :End of TRACE" }, +/* 263 */ { RPL_TRYAGAIN, "%s :Please wait a while and try again." }, + { 0, (char *)NULL } +}; + +char *err_str(numeric, to) +int numeric; +char *to; +{ + Reg Numeric *nptr; + Reg int num = numeric; + + if (BadPtr(to)) /* for unregistered clients */ + to = "*"; + + num -= numeric_errors[0].num_val; + if (num < 0 || num > ERR_USERSDONTMATCH) + SPRINTF(numbuff, + ":%%s %d %%s :INTERNAL ERROR: BAD NUMERIC! %d", + numeric, num); + else + { + nptr = &numeric_errors[num]; + Debug((DEBUG_NUM, + "err_str: to %s #%d num %d nptr %#x %d [%s]", to, + numeric, num, nptr, nptr->num_val, nptr->num_form)); + if (!nptr->num_form || !nptr->num_val) + SPRINTF(numbuff, + ":%%s %d %%s :NO ERROR FOR NUMERIC ERROR %d", + numeric, num); + else + (void)prepbuf(numbuff, ME, to, nptr->num_val, + nptr->num_form); + } + return numbuff; +} + + +char *rpl_str(numeric, to) +int numeric; +char *to; +{ + Reg Numeric *nptr; + Reg int num = numeric; + + if (num > 5) + num -= (num > 300) ? 300 : 100; + + if (BadPtr(to)) /* for unregistered clients */ + to = "*"; + + if (num < 0 || num > 200) + 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: to %s #%d num %d nptr %#x %d [%s]", to, + numeric, num, nptr, nptr->num_val, nptr->num_form)); + if (!nptr->num_form || !nptr->num_val) + SPRINTF(numbuff, + ":%%s %d %%s :NO REPLY FOR NUMERIC ERROR %d", + numeric, num); + else + (void)prepbuf(numbuff, ME, to, nptr->num_val, + nptr->num_form); + } + return numbuff; +} + +static char *prepbuf(buffer, from, to, num, tail) +char *buffer; +Reg int num; +char *from, *to, *tail; +{ + Reg char *s = buffer; + + *s++ = ':'; + (void)strcpy(s, from); + (void)strcat(s, " "); + s += strlen(s); + + *s++ = '0' + num/100; + num %= 100; + *s++ = '0' + num/10; + *s++ = '0' + num%10; + *s++ = ' '; + (void)strcpy(s, to); + s += strlen(s); + *s++ = ' '; + (void)strcpy(s, tail); + return buffer; +} diff --git a/ircd/s_err_ext.h b/ircd/s_err_ext.h new file mode 100644 index 0000000..e5d0534 --- /dev/null +++ b/ircd/s_err_ext.h @@ -0,0 +1,33 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_err_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_err.c. + */ + +/* External definitions for global functions. + */ +#ifndef S_ERR_C +#define EXTERN extern +#else /* S_ERR_C */ +#define EXTERN +#endif /* S_ERR_C */ +EXTERN char *err_str __P((int numeric, char *to)); +EXTERN char *rpl_str __P((int numeric, char *to)); +#undef EXTERN diff --git a/ircd/s_externs.h b/ircd/s_externs.h new file mode 100644 index 0000000..d0ef238 --- /dev/null +++ b/ircd/s_externs.h @@ -0,0 +1,53 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_externs.h + * Copyright (C) 1997 Alain Nissen + * + * 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 includes all *_ext.h files containing external declarations + * for the IRC server. + */ + +#include "bsd_ext.h" +#include "channel_ext.h" +#include "class_ext.h" +#include "dbuf_ext.h" +#include "hash_ext.h" +#include "ircd_ext.h" +#include "list_ext.h" +#include "match_ext.h" +#include "packet_ext.h" +#include "parse_ext.h" +#include "res_comp_ext.h" +#include "res_ext.h" +#include "res_init_ext.h" +#include "res_mkquery_ext.h" +#include "s_auth_ext.h" +#include "s_bsd_ext.h" +#include "s_conf_ext.h" +#include "s_debug_ext.h" +#include "s_err_ext.h" +#include "s_misc_ext.h" +#include "s_numeric_ext.h" +#include "s_serv_ext.h" +#include "s_service_ext.h" +#include "s_user_ext.h" +#include "s_zip_ext.h" +#include "s_id_ext.h" +#include "send_ext.h" +#include "support_ext.h" +#include "version_ext.h" +#include "whowas_ext.h" diff --git a/ircd/s_id.c b/ircd/s_id.c new file mode 100644 index 0000000..5feb948 --- /dev/null +++ b/ircd/s_id.c @@ -0,0 +1,208 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_id.c + * Copyright (C) 1998 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: s_id.c,v 1.9 1999/07/27 11:26:37 chopin Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_ID_C +#include "s_externs.h" +#undef S_ID_C + +/* + * channel IDs + */ +#define CHIDNB 36 + +static unsigned char id_alphabet[CHIDNB+1] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890A"; + +static unsigned int alphabet_id[256] = + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + /* 0 */ 35, /* 1 */ 26, /* 2 */ 27, /* 3 */ 28, /* 4 */ 29, + /* 5 */ 30, /* 6 */ 31, /* 7 */ 32, /* 8 */ 33, /* 9 */ 34, + -1, -1, -1, -1, -1, -1, -1, + /* A */ 0, /* B */ 1, /* C */ 2, /* D */ 3, /* E */ 4, /* F */ 5, + /* G */ 6, /* H */ 7, /* I */ 8, /* J */ 9, /* K */ 10, /* L */ 11, + /* M */ 12, /* N */ 13, /* O */ 14, /* P */ 15, /* Q */ 16, + /* R */ 17, /* S */ 18, /* T */ 19, /* U */ 20, /* V */ 21, + /* W */ 22, /* X */ 23, /* Y */ 24, /* Z */ 25, + -1, -1, -1, -1, -1, -1, + /* a */ 0, /* b */ 1, /* c */ 2, /* d */ 3, /* e */ 4, /* f */ 5, + /* g */ 6, /* h */ 7, /* i */ 8, /* j */ 9, /* k */ 10, /* l */ 11, + /* m */ 12, /* n */ 13, /* o */ 14, /* p */ 15, /* q */ 16, + /* r */ 17, /* s */ 18, /* t */ 19, /* u */ 20, /* v */ 21, + /* w */ 22, /* x */ 23, /* y */ 24, /* z */ 25, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1 }; + +/* ltoid: base 10 -> base 36 conversion */ +static char * +ltoid(l) +time_t l; +{ + static char idrpl[CHIDLEN+1]; + char c = CHIDLEN-1; + + idrpl[CHIDLEN] = '\0'; + do + { + idrpl[c] = id_alphabet[1 + l % CHIDNB]; + l /= CHIDNB; + } + while (c-- > 0); + return (char *) idrpl; +} + +/* idtol: base 36 -> base 10 conversion */ +static unsigned long +idtol(id) +char *id; +{ + unsigned long l = 0; + char c = CHIDLEN-1; + + l = alphabet_id[*id++]; + while (c-- > 0) + l = l * CHIDNB + alphabet_id[*id++]; + return l; +} + +/* get_chid: give the current id */ +char * +get_chid() +{ + return ltoid(time(NULL)); +} + +/* close_chid: is the ID in the close future? (written for CHIDLEN == 5) */ +int +close_chid(id) +char *id; +{ + static time_t last = 0; + static char current; + char *curid; + + if (timeofday - last > 900 || id[0] == current) + { + last = timeofday; + curid = get_chid(); + current = curid[0]; + } + if (id_alphabet[1 + alphabet_id[current]] == id[1]) + return 1; + if (id[0] == current && + idtol(id) >= (timeofday % (u_int) pow(CHIDNB, CHIDLEN))) + return 1; + return 0; +} + +aChannel *idcache = NULL; + +/* cache_chid: add a channel to the list of cached names */ +void +cache_chid(chptr) +aChannel *chptr; +{ + /* + ** caching should be limited to the minimum, + ** for memory reasons, but most importantly for + ** user friendly-ness. + ** Is the logic here right, tho? + */ + if (chptr->history == 0 || + (timeofday - chptr->history) >LDELAYCHASETIMELIMIT+DELAYCHASETIMELIMIT) + { + MyFree((char *)chptr); + return; + } + + chptr->nextch = idcache; + idcache = chptr; + istat.is_cchan++; + istat.is_cchanmem -= sizeof(aChannel) + strlen(chptr->chname); +} + +/* check_chid: checks if a (short) channel name is in the cache + * returns: 0 if not, 1 if yes + */ +int +check_chid(name) +char *name; +{ + aChannel *chptr = idcache; + + while (chptr) + { + if (!strcasecmp(name, chptr->chname+1+CHIDLEN)) + return 1; + chptr = chptr->nextch; + } + return 0; +} + +/* collect_chid: remove expired entries from the cache */ +void +collect_chid() +{ + aChannel **chptr = &idcache, *del; + + while (*chptr) + { + if (close_chid((*chptr)->chname) == 0) + { + del = *chptr; + *chptr = del->nextch; + istat.is_cchan--; + istat.is_cchanmem -= sizeof(aChannel) +strlen(del->chname); + MyFree((char *)del); + } + else + chptr = &((*chptr)->nextch); + } +} + +/* checks wether the ID is valid */ +int +cid_ok(name) +char *name; +{ + int l = 1; + + while (l <= CHIDLEN) + { + if (alphabet_id[name[l]] == -1) + return 0; + l += 1; + } + if (l != CHIDLEN+1) + return 0; + return 1; +} diff --git a/ircd/s_id_ext.h b/ircd/s_id_ext.h new file mode 100644 index 0000000..e55ca33 --- /dev/null +++ b/ircd/s_id_ext.h @@ -0,0 +1,43 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_id_ext.h + * Copyright (C) 1998 Christophe Kalt + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_id.c. + */ + +/* External definitions for global variables. + */ +#ifndef S_ID_C +/* none */ +#endif /* S_ID_C */ + +/* External definitions for global functions. + */ +#ifndef S_ID_C +#define EXTERN extern +#else /* S_ID_C */ +#define EXTERN +#endif /* S_ID_C */ +EXTERN char *get_chid __P(()); +EXTERN int close_chid __P((char *)); +EXTERN void cache_chid __P((aChannel *)); +EXTERN int check_chid __P((char *)); +EXTERN void collect_chid __P(()); +EXTERN int cid_ok __P((char *)); +#undef EXTERN diff --git a/ircd/s_misc.c b/ircd/s_misc.c new file mode 100644 index 0000000..17c9946 --- /dev/null +++ b/ircd/s_misc.c @@ -0,0 +1,998 @@ +/************************************************************************ + * 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 rcsid[] = "@(#)$Id: s_misc.c,v 1.30 1999/07/21 22:57:39 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_MISC_C +#include "s_externs.h" +#undef S_MISC_C + +static void exit_one_client __P((aClient *,aClient *,aClient *,char *)); + +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; + Reg struct tm *lt, *gm; + struct tm gmbuf; + int minswest; + + if (!clock) + time(&clock); + 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 = ((lt->tm_hour + 24) - gm->tm_hour) * 60; + + plus = (minswest > 0) ? '-' : '+'; + if (minswest < 0) + minswest = -minswest; + + (void)sprintf(buf, "%s %s %d %d -- %02d:%02d %c%02d:%02d", + weekdays[lt->tm_wday], months[lt->tm_mon],lt->tm_mday, + lt->tm_year + 1900, lt->tm_hour, lt->tm_min, + plus, minswest/60, minswest%60); + + 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, "*")); + 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, "*")); + return -1; + } + return 0; +} + +/* +** check_registered_service cancels message, if 'x' is not +** a registered service. +*/ +int check_registered_service(sptr) +aClient *sptr; +{ + if (!IsService(sptr)) + { + sendto_one(sptr, err_str(ERR_NOTREGISTERED, "*")); + 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[username@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) + SPRINTF(nbuf, "%s[%s]", + sptr->name, sptr->sockhost); + else + SPRINTF(nbuf, "%s[%s]", + sptr->name, me.sockhost); + } + else + { + if (showip) + (void)sprintf(nbuf, "%s[%.*s@%s]", + sptr->name, USERLEN, + (!(sptr->flags & FLAGS_GOTID)) ? "" : + sptr->auth, +#ifdef INET6 + inetntop(AF_INET6, + (char *)&sptr->ip, + mydummy, MYDUMMY_SIZE)); +#else + inetntoa((char *)&sptr->ip)); +#endif + else + { + if (mycmp(sptr->name, sptr->sockhost)) + /* Show username for clients and + * ident for others. + */ + SPRINTF(nbuf, "%s[%.*s@%s]", + sptr->name, USERLEN, + IsPerson(sptr) ? + sptr->user->username : + sptr->auth, + 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)) + SPRINTF(nbuf, "%s[%s]", cptr->name, ME); + else + (void)sprintf(nbuf, "%s[%-.*s@%-.*s]", + cptr->name, USERLEN, + (!(cptr->flags & FLAGS_GOTID)) ? "" : cptr->auth, + 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) +Reg aClient *cptr; +Reg char *host; +{ + Reg char *s; + if ((s = (char *)index(host, '@'))) + s++; + else + s = host; + strncpyzt(cptr->sockhost, s, sizeof(cptr->sockhost)); + Debug((DEBUG_DNS,"get_sockhost %s",s)); +} + +/* + * Return wildcard name of my server name according to given config entry + * --Jto + */ +char *my_name_for_link(name, count) +char *name; +Reg int count; +{ + static char namebuf[HOSTLEN]; + Reg 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; +} + +/* + * Goes thru the list of locally connected servers (except cptr), + * check if my neighbours can see the server "name" (or if it is hidden + * by a hostmask) + * Returns the number of marked servers + */ +int +mark_blind_servers (cptr, name) +aClient *cptr; +char *name; +{ + Reg int i, j = 0; + Reg aClient *acptr; + Reg aConfItem *aconf; + + for (i = fdas.highest; i >= 0; i--) + { + if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr)) + continue; + if (acptr == cptr || IsMe(acptr)) + { + acptr->flags &= ~FLAGS_HIDDEN; + continue; + } + if ((aconf = acptr->serv->nline) && + (match(my_name_for_link(ME, aconf->port), name) == 0)) + { + acptr->flags |= FLAGS_HIDDEN; + j++; + } + } + return j; +} + +/* +** exit_client +** This is old "m_bye". Name changed, because this is not a +** protocol function, but a general server utility function. +** +** This function exits a client of *any* type (user, server, etc) +** from this server. Also, this generates all necessary prototol +** messages that this exit may cause. +** +** 1) If the client is a local client, then this implicitly +** exits all other clients depending on this connection (e.g. +** remote clients having 'from'-field that points to this. +** +** 2) If the client is a remote client, then only this is exited. +** +** For convenience, this function returns a suitable value for +** m_funtion return value: +** +** FLUSH_BUFFER if (cptr == sptr) +** 0 if (cptr != sptr) +*/ +int exit_client(cptr, sptr, from, comment) +aClient *cptr; /* + ** The local client originating the exit or NULL, if this + ** exit is generated by this server for internal reasons. + ** This will not get any of the generated messages. + */ +aClient *sptr; /* Client exiting */ +aClient *from; /* Client firing off this Exit, never NULL! */ +char *comment; /* Reason for the exit */ + { + Reg aClient *acptr; + Reg aClient *next; + Reg aServer *asptr; + Reg aService *asvptr; +#if defined(FNAME_USERLOG) || defined(USE_SYSLOG) || defined(USE_SERVICES) + time_t on_for; +#endif + char comment1[HOSTLEN + HOSTLEN + 2]; + int flags = 0; + + if (MyConnect(sptr) || (sptr->flags & FLAGS_HELD)) + { + if (sptr->flags & FLAGS_KILLED) + { + sendto_flag(SCH_LOCAL, "Killed: %s.", + get_client_name(sptr, TRUE)); + sptr->exitc = EXITC_KILL; + } + + sptr->flags |= FLAGS_CLOSING; +#if (defined(FNAME_USERLOG) || defined(FNAME_CONNLOG) \ + || defined(USE_SERVICES)) \ + || (defined(USE_SYSLOG) && (defined(SYSLOG_USERS) || defined(SYSLOG_CONN))) + if (IsPerson(sptr)) + { + /* It's ugly, it's simple, it's not so important */ + on_for = timeofday - sptr->firsttime + 1; +# if defined(USE_SYSLOG) && defined(SYSLOG_USERS) + syslog(LOG_NOTICE, + "%s (%3d:%02d:%02d): %s@%s [%s] %c\n", + myctime(sptr->firsttime), + on_for / 3600, (on_for % 3600)/60, + on_for % 60, + sptr->user->username, sptr->user->host, + sptr->auth, sptr->exitc); +# endif +# if defined(FNAME_USERLOG) || defined(USE_SERVICES) + sendto_flog(sptr, NULL, on_for, sptr->user->username, + sptr->user->host); +# endif + } + else if (sptr->exitc != EXITC_REF && sptr->exitc != EXITC_AREF) + { +# if defined(USE_SYSLOG) && defined(SYSLOG_CONN) + syslog(LOG_NOTICE, + "%s ( Unknown ): <none>@%s [%s] %c\n", + myctime(sptr->firsttime), + (IsUnixSocket(sptr)) ? me.sockhost : + ((sptr->hostp) ? sptr->hostp->h_name : + sptr->sockhost), sptr->auth, sptr->exitc); +# endif +# if defined(FNAME_CONNLOG) || defined(USE_SERVICES) + sendto_flog(sptr, " Unknown ", 0, "<none>", + (IsUnixSocket(sptr)) ? me.sockhost : + ((sptr->hostp) ? sptr->hostp->h_name : + sptr->sockhost)); +# endif + } +#endif + if (MyConnect(sptr)) + { + if (IsPerson(sptr)) + istat.is_myclnt--; + else if (IsServer(sptr)) + istat.is_myserv--; + else if (IsService(sptr)) + istat.is_myservice--; + else + istat.is_unknown--; + + if (cptr != NULL && sptr != cptr) + sendto_one(sptr, "ERROR :Closing Link: %s %s (%s)", + get_client_name(sptr,FALSE), + cptr->name, comment); + else + sendto_one(sptr, "ERROR :Closing Link: %s (%s)", + get_client_name(sptr,FALSE), comment); + + if (sptr->auth != sptr->username) + { + istat.is_authmem -= sizeof(sptr->auth); + istat.is_auth -= 1; + MyFree(sptr->auth); + sptr->auth = sptr->username; + } + } + /* + ** Currently only server connections can have + ** depending remote clients here, but it does no + ** harm to check for all local clients. In + ** future some other clients than servers might + ** have remotes too... + ** now, I think it harms big client servers... - krys + ** + ** Close the Client connection first and mark it + ** so that no messages are attempted to send to it. + ** (The following *must* make MyConnect(sptr) == FALSE!). + ** It also makes sptr->from == NULL, thus it's unnecessary + ** to test whether "sptr != acptr" in the following loops. + */ + close_connection(sptr); + + if (IsServer(sptr)) + { + /* + ** First QUIT all NON-servers which are behind this link + ** + ** Note There is no danger of 'cptr' being exited in + ** the following loops. 'cptr' is a *local* client, + ** all dependants are *remote* clients. + */ + + /* This next bit is a a bit ugly but all it does is take the + ** name of us.. me.name and tack it together with the name of + ** the server sptr->name that just broke off and puts this + ** together into exit_one_client() to provide some useful + ** information about where the net is broken. Ian + */ + (void)strcpy(comment1, ME); + (void)strcat(comment1," "); + (void)strcat(comment1, sptr->name); + + /* This will quit all the *users*, without checking the + ** whole list of clients. + */ + for (asptr = svrtop; asptr; asptr = (aServer *)next) + { + next = (aClient *)asptr->nexts; + if ((asptr->bcptr == NULL) || + (asptr->bcptr->from != sptr + && asptr->bcptr != sptr)) + continue; + /* + ** This version doesn't need QUITs to be + ** propagaged unless the remote server is + ** hidden (by a hostmask) + */ + if (mark_blind_servers(NULL, + asptr->bcptr->name)) + flags |= FLAGS_SPLIT | FLAGS_HIDDEN; + else + flags |= FLAGS_SPLIT; + while (GotDependantClient(asptr->bcptr)) + { + acptr = asptr->bcptr->prev; + acptr->flags |= flags; + exit_one_client(NULL, acptr, &me, + comment1); + } + } + /* + ** Second SQUIT all servers behind this link + */ + for (asptr = svrtop; asptr; asptr = (aServer *)next) + { + next = (aClient *)asptr->nexts; + if ((acptr = asptr->bcptr) && + acptr->from == sptr) + { + sendto_flag(SCH_SERVER, + "Sending SQUIT %s (%s)", + acptr->name, comment); + exit_one_client(NULL, acptr, &me, ME); + } + } + } /* If (IsServer(sptr)) */ + } /* if (MyConnect(sptr) || (sptr->flags & FLAGS_HELD)) */ + + if (IsServer(sptr) && GotDependantClient(sptr)) + { + /* + ** generate QUITs locally when receiving a SQUIT + ** check for hostmasking. + */ + if (mark_blind_servers(cptr, sptr->name)) + flags = FLAGS_SPLIT | FLAGS_HIDDEN; + else + flags = FLAGS_SPLIT; + + if (IsServer(from)) + /* this is a guess */ + (void)strcpy(comment1, from->name); + else + /* this is right */ + (void)strcpy(comment1, sptr->serv->up); + (void)strcat(comment1, " "); + (void)strcat(comment1, sptr->name); + + while (GotDependantClient(sptr)) + { + acptr = sptr->prev; + acptr->flags |= flags; + exit_one_client(cptr, acptr, &me, comment1); + } + } + + /* + ** Try to guess from comment if the client is exiting + ** normally (KILL or issued QUIT), or if it is splitting + ** It requires comment for splitting users to be + ** "server.some.where splitting.some.where" + */ + comment1[0] = '\0'; + if (!IsServer(sptr) && ((sptr->flags & FLAGS_KILLED) == 0)) + { + char *c = comment; + int i = 0; + while (*c && *c != ' ') + if (*c++ == '.') + i++; + if (*c++ && i) + { + i = 0; + while (*c && *c != ' ') + if (*c++ == '.') + i++; + if (!i || *c) + sptr->flags |= FLAGS_QUIT; + } + else + sptr->flags |= FLAGS_QUIT; + + if (sptr == cptr && !(sptr->flags & FLAGS_QUIT)) + { + /* + ** This will avoid nick delay to be abused by + ** letting local users put a comment looking + ** like a server split. + */ + strncpyzt(comment1, comment, HOSTLEN + HOSTLEN); + strcat(comment1, " "); + sptr->flags |= FLAGS_QUIT; + } + } + + if (IsServer(sptr) && (cptr == sptr)) + sendto_flag(SCH_SERVER, "Sending SQUIT %s (%s)", + cptr->name, comment); + + exit_one_client(cptr, sptr, from, (*comment1) ? comment1 : comment); + return cptr == sptr ? FLUSH_BUFFER : 0; + } + +/* +** Exit one client, local or remote. Assuming all dependants have +** been already removed, and socket closed for local client. +*/ +static void exit_one_client(cptr, sptr, from, comment) +aClient *sptr; +aClient *cptr; +aClient *from; +char *comment; +{ + Reg aClient *acptr; + Reg int i; + Reg Link *lp; + + /* + ** For a server or user quitting, propagage the information to + ** other servers (except to the one where is came from (cptr)) + */ + if (IsMe(sptr)) + { + sendto_flag(SCH_ERROR, + "ERROR: tried to exit me! : %s", comment); + return; /* ...must *never* exit self!! */ + } + else if (IsServer(sptr)) { + /* + ** Old sendto_serv_but_one() call removed because we now + ** need to send different names to different servers + ** (domain name matching) + */ + istat.is_serv--; + for (i = fdas.highest; i >= 0; i--) + { + Reg aConfItem *aconf; + + if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) || + acptr == cptr || IsMe(acptr)) + continue; + if ((aconf = acptr->serv->nline) && + (match(my_name_for_link(ME, aconf->port), + sptr->name) == 0)) + continue; + sendto_one(acptr, ":%s SQUIT %s :%s", + from->name, sptr->name, comment); + } +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_SQUIT, sptr->name, sptr, + ":%s SQUIT %s :%s", from->name, + sptr->name, comment); +#endif + (void) del_from_server_hash_table(sptr->serv, cptr ? cptr : + sptr->from); + } else if (!IsPerson(sptr) && !IsService(sptr)) + /* ...this test is *dubious*, would need + ** some thougth.. but for now it plugs a + ** nasty hole in the server... --msa + */ + ; /* Nothing */ + else if (sptr->name[0] && !IsService(sptr)) /* clean with QUIT... */ + { + /* + ** If this exit is generated from "m_kill", then there + ** is no sense in sending the QUIT--KILL's have been + ** sent instead. + */ + if ((sptr->flags & FLAGS_KILLED) == 0) + { + if ((sptr->flags & FLAGS_SPLIT) == 0) + { + sendto_serv_butone(cptr, ":%s QUIT :%s", + sptr->name, comment); +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_QUIT| + SERVICE_WANT_RQUIT, + (sptr->user) ? + sptr->user->server + : NULL, cptr, + ":%s QUIT :%s", + sptr->name, comment); +#endif + } + else + { + if (sptr->flags & FLAGS_HIDDEN) + /* joys of hostmasking */ + for (i = fdas.highest; i >= 0; i--) + { + if (!(acptr =local[fdas.fd[i]]) + || !IsServer(acptr) + || acptr == cptr + || IsMe(acptr)) + continue; + if (acptr->flags &FLAGS_HIDDEN) + sendto_one(acptr, + ":%s QUIT :%s", + sptr->name, + comment); + } +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_QUIT, + (sptr->user) ? sptr->user->server + : NULL, cptr, + ":%s QUIT :%s", + sptr->name, comment); +#endif + } + } + /* + ** If a person is on a channel, send a QUIT notice + ** to every client (person) on the same channel (so + ** that the client can show the "**signoff" message). + ** (Note: The notice is to the local clients *only*) + */ + if (sptr->user) + { + if (IsInvisible(sptr)) + istat.is_user[1]--; + else + istat.is_user[0]--; + if (IsAnOper(sptr)) + istat.is_oper--; + sendto_common_channels(sptr, ":%s QUIT :%s", + sptr->name, comment); + + if (!(acptr = cptr ? cptr : sptr->from)) + acptr = sptr; + while ((lp = sptr->user->channel)) + { + /* + ** Mark channels from where remote chop left, + ** this will eventually lock the channel. + ** close_connection() has already been called, + ** it makes MyConnect == False - krys + */ + if (sptr != cptr) + if (*lp->value.chptr->chname == '!') + { + if (!(sptr->flags &FLAGS_QUIT)) + lp->value.chptr->history = timeofday + LDELAYCHASETIMELIMIT; + } + else if ( +#ifndef BETTER_CDELAY + !(sptr->flags & FLAGS_QUIT) && +#endif + is_chan_op(sptr, lp->value.chptr)) + lp->value.chptr->history = timeofday + DELAYCHASETIMELIMIT; + if (IsAnonymous(lp->value.chptr) && + !IsQuiet(lp->value.chptr)) + sendto_channel_butserv(lp->value.chptr, sptr, ":%s PART %s :None", sptr->name, lp->value.chptr->chname); + remove_user_from_channel(sptr,lp->value.chptr); + } + + /* Clean up invitefield */ + while ((lp = sptr->user->invited)) + del_invite(sptr, lp->value.chptr); + /* again, this is all that is needed */ + + /* Add user to history */ +#ifndef BETTER_NDELAY + add_history(sptr, (sptr->flags & FLAGS_QUIT) ? + &me : NULL); +#else + add_history(sptr, (sptr == cptr) ? &me : NULL); +#endif + off_history(sptr); + } + } + else if (sptr->name[0] && IsService(sptr)) + { + /* + ** If this exit is generated from "m_kill", then there + ** is no sense in sending the QUIT--KILL's have been + ** sent instead. + */ + if ((sptr->flags & FLAGS_KILLED) == 0) + { + /* + ** A service quitting is annoying, It has to be sent + ** to connected servers depending on + ** sptr->service->dist + */ + for (i = fdas.highest; i >= 0; i--) + { + if (!(acptr = local[fdas.fd[i]]) + || !IsServer(acptr) || acptr == cptr + || IsMe(acptr)) + continue; + if (match(sptr->service->dist, acptr->name)) + continue; + sendto_one(acptr, ":%s QUIT :%s", sptr->name, + comment); + } + } +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_SERVICE, NULL, NULL, + ":%s QUIT :%s", sptr->name, comment); +#endif + /* MyConnect(sptr) is always FALSE here */ + if (cptr == sptr) + sendto_flag(SCH_NOTICE, "Service %s disconnected", + get_client_name(sptr, TRUE)); + sendto_flag(SCH_SERVICE, "Received QUIT %s from %s (%s)", + sptr->name, from->name, comment); + istat.is_service--; + } + + /* Remove sptr from the client list */ + if (del_from_client_hash_table(sptr->name, sptr) != 1) + Debug((DEBUG_ERROR, "%#x !in tab %s[%s] %#x %#x %#x %d %d %#x", + sptr, sptr->name, + sptr->from ? sptr->from->sockhost : "??host", + sptr->from, sptr->next, sptr->prev, sptr->fd, + sptr->status, sptr->user)); + remove_client_from_list(sptr); + return; +} + +void checklist() +{ + Reg aClient *acptr; + Reg 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 *)&istat, sizeof(istat)); + istat.is_serv = 1; + istat.is_remc = 1; /* don't ask me why, I forgot. */ + bzero((char *)&ircst, sizeof(ircst)); +} + +void tstats(cptr, name) +aClient *cptr; +char *name; +{ + Reg aClient *acptr; + Reg int i; + Reg 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 += timeofday - 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 += timeofday - 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, RPL_STATSDEBUG, name, sp->is_ac, sp->is_ref); + sendto_one(cptr, ":%s %d %s :unknown: commands %u prefixes %u", + ME, RPL_STATSDEBUG, name, sp->is_unco, sp->is_unpf); + sendto_one(cptr, ":%s %d %s :nick collisions %u unknown closes %u", + ME, RPL_STATSDEBUG, name, sp->is_kill, sp->is_ni); + sendto_one(cptr, ":%s %d %s :wrong direction %u empty %u", + ME, RPL_STATSDEBUG, name, sp->is_wrdi, sp->is_empt); + sendto_one(cptr, ":%s %d %s :users without servers %u ghosts N/A", + ME, RPL_STATSDEBUG, name, sp->is_nosrv); + sendto_one(cptr, ":%s %d %s :numerics seen %u mode fakes %u", + ME, RPL_STATSDEBUG, name, sp->is_num, sp->is_fake); + sendto_one(cptr, ":%s %d %s :auth: successes %u fails %u", + ME, RPL_STATSDEBUG, name, sp->is_asuc, sp->is_abad); + sendto_one(cptr,":%s %d %s :local connections %u udp packets %u", + ME, RPL_STATSDEBUG, name, sp->is_loc, sp->is_udpok); + sendto_one(cptr,":%s %d %s :udp errors %u udp dropped %u", + ME, RPL_STATSDEBUG, name, sp->is_udperr, sp->is_udpdrop); + sendto_one(cptr, + ":%s %d %s :link checks %u passed %u 15s/%u 30s dropped %uSq/%uYg/%uFl", + ME, RPL_STATSDEBUG, name, sp->is_ckl, sp->is_cklq, + sp->is_cklok, sp->is_cklQ, sp->is_ckly, sp->is_cklno); + if (sp->is_wwcnt) + sendto_one(cptr, ":%s %d %s :whowas turnover %u/%u/%u [%u]", + ME, RPL_STATSDEBUG, name, sp->is_wwmt, + (u_int) (sp->is_wwt / sp->is_wwcnt), sp->is_wwMt, + KILLCHASETIMELIMIT); + if (sp->is_lkcnt) + sendto_one(cptr, ":%s %d %s :ndelay turnover %u/%u/%u [%u]", + ME, RPL_STATSDEBUG, name, sp->is_lkmt, + (u_int) (sp->is_lkt / sp->is_lkcnt), sp->is_lkMt, + DELAYCHASETIMELIMIT); + sendto_one(cptr, ":%s %d %s :abuse protections %u strict %u", ME, + RPL_STATSDEBUG, name, (bootopt & BOOT_PROT) ? 1 : 0, + (bootopt & BOOT_STRICTPROT) ? 1 : 0); + sendto_one(cptr, ":%s %d %s :Client - Server", + ME, RPL_STATSDEBUG, name); + sendto_one(cptr, ":%s %d %s :connected %u %u", + ME, RPL_STATSDEBUG, name, sp->is_cl, sp->is_sv); + sendto_one(cptr, ":%s %d %s :bytes sent %u.%uK %u.%uK", + ME, 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, 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, RPL_STATSDEBUG, name, sp->is_cti, sp->is_sti); +#if defined(USE_IAUTH) + report_iauth_stats(cptr, name); +#endif +} + +#ifdef CACHED_MOTD +aMotd *motd = NULL; +struct tm motd_tm; + +void read_motd(filename) +char *filename; +{ + int fd; + register aMotd *temp, *last; + struct stat Sb; + char line[80]; + register char *tmp; + + if ((fd = open(filename, O_RDONLY)) == -1) + return; + if (fstat(fd, &Sb) == -1) + { + close(fd); + return; + } + for(;motd != NULL;motd=last) + { + last = motd->next; + MyFree(motd->line); + MyFree((char *)motd); + } + motd_tm = *localtime(&Sb.st_mtime); + (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ + last = NULL; + while (dgets(fd, line, sizeof(line)-1) > 0) + { + if ((tmp = strchr(line, '\n')) != NULL) + *tmp = (char) 0; + if ((tmp = strchr(line, '\r')) != NULL) + *tmp = (char) 0; + temp = (aMotd *)MyMalloc(sizeof(aMotd)); + if (!temp) + outofmemory(); + temp->line = mystrdup(line); + temp->next = NULL; + if (!motd) + motd = temp; + else + last->next = temp; + last = temp; + } + (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ + close(fd); +} +#endif diff --git a/ircd/s_misc_ext.h b/ircd/s_misc_ext.h new file mode 100644 index 0000000..3c4f572 --- /dev/null +++ b/ircd/s_misc_ext.h @@ -0,0 +1,58 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_misc_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_misc.c. + */ + +/* External definitions for global variables. + */ +#ifndef S_MISC_C +extern struct stats ircst, *ircstp; +#ifdef CACHED_MOTD +extern aMotd *motd; +extern struct tm motd_tm; +#endif /* CACHED_MOTD */ +#endif /* S_MISC_C */ + +/* External definitions for global functions. + */ +#ifndef S_MISC_C +#define EXTERN extern +#else /* S_MISC_C */ +#define EXTERN +#endif /* S_MISC_C */ +EXTERN char *date __P((time_t clock)); +EXTERN int check_registered_user __P((aClient *sptr)); +EXTERN int check_registered __P((aClient *sptr)); +EXTERN int check_registered_service __P((aClient *sptr)); +EXTERN char *get_client_name __P((aClient *sptr, int showip)); +EXTERN char *get_client_host __P((aClient *cptr)); +EXTERN void get_sockhost __P((Reg aClient *cptr, Reg char *host)); +EXTERN char *my_name_for_link __P((char *name, Reg int count)); +EXTERN int mark_blind_servers __P((aClient *cptr, char *name)); +EXTERN int exit_client __P((aClient *cptr, aClient *sptr, aClient *from, + char *comment)); +EXTERN void checklist(); +EXTERN void initstats(); +EXTERN void tstats __P((aClient *cptr, char *name)); +#ifdef CACHED_MOTD +EXTERN void read_motd __P((char *filename)); +#endif /* CACHED_MOTD */ +#undef EXTERN diff --git a/ircd/s_numeric.c b/ircd/s_numeric.c new file mode 100644 index 0000000..bed99c1 --- /dev/null +++ b/ircd/s_numeric.c @@ -0,0 +1,127 @@ +/************************************************************************ + * 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 rcsid[] = "@(#)$Id: s_numeric.c,v 1.4 1998/12/12 23:48:17 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_NUMERIC_C +#include "s_externs.h" +#undef S_NUMERIC_C + +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 1; + /* 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. Don't 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) || acptr->from == cptr) + sendto_flag(SCH_NUM, + "From %s for %s: %s %d %s %s.", + get_client_name(cptr, TRUE), + acptr->name, sptr->name, + numeric, nick, buffer); + else if (IsPerson(acptr) || IsServer(acptr) || + IsService(acptr)) + sendto_prefix_one(acptr, sptr,":%s %d %s%s", + parv[0], numeric, nick, buffer); + } + /* any reason why no cptr == acptr->from checks here? -krys */ +/* because these are not used.. -Vesa + else if ((acptr = find_service(nick, (aClient *)NULL))) + 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); + } +..nuke them */ + 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 1; +} diff --git a/ircd/s_numeric_ext.h b/ircd/s_numeric_ext.h new file mode 100644 index 0000000..c17cd94 --- /dev/null +++ b/ircd/s_numeric_ext.h @@ -0,0 +1,33 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_numeric_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_numeric.c. + */ + +/* External definitions for global functions. + */ +#ifndef S_NUMERIC_C +#define EXTERN extern +#else /* S_NUMERIC_C */ +#define EXTERN +#endif /* S_NUMERIC_C */ +EXTERN int do_numeric __P((int numeric, aClient *cptr, aClient *sptr, int parc, + char *parv[])); +#undef EXTERN diff --git a/ircd/s_serv.c b/ircd/s_serv.c new file mode 100644 index 0000000..67c857d --- /dev/null +++ b/ircd/s_serv.c @@ -0,0 +1,2489 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_serv.c (formerly ircd/s_msg.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 rcsid[] = "@(#)$Id: s_serv.c,v 1.65 1999/07/02 16:49:37 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_SERV_C +#include "s_externs.h" +#undef S_SERV_C + +static char buf[BUFSIZE]; + +static int check_link __P((aClient *)); + +/* +** m_functions execute protocol messages on this server: +** +** cptr is always NON-NULL, pointing to a *LOCAL* client +** structure (with an open socket connected!). This +** identifies the physical socket where the message +** originated (or which caused the m_function to be +** executed--some m_functions may call others...). +** +** sptr is the source of the message, defined by the +** prefix part of the message if present. If not +** or prefix not found, then sptr==cptr. +** +** (!IsServer(cptr)) => (cptr == sptr), because +** prefixes are taken *only* from servers... +** +** (IsServer(cptr)) +** (sptr == cptr) => the message didn't +** have the prefix. +** +** (sptr != cptr && IsServer(sptr) means +** the prefix specified servername. (?) +** +** (sptr != cptr && !IsServer(sptr) means +** that message originated from a remote +** user (not local). +** +** combining +** +** (!IsServer(sptr)) means that, sptr can safely +** taken as defining the target structure of the +** message in this server. +** +** *Always* true (if 'parse' and others are working correct): +** +** 1) sptr->from == cptr (note: cptr->from == cptr) +** +** 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr +** *cannot* be a local connection, unless it's +** actually cptr!). [MyConnect(x) should probably +** be defined as (x == x->from) --msa ] +** +** parc number of variable parameter strings (if zero, +** parv is allowed to be NULL) +** +** parv a NULL terminated list of parameter pointers, +** +** parv[0], sender (prefix string), if not present +** this points to an empty string. +** parv[1]...parv[parc-1] +** pointers to additional parameters +** parv[parc] == NULL, *always* +** +** note: it is guaranteed that parv[0]..parv[parc-1] are all +** non-NULL pointers. +*/ + +/* +** m_version +** parv[0] = sender prefix +** parv[1] = remote server +*/ +int m_version(cptr, sptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + if (hunt_server(cptr,sptr,":%s VERSION :%s",1,parc,parv)==HUNTED_ISME) + sendto_one(sptr, rpl_str(RPL_VERSION, parv[0]), + version, debugmode, ME, serveropts); + return 2; +} + +/* +** m_squit +** parv[0] = sender prefix +** parv[1] = server name +** parv[2] = comment +*/ +int m_squit(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + Reg aConfItem *aconf; + char *server; + Reg aClient *acptr; + char *comment = (parc > 2 && parv[2]) ? parv[2] : cptr->name; + + if (parc > 1) + { + server = parv[1]; + /* + ** To accomodate host masking, a squit for a masked server + ** name is expanded if the incoming mask is the same as + ** the server name for that link to the name of link. + */ + while ((*server == '*') && IsServer(cptr)) + { + aconf = cptr->serv->nline; + if (!aconf) + break; + if (!mycmp(server, + my_name_for_link(ME, aconf->port))) + server = cptr->name; + break; /* WARNING is normal here */ + } + /* + ** The following allows wild cards in SQUIT. Only usefull + ** when the command is issued by an oper. + */ + for (acptr = client; (acptr = next_client(acptr, server)); + acptr = acptr->next) + if (IsServer(acptr) || IsMe(acptr)) + break; + if (acptr && IsMe(acptr)) + { + acptr = cptr; + server = cptr->sockhost; + } + } + else + { + /* + ** This is actually protocol error. But, well, closing + ** the link is very proper answer to that... + */ + server = cptr->name; + acptr = cptr; + } + + /* + ** SQUIT semantics is tricky, be careful... + ** + ** The old (irc2.2PL1 and earlier) code just cleans away the + ** server client from the links (because it is never true + ** "cptr == acptr". + ** + ** This logic here works the same way until "SQUIT host" hits + ** the server having the target "host" as local link. Then it + ** will do a real cleanup spewing SQUIT's and QUIT's to all + ** directions, also to the link from which the orinal SQUIT + ** came, generating one unnecessary "SQUIT host" back to that + ** link. + ** + ** One may think that this could be implemented like + ** "hunt_server" (e.g. just pass on "SQUIT" without doing + ** nothing until the server having the link as local is + ** reached). Unfortunately this wouldn't work in the real life, + ** because either target may be unreachable or may not comply + ** with the request. In either case it would leave target in + ** links--no command to clear it away. So, it's better just + ** clean out while going forward, just to be sure. + ** + ** ...of course, even better cleanout would be to QUIT/SQUIT + ** dependant users/servers already on the way out, but + ** currently there is not enough information about remote + ** clients to do this... --msa + */ + if (!acptr) + { + sendto_one(sptr, err_str(ERR_NOSUCHSERVER, parv[0]), server); + return 1; + } + if (MyConnect(sptr) && !MyConnect(acptr) && parc < 3) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS,parv[0]), "SQUIT"); + return 0; + } + if (IsLocOp(sptr) && !MyConnect(acptr)) + { + sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0])); + return 1; + } + if (!MyConnect(acptr) && (cptr != acptr->from)) + { + /* + ** The following is an awful kludge, but I don't see any other + ** way to change the pre 2.10.3 behaviour. I'm probably going + ** to regret it.. -kalt + */ + if ((acptr->from->serv->version & SV_OLDSQUIT) == 0) + { + /* better server: just propagate upstream */ + sendto_one(acptr->from, ":%s SQUIT %s :%s", parv[0], + acptr->name, comment); + sendto_flag(SCH_SERVER, + "Forwarding SQUIT %s from %s (%s)", + acptr->name, parv[0], comment); + sendto_flag(SCH_DEBUG, + "Forwarding SQUIT %s to %s from %s (%s)", + acptr->name, acptr->from->name, + parv[0], comment); + return 1; + } + /* + ** ack, bad server encountered! + ** must send back to other good servers which were trying to + ** do the right thing, and fake the yet to come SQUIT which + ** will never be received from the bad servers. + */ + if (IsServer(cptr) && + (cptr->serv->version & SV_OLDSQUIT) == 0) + { + sendto_one(cptr, ":%s SQUIT %s :%s (Bounced for %s)", + ME, acptr->name, comment, parv[0]); + sendto_flag(SCH_DEBUG, "Bouncing SQUIT %s back to %s", + acptr->name, acptr->from->name); + } + } + /* + ** Notify all opers, if my local link is remotely squitted + */ + if (MyConnect(acptr) && !IsAnOper(cptr)) + { + sendto_ops_butone(NULL, &me, + ":%s WALLOPS :Received SQUIT %s from %s (%s)", + ME, server, parv[0], comment); +#if defined(USE_SYSLOG) && defined(SYSLOG_SQUIT) + syslog(LOG_DEBUG,"SQUIT From %s : %s (%s)", + parv[0], server, comment); +#endif + } + if (MyConnect(acptr)) + { + int timeconnected = timeofday - acptr->firsttime; + sendto_flag(SCH_NOTICE, + "Closing link to %s (%d, %2d:%02d:%02d)", + get_client_name(acptr, FALSE), + timeconnected / 86400, + (timeconnected % 86400) / 3600, + (timeconnected % 3600)/60, + timeconnected % 60); + } + sendto_flag(SCH_SERVER, "Received SQUIT %s from %s (%s)", + acptr->name, parv[0], comment); + + if (MyConnect(acptr) && + IsServer(cptr) && (cptr->serv->version & SV_OLDSQUIT) == 0) + { + sendto_one(cptr, ":%s SQUIT %s :%s", ME, acptr->name, comment); + sendto_flag(SCH_DEBUG, "Issuing additionnal SQUIT %s for %s", + acptr->name, acptr->from->name); + } + return exit_client(cptr, acptr, sptr, comment); + } + +/* +** check_version +** The PASS command delivers additional information about incoming +** connection. The data is temporarily stored to info/name/username +** in m_pass() and processed here before the fields are natively used. +** Return: < 1: exit/error, > 0: no error +*/ +int check_version(cptr) +aClient *cptr; +{ + char *id, *misc = NULL, *link = NULL; + + Debug((DEBUG_INFO,"check_version: %s", cptr->info)); + + if (cptr->info == DefInfo) + { + cptr->hopcount = SV_OLD; + return 1; /* no version checked (e.g. older than 2.9) */ + } + if (id = index(cptr->info, ' ')) + { + *id++ = '\0'; + if (link = index(id, ' ')) + *link++ = '\0'; + if (misc = index(id, '|')) + *misc++ = '\0'; + else + { + misc = id; + id = ""; + } + } + else + id = ""; + + if (!strncmp(cptr->info, "021", 3)) + cptr->hopcount = SV_29|SV_NJOIN|SV_NMODE|SV_NCHAN; /* SV_2_10*/ + else if (!strncmp(cptr->info, "0209", 4)) + cptr->hopcount = SV_29|SV_OLDSQUIT; /* 2.9+ protocol */ + else + cptr->hopcount = SV_OLD; /* uhuh */ + + if (!strcmp("IRC", id) && !strncmp(cptr->info, "02100", 5) && + atoi(cptr->info+5) < 20600) + /* before 2.10.3a6 ( 2.10.3a5 is just broken ) */ + cptr->hopcount |= SV_OLDSQUIT; + + /* Check version number/mask from conf */ + sprintf(buf, "%s/%s", id, cptr->info); + if (find_two_masks(cptr->name, buf, CONF_VER)) + { + sendto_flag(SCH_ERROR, "Bad version %s %s from %s", id, + cptr->info, get_client_name(cptr, TRUE)); + return exit_client(cptr, cptr, &me, "Bad version"); + } + + if (misc) + { + sprintf(buf, "%s/%s", id, misc); + /* Check version flags from conf */ + if (find_conf_flags(cptr->name, buf, CONF_VER)) + { + sendto_flag(SCH_ERROR, "Bad flags %s (%s) from %s", + misc, id, get_client_name(cptr, TRUE)); + return exit_client(cptr, cptr, &me, "Bad flags"); + } + } + + /* right now, I can't code anything good for this */ + /* Stop whining, and do it! ;) */ + if (link && strchr(link, 'Z')) /* Compression requested */ + cptr->flags |= FLAGS_ZIPRQ; + /* + * If server was started with -p strict, be careful about the + * other server mode. + */ + if (link && strncmp(cptr->info, "020", 3) && + (bootopt & BOOT_STRICTPROT) && !strchr(link, 'P')) + return exit_client(cptr, cptr, &me, "Unsafe mode"); + + return 2; +} + +/* +** m_server +** parv[0] = sender prefix +** parv[1] = servername +** parv[2] = serverinfo/hopcount +** parv[3] = token/serverinfo (2.9) +** parv[4] = serverinfo +*/ +int m_server(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg char *ch; + Reg int i; + char info[REALLEN+1], *inpath, *host, *stok; + aClient *acptr, *bcptr; + aConfItem *aconf; + int hop = 0, token = 0; + + if (sptr->user) /* in case NICK hasn't been received yet */ + { + sendto_one(sptr, err_str(ERR_ALREADYREGISTRED, parv[0])); + return 1; + } + info[0] = info[REALLEN] = '\0'; /* strncpy() doesn't guarantee NULL */ + inpath = get_client_name(cptr, FALSE); + if (parc < 2 || *parv[1] == '\0') + { + sendto_one(cptr,"ERROR :No servername"); + return 1; + } + host = parv[1]; + if (parc > 3 && (hop = atoi(parv[2]))) + { + if (parc > 4 && (token = atoi(parv[3]))) + (void)strncpy(info, parv[4], REALLEN); + else + (void)strncpy(info, parv[3], REALLEN); + } + else if (parc > 2) + { + (void)strncpy(info, parv[2], REALLEN); + i = strlen(info); + if (parc > 3 && ((i+2) < REALLEN)) + { + (void)strncat(info, " ", REALLEN - i - 1); + (void)strncat(info, parv[3], REALLEN - i - 2); + } + } + /* + ** Check for "FRENCH " infection ;-) (actually this should + ** be replaced with routine to check the hostname syntax in + ** general). [ This check is still needed, even after the parse + ** is fixed, because someone can send "SERVER :foo bar " ]. + ** Also, changed to check other "difficult" characters, now + ** that parse lets all through... --msa + */ + if (strlen(host) > (size_t) HOSTLEN) + host[HOSTLEN] = '\0'; + for (ch = host; *ch; ch++) + if (*ch <= ' ' || *ch > '~') + break; + if (*ch || !index(host, '.')) + { + sendto_one(sptr,"ERROR :Bogus server name (%s)", host); + sendto_flag(SCH_ERROR, "Bogus server name (%s) from %s", host, + get_client_name(cptr, TRUE)); + return 2; + } + + /* *WHEN* can it be that "cptr != sptr" ????? --msa */ + /* When SERVER command (like now) has prefix. -avalon */ + + if (IsRegistered(cptr) && ((acptr = find_name(host, NULL)) + || (acptr = find_mask(host, NULL)))) + { + /* + ** This link is trying feed me a server that I already have + ** access through another path -- multiple paths not accepted + ** currently, kill this link immeatedly!! + ** + ** Rather than KILL the link which introduced it, KILL the + ** youngest of the two links. -avalon + */ + bcptr = (cptr->firsttime > acptr->from->firsttime) ? cptr : + acptr->from; + sendto_one(bcptr, "ERROR :Server %s already exists", host); + /* in both cases the bcptr (the youngest is killed) */ + if (bcptr == cptr) + { + sendto_flag(SCH_ERROR, + "Link %s cancelled, server %s already exists", + get_client_name(bcptr, TRUE), host); + return exit_client(bcptr, bcptr, &me, "Server Exists"); + } + else + { + /* + ** in this case, we are not dropping the link from + ** which we got the SERVER message. Thus we canNOT + ** `return' yet! -krys + */ + strcpy(buf, get_client_name(bcptr, TRUE)); + sendto_flag(SCH_ERROR, + "Link %s cancelled, server %s reintroduced by %s", + buf, host, get_client_name(cptr, TRUE)); + (void) exit_client(bcptr, bcptr, &me, "Server Exists"); + } + } + if ((acptr = find_person(host, NULL)) && (acptr != cptr)) + { + /* + ** Server trying to use the same name as a person. Would + ** cause a fair bit of confusion. Enough to make it hellish + ** for a while and servers to send stuff to the wrong place. + */ + sendto_one(cptr,"ERROR :Nickname %s already exists!", host); + sendto_flag(SCH_ERROR, + "Link %s cancelled: Server/nick collision on %s", + inpath, host); + sendto_serv_butone(NULL, /* all servers */ + ":%s KILL %s :%s (%s <- %s)", + ME, acptr->name, ME, + acptr->from->name, host); + acptr->flags |= FLAGS_KILLED; + (void)exit_client(NULL, acptr, &me, "Nick collision"); + return exit_client(cptr, cptr, &me, "Nick as Server"); + } + + if (IsServer(cptr)) + { + /* A server can only be introduced by another server. */ + if (!IsServer(sptr)) + { + sendto_flag(SCH_LOCAL, + "Squitting %s brought by %s (introduced by %s)", + host, get_client_name(cptr, FALSE), + sptr->name); + sendto_one(cptr, + ":%s SQUIT %s :(Introduced by %s from %s)", + me.name, host, sptr->name, + get_client_name(cptr, FALSE)); + return 1; + } + /* + ** Server is informing about a new server behind + ** this link. Create REMOTE server structure, + ** add it to list and propagate word to my other + ** server links... + */ + if (parc == 1 || info[0] == '\0') + { + sendto_one(cptr, + "ERROR :No server info specified for %s", + host); + sendto_flag(SCH_ERROR, "No server info for %s from %s", + host, get_client_name(cptr, TRUE)); + return 1; + } + + /* + ** See if the newly found server is behind a guaranteed + ** leaf (L-line). If so, close the link. + */ + if ((aconf = find_conf_host(cptr->confs, host, CONF_LEAF)) && + (!aconf->port || (hop > aconf->port))) + { + sendto_flag(SCH_ERROR, + "Leaf-only link %s->%s - Closing", + get_client_name(cptr, TRUE), + aconf->host ? aconf->host : "*"); + sendto_one(cptr, "ERROR :Leaf-only link, sorry."); + return exit_client(cptr, cptr, &me, "Leaf Only"); + } + /* + ** + */ + if (!(aconf = find_conf_host(cptr->confs, host, CONF_HUB)) || + (aconf->port && (hop > aconf->port)) ) + { + sendto_flag(SCH_ERROR, + "Non-Hub link %s introduced %s(%s).", + get_client_name(cptr, TRUE), host, + aconf ? (aconf->host ? aconf->host : "*") : + "!"); + return exit_client(cptr, cptr, &me, + "Too many servers"); + } + /* + ** See if the newly found server has a Q line for it in + ** our conf. If it does, lose the link that brought it + ** into our network. Format: + ** + ** Q:<unused>:<reason>:<servername> + ** + ** Example: Q:*:for the hell of it:eris.Berkeley.EDU + */ + if ((aconf = find_conf_name(host, CONF_QUARANTINED_SERVER))) + { + sendto_ops_butone(NULL, &me, + ":%s WALLOPS * :%s brought in %s, %s %s", + ME, get_client_name(cptr, TRUE), + host, "closing link because", + BadPtr(aconf->passwd) ? "reason unspecified" : + aconf->passwd); + + sendto_one(cptr, + "ERROR :%s is not welcome: %s. %s", + host, BadPtr(aconf->passwd) ? + "reason unspecified" : aconf->passwd, + "Go away and get a life"); + + return exit_client(cptr, cptr, &me, "Q-Lined Server"); + } + + acptr = make_client(cptr); + (void)make_server(acptr); + acptr->hopcount = hop; + strncpyzt(acptr->name, host, sizeof(acptr->name)); + if (acptr->info != DefInfo) + MyFree(acptr->info); + acptr->info = mystrdup(info); + acptr->serv->up = sptr->name; + acptr->serv->stok = token; + acptr->serv->snum = find_server_num(acptr->name); + SetServer(acptr); + istat.is_serv++; + add_client_to_list(acptr); + (void)add_to_client_hash_table(acptr->name, acptr); + (void)add_to_server_hash_table(acptr->serv, cptr); + /* + ** Old sendto_serv_but_one() call removed because we now + ** need to send different names to different servers + ** (domain name matching) + */ + for (i = fdas.highest; i >= 0; i--) + { + if (!(bcptr = local[fdas.fd[i]]) || !IsServer(bcptr) || + bcptr == cptr || IsMe(bcptr)) + continue; + if (!(aconf = bcptr->serv->nline)) + { + sendto_flag(SCH_NOTICE, + "Lost N-line for %s on %s:Closing", + get_client_name(cptr, TRUE), host); + return exit_client(cptr, cptr, &me, + "Lost N line"); + } + if (match(my_name_for_link(ME, aconf->port), + acptr->name) == 0) + continue; + stok = acptr->serv->tok; + sendto_one(bcptr, ":%s SERVER %s %d %s :%s", parv[0], + acptr->name, hop+1, stok, acptr->info); + } +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_SERVER, acptr->name, acptr, + ":%s SERVER %s %d %s :%s", parv[0], + acptr->name, hop+1, acptr->serv->tok, + acptr->info); +#endif + sendto_flag(SCH_SERVER, "Received SERVER %s from %s (%d %s)", + acptr->name, parv[0], hop+1, acptr->info); + return 0; + } + + if ((!IsUnknown(cptr) && !IsHandshake(cptr)) || + (cptr->flags & FLAGS_UNKCMD)) + return 1; + /* + ** A local link that is still in undefined state wants + ** to be a SERVER. Check if this is allowed and change + ** status accordingly... + */ + strncpyzt(cptr->name, host, sizeof(cptr->name)); + /* cptr->name has to exist before check_version(), and cptr->info + * may not be filled before check_version(). */ + if ((hop = check_version(cptr)) < 1) + return hop; /* from exit_client() */ + if (cptr->info != DefInfo) + MyFree(cptr->info); + cptr->info = mystrdup(info[0] ? info : ME); + + switch (check_server_init(cptr)) + { + case 0 : + return m_server_estab(cptr); + case 1 : + sendto_flag(SCH_NOTICE, "Checking access for %s", + get_client_name(cptr,TRUE)); + return 1; + default : + ircstp->is_ref++; + sendto_flag(SCH_NOTICE, "Unauthorized server from %s.", + get_client_host(cptr)); + return exit_client(cptr, cptr, &me, "No C/N conf lines"); + } +} + +int m_server_estab(cptr) +Reg aClient *cptr; +{ + Reg aClient *acptr; + Reg aConfItem *aconf, *bconf; + char mlname[HOSTLEN+1], *inpath, *host, *s, *encr, *stok; + int split, i; + + host = cptr->name; + inpath = get_client_name(cptr,TRUE); /* "refresh" inpath with host */ + split = mycmp(cptr->name, cptr->sockhost); + + if (!(aconf = find_conf(cptr->confs, host, CONF_NOCONNECT_SERVER))) + { + ircstp->is_ref++; + sendto_one(cptr, + "ERROR :Access denied. No N line for server %s", + inpath); + sendto_flag(SCH_ERROR, + "Access denied. No N line for server %s", inpath); + return exit_client(cptr, cptr, &me, "No N line for server"); + } + if (!(bconf = find_conf(cptr->confs, host, CONF_CONNECT_SERVER| + CONF_ZCONNECT_SERVER))) + { + ircstp->is_ref++; + sendto_one(cptr, "ERROR :Only N (no C) field for server %s", + inpath); + sendto_flag(SCH_ERROR, + "Only N (no C) field for server %s",inpath); + return exit_client(cptr, cptr, &me, "No C line for server"); + } + + if (cptr->hopcount == SV_OLD) /* lame test, should be == 0 */ + { + sendto_one(cptr, "ERROR :Server version is too old."); + sendto_flag(SCH_ERROR, "Old version for %s", inpath); + return exit_client(cptr, cptr, &me, "Old version"); + } + +#ifdef CRYPT_LINK_PASSWORD + /* use first two chars of the password they send in as salt */ + + /* passwd may be NULL. Head it off at the pass... */ + if (*cptr->passwd) + { + char salt[3]; + extern char *crypt(); + + /* Determine if MD5 or DES */ + if (strncmp(aconf->passwd, "$1$", 3)) + { + salt[0] = aconf->passwd[0]; + salt[1] = aconf->passwd[1]; + } + else + { + salt[0] = aconf->passwd[3]; + salt[1] = aconf->passwd[4]; + } + salt[2] = '\0'; + encr = crypt(cptr->passwd, salt); + } + else + encr = ""; +#else + encr = cptr->passwd; +#endif /* CRYPT_LINK_PASSWORD */ + if (*aconf->passwd && !StrEq(aconf->passwd, encr)) + { + ircstp->is_ref++; + sendto_one(cptr, "ERROR :No Access (passwd mismatch) %s", + inpath); + sendto_flag(SCH_ERROR, + "Access denied (passwd mismatch) %s", inpath); + return exit_client(cptr, cptr, &me, "Bad Password"); + } + bzero(cptr->passwd, sizeof(cptr->passwd)); + +#ifndef HUB + for (i = 0; i <= highest_fd; i++) + if (local[i] && IsServer(local[i])) + { + ircstp->is_ref++; + sendto_flag(SCH_ERROR, "I'm a leaf, cannot link %s", + get_client_name(cptr, TRUE)); + return exit_client(cptr, cptr, &me, "I'm a leaf"); + } +#endif + (void) strcpy(mlname, my_name_for_link(ME, aconf->port)); + if (IsUnknown(cptr)) + { + if (bconf->passwd[0]) +#ifndef ZIP_LINKS + sendto_one(cptr, "PASS %s %s IRC|%s %s", bconf->passwd, + pass_version, serveropts, + (bootopt & BOOT_STRICTPROT) ? "P" : ""); +#else + sendto_one(cptr, "PASS %s %s IRC|%s %s%s", + bconf->passwd, pass_version, serveropts, + (bconf->status == CONF_ZCONNECT_SERVER) ? "Z" : "", + (bootopt & BOOT_STRICTPROT) ? "P" : ""); +#endif + /* + ** Pass my info to the new server + */ + sendto_one(cptr, "SERVER %s 1 :%s", mlname, me.info); + + /* + ** If we get a connection which has been authorized to be + ** an already existing connection, remove the already + ** existing connection if it has a sendq else remove the + ** new and duplicate server. -avalon + ** Remove existing link only if it has been linked for longer + ** and has sendq higher than a threshold. -Vesa + */ + if ((acptr = find_name(host, NULL)) + || (acptr = find_mask(host, NULL))) + { + if (MyConnect(acptr) && + DBufLength(&acptr->sendQ) > CHREPLLEN && + timeofday - acptr->firsttime > TIMESEC) + (void) exit_client(acptr, acptr, &me, + "New Server"); + else + return exit_client(cptr, cptr, &me, + "Server Exists"); + } + } + else + { + s = (char *)index(aconf->host, '@'); + *s = '\0'; /* should never be NULL */ + Debug((DEBUG_INFO, "Check Usernames [%s]vs[%s]", + aconf->host, cptr->username)); + if (match(aconf->host, cptr->username)) + { + *s = '@'; + ircstp->is_ref++; + sendto_flag(SCH_ERROR, + "Username mismatch [%s]v[%s] : %s", + aconf->host, cptr->username, + get_client_name(cptr, TRUE)); + sendto_one(cptr, "ERROR :No Username Match"); + return exit_client(cptr, cptr, &me, "Bad User"); + } + *s = '@'; + } + +#ifdef ZIP_LINKS + if ((cptr->flags & FLAGS_ZIPRQ) && + (bconf->status == CONF_ZCONNECT_SERVER)) + { + if (zip_init(cptr) == -1) + { + zip_free(cptr); + sendto_flag(SCH_ERROR, + "Unable to setup compressed link for %s", + get_client_name(cptr, TRUE)); + return exit_client(cptr, cptr, &me, + "zip_init() failed"); + } + cptr->flags |= FLAGS_ZIP|FLAGS_ZIPSTART; + } +#endif + + det_confs_butmask(cptr, CONF_LEAF|CONF_HUB|CONF_NOCONNECT_SERVER); + /* + ** *WARNING* + ** In the following code in place of plain server's + ** name we send what is returned by get_client_name + ** which may add the "sockhost" after the name. It's + ** *very* *important* that there is a SPACE between + ** the name and sockhost (if present). The receiving + ** server will start the information field from this + ** first blank and thus puts the sockhost into info. + ** ...a bit tricky, but you have been warned, besides + ** code is more neat this way... --msa + */ + SetServer(cptr); + istat.is_unknown--; + istat.is_serv++; + istat.is_myserv++; + nextping = timeofday; + sendto_flag(SCH_NOTICE, "Link with %s established. (%X%s)", inpath, + cptr->hopcount, (cptr->flags & FLAGS_ZIP) ? "z" : ""); + (void)add_to_client_hash_table(cptr->name, cptr); + /* doesnt duplicate cptr->serv if allocted this struct already */ + (void)make_server(cptr); + cptr->serv->up = me.name; + cptr->serv->nline = aconf; + cptr->serv->version = cptr->hopcount; /* temporary location */ + cptr->hopcount = 1; /* local server connection */ + cptr->serv->snum = find_server_num(cptr->name); + cptr->serv->stok = 1; + cptr->flags |= FLAGS_CBURST; + (void) add_to_server_hash_table(cptr->serv, cptr); + Debug((DEBUG_NOTICE, "Server link established with %s V%X %d", + cptr->name, cptr->serv->version, cptr->serv->stok)); + add_fd(cptr->fd, &fdas); +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_SERVER, cptr->name, cptr, + ":%s SERVER %s %d %s :%s", ME, cptr->name, + cptr->hopcount+1, cptr->serv->tok, cptr->info); +#endif + sendto_flag(SCH_SERVER, "Sending SERVER %s (%d %s)", cptr->name, + 1, cptr->info); + /* + ** Old sendto_serv_but_one() call removed because we now + ** need to send different names to different servers + ** (domain name matching) Send new server to other servers. + */ + for (i = fdas.highest; i >= 0; i--) + { + if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) || + acptr == cptr || IsMe(acptr)) + continue; + if ((aconf = acptr->serv->nline) && + !match(my_name_for_link(ME, aconf->port), cptr->name)) + continue; + stok = cptr->serv->tok; + if (split) + sendto_one(acptr,":%s SERVER %s 2 %s :[%s] %s", + ME, cptr->name, stok, + cptr->sockhost, cptr->info); + else + sendto_one(acptr,":%s SERVER %s 2 %s :%s", + ME, cptr->name, stok, cptr->info); + } + /* + ** Pass on my client information to the new server + ** + ** First, pass only servers (idea is that if the link gets + ** cancelled beacause the server was already there, + ** there are no NICK's to be cancelled...). Of course, + ** if cancellation occurs, all this info is sent anyway, + ** and I guess the link dies when a read is attempted...? --msa + ** + ** Note: Link cancellation to occur at this point means + ** that at least two servers from my fragment are building + ** up connection this other fragment at the same time, it's + ** a race condition, not the normal way of operation... + ** + ** ALSO NOTE: using the get_client_name for server names-- + ** see previous *WARNING*!!! (Also, original inpath + ** is destroyed...) + */ + aconf = cptr->serv->nline; + for (acptr = &me; acptr; acptr = acptr->prev) + { + /* acptr->from == acptr for acptr == cptr */ + if ((acptr->from == cptr) || !IsServer(acptr)) + continue; + if (*mlname == '*' && match(mlname, acptr->name) == 0) + continue; + split = (MyConnect(acptr) && + mycmp(acptr->name, acptr->sockhost)); + stok = acptr->serv->tok; + if (split) + sendto_one(cptr, ":%s SERVER %s %d %s :[%s] %s", + acptr->serv->up, + acptr->name, acptr->hopcount+1, stok, + acptr->sockhost, acptr->info); + else + sendto_one(cptr, ":%s SERVER %s %d %s :%s", + acptr->serv->up, acptr->name, + acptr->hopcount+1, stok, acptr->info); + } + + for (acptr = &me; acptr; acptr = acptr->prev) + { + /* acptr->from == acptr for acptr == cptr */ + if (acptr->from == cptr) + continue; + if (IsPerson(acptr)) + { + /* + ** IsPerson(x) is true only when IsClient(x) is true. + ** These are only true when *BOTH* NICK and USER have + ** been received. -avalon + */ + if (*mlname == '*' && + match(mlname, acptr->user->server) == 0) + stok = me.serv->tok; + else + stok = acptr->user->servp->tok; + send_umode(NULL, acptr, 0, SEND_UMODES, buf); + sendto_one(cptr,"NICK %s %d %s %s %s %s :%s", + acptr->name, acptr->hopcount + 1, + acptr->user->username, + acptr->user->host, stok, + (*buf) ? buf : "+", acptr->info); + if ((cptr->serv->version & SV_NJOIN) == 0) + send_user_joins(cptr, acptr); + } + else if (IsService(acptr) && + match(acptr->service->dist, cptr->name) == 0) + { + if (*mlname == '*' && + match(mlname, acptr->service->server) == 0) + stok = me.serv->tok; + else + stok = acptr->service->servp->tok; + sendto_one(cptr, "SERVICE %s %s %s %d %d :%s", + acptr->name, stok, acptr->service->dist, + acptr->service->type, acptr->hopcount + 1, + acptr->info); + } + /* the previous if does NOT catch all services.. ! */ + } + + flush_connections(cptr->fd); + + /* + ** Last, pass all channels modes + ** only sending modes for LIVE channels. + */ + { + Reg aChannel *chptr; + for (chptr = channel; chptr; chptr = chptr->nextch) + if (chptr->users) + { + if (cptr->serv->version & SV_NJOIN) + send_channel_members(cptr, chptr); + send_channel_modes(cptr, chptr); + } + } + + cptr->flags &= ~FLAGS_CBURST; +#ifdef ZIP_LINKS + /* + ** some stats about the connect burst, + ** they are slightly incorrect because of cptr->zip->outbuf. + */ + if ((cptr->flags & FLAGS_ZIP) && cptr->zip->out->total_in) + sendto_flag(SCH_NOTICE, + "Connect burst to %s: %lu, compressed: %lu (%3.1f%%)", + get_client_name(cptr, TRUE), + cptr->zip->out->total_in,cptr->zip->out->total_out, + (float) 100*cptr->zip->out->total_out/cptr->zip->out->total_in); +#endif + return 0; +} + +int m_reconnect(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + aConfItem *aconf; + aClient *acptr = NULL; + char *name; + int i; + + if (IsRegistered(sptr)) + return exit_client(cptr, sptr, &me, "Already registered"); + + if (parc < 3) + return 1; + + name = parv[1]; + + for (i = highest_fd; i >= 0; i--) + { + if (!(acptr = local[i]) || !IsHeld(acptr) || + bcmp((char *)&acptr->ip, (char *)&cptr->ip, + sizeof(acptr->ip)) || mycmp(acptr->name, name)) + continue; + if (!(aconf = find_conf_name(name, CONF_CONNECT_SERVER| + CONF_ZCONNECT_SERVER)) || + atoi(parv[2]) != acptr->receiveM) + break; + attach_confs(acptr, name, CONF_SERVER_MASK); + acptr->flags &= ~FLAGS_HELD; + acptr->fd = cptr->fd; + cptr->fd = -2; + SetUnknown(acptr); + if (check_server(acptr, NULL, NULL, NULL, TRUE) < 0) + break; + sendto_flag(SCH_NOTICE, "%s has reconnected", + get_client_name(acptr, TRUE)); + return exit_client(cptr, sptr, &me, "Reconnected"); + } + sendto_flag(SCH_NOTICE, "Reconnect from %s failed", + get_client_name(cptr, TRUE)); + if (acptr) + (void) exit_client(cptr, acptr, &me, "Reconnect failed"); + return exit_client(cptr, sptr, &me, "Reconnect failed"); +} + +/* +** m_info +** parv[0] = sender prefix +** parv[1] = servername +*/ +int m_info(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + char **text = infotext; + + if (IsServer(cptr) && check_link(cptr)) + { + sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]), + "INFO"); + return 5; + } + if (hunt_server(cptr,sptr,":%s INFO :%s",1,parc,parv) == HUNTED_ISME) + { + while (*text) + sendto_one(sptr, rpl_str(RPL_INFO, parv[0]), *text++); + + sendto_one(sptr, rpl_str(RPL_INFO, parv[0]), ""); + sendto_one(sptr, + ":%s %d %s :Birth Date: %s, compile # %s", + ME, RPL_INFO, parv[0], creation, generation); + sendto_one(sptr, ":%s %d %s :On-line since %s", + ME, RPL_INFO, parv[0], + myctime(me.firsttime)); + sendto_one(sptr, rpl_str(RPL_ENDOFINFO, parv[0])); + return 5; + } + else + return 10; +} + +/* +** m_links +** parv[0] = sender prefix +** parv[1] = servername mask +** or +** parv[0] = sender prefix +** parv[1] = server to query +** parv[2] = servername mask +*/ +int m_links(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aServer *asptr; + char *mask; + aClient *acptr; + + if (parc > 2) + { + if (IsServer(cptr) && check_link(cptr) && !IsOper(sptr)) + { + sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]), + "LINKS"); + return 5; + } + if (hunt_server(cptr, sptr, ":%s LINKS %s :%s", 1, parc, parv) + != HUNTED_ISME) + return 5; + mask = parv[2]; + } + else + mask = parc < 2 ? NULL : parv[1]; + + for (asptr = svrtop, (void)collapse(mask); asptr; asptr = asptr->nexts) + { + acptr = asptr->bcptr; + if (!BadPtr(mask) && match(mask, acptr->name)) + continue; + sendto_one(sptr, rpl_str(RPL_LINKS, parv[0]), + acptr->name, acptr->serv->up, + acptr->hopcount, (acptr->info[0] ? acptr->info : + "(Unknown Location)")); + } + + sendto_one(sptr, rpl_str(RPL_ENDOFLINKS, parv[0]), + BadPtr(mask) ? "*" : mask); + return 2; +} + +/* +** m_summon should be redefined to ":prefix SUMMON host user" so +** that "hunt_server"-function could be used for this too!!! --msa +** As of 2.7.1e, this was the case. -avalon +** +** parv[0] = sender prefix +** parv[1] = user +** parv[2] = server +** parv[3] = channel (optional) +*/ +int m_summon(cptr, sptr, parc, parv) +aClient *sptr, *cptr; +int parc; +char *parv[]; +{ + char *host, *user, *chname; +#ifdef ENABLE_SUMMON + char hostbuf[17], namebuf[10], linebuf[10]; +# ifdef LEAST_IDLE + char linetmp[10], ttyname[15]; /* Ack */ + struct stat stb; + time_t ltime = (time_t)0; +# endif + int fd, flag = 0; +#endif + + if (parc < 2 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NORECIPIENT, parv[0]), "SUMMON"); + return 1; + } + user = parv[1]; + host = (parc < 3 || BadPtr(parv[2])) ? ME : parv[2]; + chname = (parc > 3) ? parv[3] : "*"; + /* + ** Summoning someone on remote server, find out which link to + ** use and pass the message there... + */ + parv[1] = user; + parv[2] = host; + parv[3] = chname; + parv[4] = NULL; + if (hunt_server(cptr, sptr, ":%s SUMMON %s %s %s", 2, parc, parv) == + HUNTED_ISME) + { +#ifdef ENABLE_SUMMON + if ((fd = utmp_open()) == -1) + { + sendto_one(sptr, err_str(ERR_FILEERROR, parv[0]), + "open", UTMP); + return 1; + } +# ifndef LEAST_IDLE + while ((flag = utmp_read(fd, namebuf, linebuf, hostbuf, + sizeof(hostbuf))) == 0) + if (StrEq(namebuf,user)) + break; +# else + /* use least-idle tty, not the first + * one we find in utmp. 10/9/90 Spike@world.std.com + * (loosely based on Jim Frost jimf@saber.com code) + */ + + while ((flag = utmp_read(fd, namebuf, linetmp, hostbuf, + sizeof(hostbuf))) == 0) + { + if (StrEq(namebuf,user)) + { + SPRINTF(ttyname,"/dev/%s",linetmp); + if (stat(ttyname,&stb) == -1) + { + sendto_one(sptr, + err_str(ERR_FILEERROR, + sptr->name), + "stat", ttyname); + return 1; + } + if (!ltime) + { + ltime= stb.st_mtime; + (void)strcpy(linebuf,linetmp); + } + else if (stb.st_mtime > ltime) /* less idle */ + { + ltime= stb.st_mtime; + (void)strcpy(linebuf,linetmp); + } + } + } +# endif + (void)utmp_close(fd); +# ifdef LEAST_IDLE + if (ltime == 0) +# else + if (flag == -1) +# endif + sendto_one(sptr, err_str(ERR_NOLOGIN, parv[0]), user); + else + summon(sptr, user, linebuf, chname); +#else + sendto_one(sptr, err_str(ERR_SUMMONDISABLED, parv[0])); +#endif /* ENABLE_SUMMON */ + } + else + return 3; + return 2; +} + + +/* +** m_stats +** parv[0] = sender prefix +** parv[1] = statistics selector (defaults to Message frequency) +** parv[2] = server name (current server defaulted, if omitted) +** +** Currently supported are: +** M = Message frequency (the old stat behaviour) +** L = Local Link statistics +** C = Report C and N configuration lines +*/ +/* +** m_stats/stats_conf +** Report N/C-configuration lines from this server. This could +** report other configuration lines too, but converting the +** status back to "char" is a bit akward--not worth the code +** it needs... +** +** Note: The info is reported in the order the server uses +** it--not reversed as in ircd.conf! +*/ + +static int report_array[17][3] = { + { CONF_ZCONNECT_SERVER, RPL_STATSCLINE, 'c'}, + { CONF_CONNECT_SERVER, RPL_STATSCLINE, 'C'}, + { CONF_NOCONNECT_SERVER, RPL_STATSNLINE, 'N'}, + { CONF_CLIENT, RPL_STATSILINE, 'I'}, + { CONF_RCLIENT, RPL_STATSILINE, 'i'}, + { CONF_OTHERKILL, RPL_STATSKLINE, 'k'}, + { CONF_KILL, RPL_STATSKLINE, 'K'}, + { CONF_QUARANTINED_SERVER,RPL_STATSQLINE, 'Q'}, + { CONF_LEAF, RPL_STATSLLINE, 'L'}, + { CONF_OPERATOR, RPL_STATSOLINE, 'O'}, + { CONF_HUB, RPL_STATSHLINE, 'H'}, + { CONF_LOCOP, RPL_STATSOLINE, 'o'}, + { CONF_SERVICE, RPL_STATSSLINE, 'S'}, + { CONF_VER, RPL_STATSVLINE, 'V'}, + { CONF_BOUNCE, RPL_STATSBLINE, 'B'}, + { CONF_DENY, RPL_STATSDLINE, 'D'}, + { 0, 0, 0} + }; + +static void report_configured_links(sptr, to, mask) +aClient *sptr; +char *to; +int mask; +{ + static char null[] = "<NULL>"; + aConfItem *tmp; + int *p, port; + char c, *host, *pass, *name; + + for (tmp = (mask & (CONF_KILL|CONF_OTHERKILL)) ? kconf : conf; + tmp; tmp = tmp->next) + if (tmp->status & mask) + { + for (p = &report_array[0][0]; *p; p += 3) + if (*p == tmp->status) + break; + if (!*p) + continue; + c = (char)*(p+2); + host = BadPtr(tmp->host) ? null : tmp->host; + pass = BadPtr(tmp->passwd) ? NULL : tmp->passwd; + name = BadPtr(tmp->name) ? null : tmp->name; + port = (int)tmp->port; + /* + * On K/V lines the passwd contents can be + * displayed on STATS reply. -Vesa + */ + if (tmp->status == CONF_KILL + || tmp->status == CONF_OTHERKILL + || tmp->status == CONF_VER) + sendto_one(sptr, rpl_str(p[1], to), c, host, + (pass) ? pass : null, + name, port, get_conf_class(tmp)); + else + sendto_one(sptr, rpl_str(p[1], to), c, host, + (pass) ? "*" : null, + name, port, get_conf_class(tmp)); + } + return; +} + +static void report_ping(sptr, to) +aClient *sptr; +char *to; +{ + aConfItem *tmp; + aCPing *cp; + + for (tmp = conf; tmp; tmp = tmp->next) + if ((cp = tmp->ping) && cp->lseq) + { + if (mycmp(tmp->name, tmp->host)) + SPRINTF(buf,"%s[%s]",tmp->name, tmp->host); + else + (void)strcpy(buf, tmp->name); + sendto_one(sptr, rpl_str(RPL_STATSPING, to), + buf, cp->lseq, cp->lrecvd, + cp->ping / (cp->recvd ? cp->recvd : 1), + tmp->pref); + sendto_flag(SCH_DEBUG, "%s: %d", buf, cp->seq); + } + return; +} + +int m_stats(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :%u"; + struct Message *mptr; + aClient *acptr; + char stat = parc > 1 ? parv[1][0] : '\0'; + Reg int i; + int doall = 0, wilds = 0; + char *name = NULL, *cm = NULL; + + if (IsServer(cptr) && + (stat != 'd' && stat != 'p' && stat != 'q' && stat != 's' && + stat != 'u' && stat != 'v') && + !(stat == 'o' && IsOper(sptr))) + { + if (check_link(cptr)) + { + sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]), + "STATS"); + return 5; + } + } + if (parc == 3) + { + if (hunt_server(cptr, sptr, ":%s STATS %s %s", + 2, parc, parv) != HUNTED_ISME) + return 5; + } + else if (parc == 4) + { + if (hunt_server(cptr, sptr, ":%s STATS %s %s %s", + 2, parc, parv) != HUNTED_ISME) + return 5; + } + + if (parc > 2) + { + name = parv[2]; + if (!mycmp(name, ME)) + doall = 2; + else if (match(name, ME) == 0) + doall = 1; + if (index(name, '*') || index(name, '?')) + wilds = 1; + if (parc > 3) + { + cm = parv[3]; + if (!index(cm, '*') && !index(cm, '?')) + wilds = 0, doall = 0; + } + } + else + name = ME; + + switch (stat) + { + case 'L' : case 'l' : + /* + * send info about connections which match, or all if the + * mask matches ME. Only restrictions are on those who + * are invisible not being visible to 'foreigners' who use + * a wild card based search to list it. + */ + for (i = 0; i <= highest_fd; i++) + { + if (!(acptr = local[i])) + continue; +#if 0 + if (IsPerson(acptr) && IsInvisible(acptr) && + (doall || wilds) && !(MyConnect(sptr) && + IsLocal(sptr) && IsOper(sptr)) && + !IsAnOper(acptr) && acptr != sptr) +#endif + if (IsPerson(acptr) && + (doall || wilds) && + !(MyConnect(sptr) && IsAnOper(sptr)) && + acptr != sptr) + continue; + if (!doall && wilds && match(name, acptr->name)) + continue; + if (!(doall || wilds) && + ((!cm && mycmp(name, acptr->name)) || + (cm && match(cm, acptr->name)))) + continue; + sendto_one(cptr, Lformat, ME, + RPL_STATSLINKINFO, parv[0], + get_client_name(acptr, isupper(stat)), + (int)DBufLength(&acptr->sendQ), + (int)acptr->sendM, (int)acptr->sendK, + (int)acptr->receiveM, (int)acptr->receiveK, + timeofday - acptr->firsttime); + } + break; +#if defined(USE_IAUTH) + case 'a' : case 'A' : /* iauth configuration */ + report_iauth_conf(sptr, parv[0]); + break; +#endif + case 'B' : case 'b' : /* B conf lines */ + report_configured_links(cptr, parv[0], CONF_BOUNCE); + break; + case 'c' : case 'C' : /* C and N conf lines */ + report_configured_links(cptr, parv[0], CONF_CONNECT_SERVER| + CONF_ZCONNECT_SERVER| + CONF_NOCONNECT_SERVER); + break; + case 'd' : case 'D' : /* defines */ + send_defines(cptr, parv[0]); + break; + case 'H' : case 'h' : /* H, L and D conf lines */ + report_configured_links(cptr, parv[0], + CONF_HUB|CONF_LEAF|CONF_DENY); + break; + case 'I' : case 'i' : /* I (and i) conf lines */ + report_configured_links(cptr, parv[0], + CONF_CLIENT|CONF_RCLIENT); + break; + case 'K' : case 'k' : /* K lines */ + report_configured_links(cptr, parv[0], + (CONF_KILL|CONF_OTHERKILL)); + break; + case 'M' : case 'm' : /* commands use/stats */ + for (mptr = msgtab; mptr->cmd; mptr++) + if (mptr->count) + sendto_one(cptr, rpl_str(RPL_STATSCOMMANDS, + parv[0]), mptr->cmd, + mptr->count, mptr->bytes, + mptr->rcount); + break; + case 'o' : case 'O' : /* O (and o) lines */ + report_configured_links(cptr, parv[0], CONF_OPS); + break; + case 'p' : case 'P' : /* ircd ping stats */ + report_ping(sptr, parv[0]); + break; + case 'Q' : case 'q' : /* Q lines */ + report_configured_links(cptr,parv[0],CONF_QUARANTINED_SERVER); + break; + case 'R' : case 'r' : /* usage */ + send_usage(cptr, parv[0]); + break; + case 'S' : case 's' : /* S lines */ + report_configured_links(cptr, parv[0], CONF_SERVICE); + break; + case 'T' : case 't' : /* various statistics */ + tstats(cptr, parv[0]); + break; + case 'U' : case 'u' : /* uptime */ + { + register time_t now; + + now = timeofday - me.since; + sendto_one(sptr, rpl_str(RPL_STATSUPTIME, parv[0]), + now/86400, (now/3600)%24, (now/60)%60, now%60); + break; + } + case 'V' : case 'v' : /* V conf lines */ + report_configured_links(cptr, parv[0], CONF_VER); + break; + case 'X' : case 'x' : /* lists */ +#ifdef DEBUGMODE + send_listinfo(cptr, parv[0]); +#endif + break; + case 'Y' : case 'y' : /* Y lines */ + report_classes(cptr, parv[0]); + break; + case 'Z' : /* memory use (OPER only) */ + if (MyOper(sptr)) + count_memory(cptr, parv[0], 1); + else + sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0])); + break; + case 'z' : /* memory use */ + count_memory(cptr, parv[0], 0); + break; + default : + stat = '*'; + break; + } + sendto_one(cptr, rpl_str(RPL_ENDOFSTATS, parv[0]), stat); + return 2; + } + +/* +** m_users +** parv[0] = sender prefix +** parv[1] = servername +*/ +int m_users(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ +#ifdef ENABLE_USERS + char namebuf[10],linebuf[10],hostbuf[17]; + int fd, flag = 0; +#endif + + if (hunt_server(cptr,sptr,":%s USERS :%s",1,parc,parv) == HUNTED_ISME) + { +#ifdef ENABLE_USERS + if ((fd = utmp_open()) == -1) + { + sendto_one(sptr, err_str(ERR_FILEERROR, parv[0]), + "open", UTMP); + return 1; + } + + sendto_one(sptr, rpl_str(RPL_USERSSTART, parv[0])); + while (utmp_read(fd, namebuf, linebuf, + hostbuf, sizeof(hostbuf)) == 0) + { + flag = 1; + sendto_one(sptr, rpl_str(RPL_USERS, parv[0]), + namebuf, linebuf, hostbuf); + } + if (flag == 0) + sendto_one(sptr, rpl_str(RPL_NOUSERS, parv[0])); + + sendto_one(sptr, rpl_str(RPL_ENDOFUSERS, parv[0])); + (void)utmp_close(fd); +#else + sendto_one(sptr, err_str(ERR_USERSDISABLED, parv[0])); +#endif + } + else + return 3; + return 2; +} + +/* +** Note: At least at protocol level ERROR has only one parameter, +** although this is called internally from other functions +** --msa +** +** parv[0] = sender prefix +** parv[*] = parameters +*/ +int m_error(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + Reg char *para; + + para = (parc > 1 && *parv[1] != '\0') ? parv[1] : "<>"; + + Debug((DEBUG_ERROR,"Received ERROR message from %s: %s", + sptr->name, para)); + /* + ** Ignore error messages generated by normal user clients + ** (because ill-behaving user clients would flood opers + ** screen otherwise). Pass ERROR's from other sources to + ** the local operator... + */ + if (IsPerson(cptr) || IsUnknown(cptr) || IsService(cptr)) + return 2; + if (cptr == sptr) + sendto_flag(SCH_ERROR, "from %s -- %s", + get_client_name(cptr, FALSE), para); + else + sendto_flag(SCH_ERROR, "from %s via %s -- %s", + sptr->name, get_client_name(cptr,FALSE), para); + return 2; + } + +/* +** m_help +** parv[0] = sender prefix +*/ +int m_help(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + int i; + + for (i = 0; msgtab[i].cmd; i++) + sendto_one(sptr,":%s NOTICE %s :%s", + ME, parv[0], msgtab[i].cmd); + return 2; + } + +/* + * parv[0] = sender + * parv[1] = host/server mask. + * parv[2] = server to query + */ +int m_lusers(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + int s_count = 0, /* server */ + c_count = 0, /* client (visible) */ + u_count = 0, /* unknown */ + i_count = 0, /* invisible client */ + o_count = 0, /* oparator */ + v_count = 0; /* service */ + int m_client = 0, /* my clients */ + m_server = 0, /* my server links */ + m_service = 0; /* my services */ + aClient *acptr; + + if (parc > 2) + if (hunt_server(cptr, sptr, ":%s LUSERS %s :%s", 2, parc, parv) + != HUNTED_ISME) + return 3; + + if (parc == 1 || !MyConnect(sptr)) + { + sendto_one(sptr, rpl_str(RPL_LUSERCLIENT, parv[0]), + istat.is_user[0] + istat.is_user[1], + istat.is_service, istat.is_serv); + if (istat.is_oper) + sendto_one(sptr, rpl_str(RPL_LUSEROP, parv[0]), + istat.is_oper); + if (istat.is_unknown > 0) + sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN, parv[0]), + istat.is_unknown); + if (istat.is_chan) + sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS, parv[0]), + istat.is_chan); + sendto_one(sptr, rpl_str(RPL_LUSERME, parv[0]), + istat.is_myclnt, istat.is_myservice, + istat.is_myserv); + return 2; + } + (void)collapse(parv[1]); + for (acptr = client; acptr; acptr = acptr->next) + { + if (!IsServer(acptr) && acptr->user) + { + if (match(parv[1], acptr->user->server)) + continue; + } + else + if (match(parv[1], acptr->name)) + continue; + + switch (acptr->status) + { + case STAT_SERVER: + if (MyConnect(acptr)) + m_server++; + /* flow thru */ + case STAT_ME: + s_count++; + break; + case STAT_SERVICE: + if (MyConnect(acptr)) + m_service++; + v_count++; + break; + case STAT_CLIENT: + if (IsOper(acptr)) + o_count++; +#ifdef SHOW_INVISIBLE_LUSERS + if (MyConnect(acptr)) + m_client++; + if (!IsInvisible(acptr)) + c_count++; + else + i_count++; +#else + if (MyConnect(acptr)) + { + if (IsInvisible(acptr)) + { + if (IsAnOper(sptr)) + m_client++; + } + else + m_client++; + } + if (!IsInvisible(acptr)) + c_count++; + else + i_count++; +#endif + break; + default: + u_count++; + break; + } + } +#ifndef SHOW_INVISIBLE_LUSERS + if (IsAnOper(sptr) && i_count) +#endif + sendto_one(sptr, rpl_str(RPL_LUSERCLIENT, parv[0]), + c_count + i_count, v_count, s_count); +#ifndef SHOW_INVISIBLE_LUSERS + else + sendto_one(sptr, rpl_str(RPL_LUSERCLIENT, parv[0]), + c_count, v_count, s_count); +#endif + if (o_count) + sendto_one(sptr, rpl_str(RPL_LUSEROP, parv[0]), o_count); + if (u_count > 0) + sendto_one(sptr, rpl_str(RPL_LUSERUNKNOWN, parv[0]), u_count); + if ((c_count = count_channels(sptr))>0) + sendto_one(sptr, rpl_str(RPL_LUSERCHANNELS, parv[0]), + count_channels(sptr)); + sendto_one(sptr, rpl_str(RPL_LUSERME, parv[0]), m_client, m_service, + m_server); + return 2; + } + + +/*********************************************************************** + * m_connect() - Added by Jto 11 Feb 1989 + ***********************************************************************/ + +/* +** m_connect +** parv[0] = sender prefix +** parv[1] = servername +** parv[2] = port number +** parv[3] = remote server +*/ +int m_connect(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + int port, tmpport, retval; + aConfItem *aconf; + aClient *acptr; + + if (parc > 3 && IsLocOp(sptr)) + { + sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0])); + return 1; + } + + if (hunt_server(cptr,sptr,":%s CONNECT %s %s :%s", + 3,parc,parv) != HUNTED_ISME) + return 1; + + if (parc < 3 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), + "CONNECT"); + return 0; + } + + if ((acptr = find_name(parv[1], NULL)) + || (acptr = find_mask(parv[1], NULL))) + { + sendto_one(sptr, ":%s NOTICE %s :Connect: Server %s %s %s.", + ME, parv[0], parv[1], "already exists from", + acptr->from->name); + return 0; + } + + for (aconf = conf; aconf; aconf = aconf->next) + if ((aconf->status == CONF_CONNECT_SERVER || + aconf->status == CONF_ZCONNECT_SERVER) && + match(parv[1], aconf->name) == 0) + break; + /* Checked first servernames, then try hostnames. */ + if (!aconf) + for (aconf = conf; aconf; aconf = aconf->next) + if ((aconf->status == CONF_CONNECT_SERVER || + aconf->status == CONF_ZCONNECT_SERVER) && + (match(parv[1], aconf->host) == 0 || + match(parv[1], index(aconf->host, '@')+1) == 0)) + break; + + if (!aconf) + { + sendto_one(sptr, + "NOTICE %s :Connect: Host %s not listed in irc.conf", + parv[0], parv[1]); + return 0; + } + /* + ** Get port number from user, if given. If not specified, + ** use the default form configuration structure. If missing + ** from there, then use the precompiled default. + */ + tmpport = port = aconf->port; + if ((port = atoi(parv[2])) <= 0) + { + sendto_one(sptr, "NOTICE %s :Connect: Illegal port number", + parv[0]); + return 0; + } + else if (port <= 0) + { + sendto_one(sptr, ":%s NOTICE %s :Connect: missing port number", + ME, parv[0]); + return 0; + } + /* + ** Notify all operators about remote connect requests + */ + if (!IsAnOper(cptr)) + { + sendto_ops_butone(NULL, &me, + ":%s WALLOPS :Remote CONNECT %s %s from %s", + ME, parv[1], parv[2] ? parv[2] : "", + get_client_name(sptr,FALSE)); +#if defined(USE_SYSLOG) && defined(SYSLOG_CONNECT) + syslog(LOG_DEBUG, "CONNECT From %s : %s %d", parv[0], + parv[1], parv[2] ? parv[2] : ""); +#endif + } + aconf->port = port; + switch (retval = connect_server(aconf, sptr, NULL)) + { + case 0: + sendto_one(sptr, ":%s NOTICE %s :*** Connecting to %s[%s].", + ME, parv[0], aconf->host, aconf->name); + sendto_flag(SCH_NOTICE, "Connecting to %s[%s] by %s", + aconf->host, aconf->name, + get_client_name(sptr, FALSE)); + break; + case -1: + sendto_one(sptr, ":%s NOTICE %s :*** Couldn't connect to %s.", + ME, parv[0], aconf->host); + sendto_flag(SCH_NOTICE, "Couldn't connect to %s by %s", + aconf->host, get_client_name(sptr, FALSE)); + break; + case -2: + sendto_one(sptr, ":%s NOTICE %s :*** Host %s is unknown.", + ME, parv[0], aconf->host); + sendto_flag(SCH_NOTICE, "Connect by %s to unknown host %s", + get_client_name(sptr, FALSE), aconf->host); + break; + default: + sendto_one(sptr, + ":%s NOTICE %s :*** Connection to %s failed: %s", + ME, parv[0], aconf->host, strerror(retval)); + sendto_flag(SCH_NOTICE, "Connection to %s by %s failed: %s", + aconf->host, get_client_name(sptr, FALSE), + strerror(retval)); + } + aconf->port = tmpport; + return 0; + } + +/* +** m_wallops (write to *all* opers currently online) +** parv[0] = sender prefix +** parv[1] = message text +*/ +int m_wallops(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + char *message, *pv[4]; + + message = parc > 1 ? parv[1] : NULL; + + if (BadPtr(message)) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), + "WALLOPS"); + return 1; + } + + if (!IsServer(sptr)) + { + pv[0] = parv[0]; + pv[1] = "+wallops"; + pv[2] = message; + pv[3] = NULL; + return m_private(cptr, sptr, 3, pv); + } + sendto_ops_butone(IsServer(cptr) ? cptr : NULL, sptr, + ":%s WALLOPS :%s", parv[0], message); +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_WALLOP, NULL, sptr, + ":%s WALLOP :%s", parv[0], message); +#endif + return 2; + } + +/* +** m_time +** parv[0] = sender prefix +** parv[1] = servername +*/ +int m_time(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + if (hunt_server(cptr,sptr,":%s TIME :%s",1,parc,parv) == HUNTED_ISME) + sendto_one(sptr, rpl_str(RPL_TIME, parv[0]), ME, date((long)0)); + return 2; +} + + +/* +** m_admin +** parv[0] = sender prefix +** parv[1] = servername +*/ +int m_admin(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + aConfItem *aconf; + + if (IsRegistered(cptr) && /* only local query for unregistered */ + hunt_server(cptr,sptr,":%s ADMIN :%s",1,parc,parv) != HUNTED_ISME) + return 3; + if ((aconf = find_admin()) && aconf->host && aconf->passwd + && aconf->name) + { + sendto_one(sptr, rpl_str(RPL_ADMINME, parv[0]), ME); + sendto_one(sptr, rpl_str(RPL_ADMINLOC1, parv[0]), aconf->host); + sendto_one(sptr, rpl_str(RPL_ADMINLOC2, parv[0]), + aconf->passwd); + sendto_one(sptr, rpl_str(RPL_ADMINEMAIL, parv[0]), + aconf->name); + } + else + sendto_one(sptr, err_str(ERR_NOADMININFO, parv[0]), ME); + return 2; + } + +#if defined(OPER_REHASH) || defined(LOCOP_REHASH) +/* +** m_rehash +** +*/ +int m_rehash(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + sendto_one(sptr, rpl_str(RPL_REHASHING, parv[0]), + mybasename(configfile)); + sendto_flag(SCH_NOTICE, + "%s is rehashing Server config file", parv[0]); +#ifdef USE_SYSLOG + syslog(LOG_INFO, "REHASH From %s\n", get_client_name(sptr, FALSE)); +#endif + return rehash(cptr, sptr, (parc > 1) ? ((*parv[1] == 'q')?2:0) : 0); +} +#endif + +#if defined(OPER_RESTART) || defined(LOCOP_RESTART) +/* +** m_restart +** +*/ +int m_restart(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aClient *acptr; + Reg int i; + char killer[HOSTLEN * 2 + USERLEN + 5]; + + strcpy(killer, get_client_name(sptr, TRUE)); + for (i = 0; i <= highest_fd; i++) + { + if (!(acptr = local[i])) + continue; + if (IsClient(acptr) || IsService(acptr)) + { + sendto_one(acptr, + ":%s NOTICE %s :Server Restarting. %s", + ME, acptr->name, killer); + acptr->exitc = EXITC_DIE; + if (IsClient(acptr)) + exit_client(acptr, acptr, &me, + "Server Restarting"); + /* services are kept for logging purposes */ + } + else if (IsServer(acptr)) + sendto_one(acptr, ":%s ERROR :Restarted by %s", + ME, killer); + } + flush_connections(me.fd); + + SPRINTF(buf, "RESTART by %s", get_client_name(sptr, TRUE)); + restart(buf); + /*NOT REACHED*/ + return 0; +} +#endif + +/* +** m_trace +** parv[0] = sender prefix +** parv[1] = servername +*/ +int m_trace(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg int i; + Reg aClient *acptr; + aClass *cltmp; + char *tname; + int doall, link_s[MAXCONNECTIONS], link_u[MAXCONNECTIONS]; + int wilds, dow; + + if (parc > 1) + tname = parv[1]; + else + tname = ME; + + switch (hunt_server(cptr, sptr, ":%s TRACE :%s", 1, parc, parv)) + { + case HUNTED_PASS: /* note: gets here only if parv[1] exists */ + { + aClient *ac2ptr; + + ac2ptr = next_client(client, parv[1]); + sendto_one(sptr, rpl_str(RPL_TRACELINK, parv[0]), + version, debugmode, tname, ac2ptr->from->name, + ac2ptr->from->serv->version, + (ac2ptr->from->flags & FLAGS_ZIP) ? "z" : "", + timeofday - ac2ptr->from->firsttime, + (int)DBufLength(&ac2ptr->from->sendQ), + (int)DBufLength(&sptr->from->sendQ)); + return 5; + } + case HUNTED_ISME: + break; + default: + return 1; + } + + doall = (parv[1] && (parc > 1)) ? !match(tname, ME): TRUE; + wilds = !parv[1] || index(tname, '*') || index(tname, '?'); + dow = wilds || doall; + + if (doall) { + for (i = 0; i < MAXCONNECTIONS; i++) + link_s[i] = 0, link_u[i] = 0; + for (acptr = client; acptr; acptr = acptr->next) +#ifdef SHOW_INVISIBLE_LUSERS + if (IsPerson(acptr)) + link_u[acptr->from->fd]++; +#else + if (IsPerson(acptr) && + (!IsInvisible(acptr) || IsOper(sptr))) + link_u[acptr->from->fd]++; +#endif + else if (IsServer(acptr)) + link_s[acptr->from->fd]++; + } + + /* report all direct connections */ + + for (i = 0; i <= highest_fd; i++) + { + char *name; + int class; + + if (!(acptr = local[i])) /* Local Connection? */ + continue; + if (IsPerson(acptr) && IsInvisible(acptr) && dow && + !(MyConnect(sptr) && IsAnOper(sptr)) && + !IsAnOper(acptr) && (acptr != sptr)) + continue; + if (!doall && wilds && match(tname, acptr->name)) + continue; + if (!dow && mycmp(tname, acptr->name)) + continue; + name = get_client_name(acptr,FALSE); + class = get_client_class(acptr); + + switch(acptr->status) + { + case STAT_CONNECTING: + sendto_one(sptr, rpl_str(RPL_TRACECONNECTING, + parv[0]), class, name); + break; + case STAT_HANDSHAKE: + sendto_one(sptr, rpl_str(RPL_TRACEHANDSHAKE, parv[0]), + class, name); + break; + case STAT_ME: + break; + case STAT_UNKNOWN: + if (IsAnOper(sptr) || MyClient(sptr)) + sendto_one(sptr, + rpl_str(RPL_TRACEUNKNOWN, parv[0]), + class, name); + break; + case STAT_CLIENT: + /* Only opers see users if there is a wildcard + * but anyone can see all the opers. + */ +/* + if (IsOper(sptr) && + (MyClient(sptr) || !(dow && IsInvisible(acptr))) + || !dow || IsAnOper(acptr)) + { + if (IsOper(sptr) && !(dow || IsInvisible(acptr)) || + (IsOper(sptr) && IsLocal(sptr)) || + !dow || IsAnOper(acptr)) +*/ + if (IsAnOper(acptr)) + sendto_one(sptr, + rpl_str(RPL_TRACEOPERATOR, parv[0]), + class, name); + else if (!dow || (MyConnect(sptr) && IsAnOper(sptr))) + sendto_one(sptr, + rpl_str(RPL_TRACEUSER, parv[0]), + class, name); +/* + { + if (IsAnOper(acptr)) + sendto_one(sptr, + rpl_str(RPL_TRACEOPERATOR, + parv[0]), class, name); + else + sendto_one(sptr, rpl_str(RPL_TRACEUSER, + parv[0]), class, name); + } +*/ + break; + case STAT_SERVER: + if (acptr->serv->user) + sendto_one(sptr, rpl_str(RPL_TRACESERVER, + parv[0]), class, link_s[i], + link_u[i], name, acptr->serv->by, + acptr->serv->user->username, + acptr->serv->user->host, + acptr->serv->version, + (acptr->flags & FLAGS_ZIP) ?"z":""); + else + sendto_one(sptr, rpl_str(RPL_TRACESERVER, + parv[0]), class, link_s[i], + link_u[i], name, + *(acptr->serv->by) ? + acptr->serv->by : "*", "*", ME, + acptr->serv->version, + (acptr->flags & FLAGS_ZIP) ?"z":""); break; + case STAT_RECONNECT: + sendto_one(sptr, rpl_str(RPL_TRACERECONNECT, parv[0]), + class, name); + break; + case STAT_SERVICE: + sendto_one(sptr, rpl_str(RPL_TRACESERVICE, parv[0]), + class, name, acptr->service->type, + acptr->service->wants); + break; + case STAT_LOG: + sendto_one(sptr, rpl_str(RPL_TRACELOG, parv[0]), + ME, acptr->port); + break; + default: /* ...we actually shouldn't come here... --msa */ + sendto_one(sptr, rpl_str(RPL_TRACENEWTYPE, parv[0]), + name); + break; + } + } + + /* + * Add these lines to summarize the above which can get rather long + * and messy when done remotely - Avalon + */ + if (IsPerson(sptr) && SendWallops(sptr)) + for (cltmp = FirstClass(); doall && cltmp; cltmp = NextClass(cltmp)) + if (Links(cltmp) > 0) + sendto_one(sptr, rpl_str(RPL_TRACECLASS, parv[0]), + Class(cltmp), Links(cltmp)); + sendto_one(sptr, rpl_str(RPL_TRACEEND, parv[0]), tname, version, + debugmode); + return 2; + } + +/* +** m_motd +** parv[0] = sender prefix +** parv[1] = servername +*/ +int m_motd(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ +#ifdef CACHED_MOTD + register aMotd *temp; + struct tm *tm; +#else + int fd; + char line[80]; + Reg char *tmp; + struct stat sb; + struct tm *tm; +#endif + + if (check_link(cptr)) + { + sendto_one(sptr, rpl_str(RPL_TRYAGAIN, parv[0]), "MOTD"); + return 5; + } + if (hunt_server(cptr, sptr, ":%s MOTD :%s", 1,parc,parv)!=HUNTED_ISME) + return 5; +#ifdef CACHED_MOTD + tm = &motd_tm; + if (motd == NULL) + { + sendto_one(sptr, err_str(ERR_NOMOTD, parv[0])); + return 1; + } + sendto_one(sptr, rpl_str(RPL_MOTDSTART, parv[0]), ME); + sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", ME, RPL_MOTD, + parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year, + tm->tm_hour, tm->tm_min); + temp = motd; + for(temp=motd;temp != NULL;temp = temp->next) + sendto_one(sptr, rpl_str(RPL_MOTD, parv[0]), temp->line); + sendto_one(sptr, rpl_str(RPL_ENDOFMOTD, parv[0])); + return 2; +#else + /* + * stop NFS hangs...most systems should be able to open a file in + * 3 seconds. -avalon (curtesy of wumpus) + */ + (void)alarm(3); + fd = open(IRCDMOTD_PATH, O_RDONLY); + (void)alarm(0); + if (fd == -1) + { + sendto_one(sptr, err_str(ERR_NOMOTD, parv[0])); + return 1; + } + (void)fstat(fd, &sb); + sendto_one(sptr, rpl_str(RPL_MOTDSTART, parv[0]), ME); + tm = localtime(&sb.st_mtime); + sendto_one(sptr, ":%s %d %s :- %d/%d/%d %d:%02d", ME, RPL_MOTD, + parv[0], tm->tm_mday, tm->tm_mon + 1, 1900 + tm->tm_year, + tm->tm_hour, tm->tm_min); + (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ + while (dgets(fd, line, sizeof(line)-1) > 0) + { + if ((tmp = (char *)index(line,'\n'))) + *tmp = '\0'; + if ((tmp = (char *)index(line,'\r'))) + *tmp = '\0'; + sendto_one(sptr, rpl_str(RPL_MOTD, parv[0]), line); + } + (void)dgets(-1, NULL, 0); /* make sure buffer is at empty pos */ + sendto_one(sptr, rpl_str(RPL_ENDOFMOTD, parv[0])); + (void)close(fd); + return 2; +#endif /* CACHED_MOTD */ +} + +/* +** m_close - added by Darren Reed Jul 13 1992. +*/ +int m_close(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aClient *acptr; + Reg int i; + int closed = 0; + + for (i = highest_fd; i; i--) + { + if (!(acptr = local[i])) + continue; + if (!IsUnknown(acptr) && !IsConnecting(acptr) && + !IsHandshake(acptr)) + continue; + sendto_one(sptr, rpl_str(RPL_CLOSING, parv[0]), + get_client_name(acptr, TRUE), acptr->status); + (void)exit_client(acptr, acptr, &me, "Oper Closing"); + closed++; + } + sendto_one(sptr, rpl_str(RPL_CLOSEEND, parv[0]), closed); + return 1; +} + +#if defined(OPER_DIE) || defined(LOCOP_DIE) +int m_die(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aClient *acptr; + Reg int i; + char killer[HOSTLEN * 2 + USERLEN + 5]; + + strcpy(killer, get_client_name(sptr, TRUE)); + for (i = 0; i <= highest_fd; i++) + { + if (!(acptr = local[i])) + continue; + if (IsClient(acptr) || IsService(acptr)) + { + sendto_one(acptr, + ":%s NOTICE %s :Server Terminating. %s", + ME, acptr->name, killer); + acptr->exitc = EXITC_DIE; + if (IsClient(acptr)) + exit_client(acptr, acptr, &me, "Server died"); + /* services are kept for logging purposes */ + } + else if (IsServer(acptr)) + sendto_one(acptr, ":%s ERROR :Terminated by %s", + ME, killer); + } + flush_connections(me.fd); + (void)s_die(0); + return 0; +} +#endif + +/* +** storing server names in User structures is a real waste, +** the following functions change it to only store a pointer. +** A better way might be to store in Server structure and use servp. -krys +*/ + +static char **server_name = NULL; +static int server_max = 0, server_num = 0; + +/* +** find_server_string +** +** Given an index, this will return a pointer to the corresponding +** (already allocated) string +*/ +char * +find_server_string(snum) +int snum; +{ + if (snum < server_num && snum >= 0) + return server_name[snum]; + /* request for a bogus snum value, something is wrong */ + sendto_flag(SCH_ERROR, "invalid index for server_name[] : %d (%d,%d)", + snum, server_num, server_max); + return NULL; +} + +/* +** find_server_num +** +** Given a server name, this will return the index of the corresponding +** string. This index can be used with find_server_name_from_num(). +** If the string doesn't exist already, it will be allocated. +*/ +int +find_server_num(sname) +char *sname; +{ + Reg int i = 0; + + while (i < server_num) + { + if (!strcasecmp(server_name[i], sname)) + break; + i++; + } + if (i < server_num) + return i; + if (i == server_max) + { + /* server_name[] array is full, let's make it bigger! */ + if (server_name) + server_name = (char **) MyRealloc((char *)server_name, + sizeof(char *)*(server_max+=50)); + else + server_name = (char **) MyMalloc(sizeof(char *)*(server_max=50)); + } + server_name[server_num] = mystrdup(sname); + return server_num++; +} + +/* +** check_link (added 97/12 to prevent abuse) +** routine which tries to find out how healthy a link is. +** useful to know if more strain may be imposed on the link or not. +** +** returns 0 if link load is light, -1 otherwise. +*/ +static int +check_link(cptr) +aClient *cptr; +{ + if (!IsServer(cptr)) + return 0; + if (!(bootopt & BOOT_PROT)) + return 0; + + ircstp->is_ckl++; + if ((int)DBufLength(&cptr->sendQ) > 65536) /* SendQ is already (too) high*/ + { + cptr->serv->lastload = timeofday; + ircstp->is_cklQ++; + return -1; + } + if (timeofday - cptr->firsttime < 60) /* link is too young */ + { + ircstp->is_ckly++; + return -1; + } + if (timeofday - cptr->serv->lastload > 30) + /* last request more than 30 seconds ago => OK */ + { + cptr->serv->lastload = timeofday; + ircstp->is_cklok++; + return 0; + } + if (timeofday - cptr->serv->lastload > 15 + && (int)DBufLength(&cptr->sendQ) < CHREPLLEN) + /* last request between 15 and 30 seconds ago, but little SendQ */ + { + cptr->serv->lastload = timeofday; + ircstp->is_cklq++; + return 0; + } + ircstp->is_cklno++; + return -1; +} diff --git a/ircd/s_serv_ext.h b/ircd/s_serv_ext.h new file mode 100644 index 0000000..4beb828 --- /dev/null +++ b/ircd/s_serv_ext.h @@ -0,0 +1,72 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_serv_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_serv.c. + */ + +/* External definitions for global functions. + */ +#ifndef S_SERV_C +#define EXTERN extern +#else /* S_SERV_C */ +#define EXTERN +#endif /* S_SERV_C */ +EXTERN int m_version __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_squit __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int check_version __P((aClient *cptr)); +EXTERN int m_server __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_server_estab __P((Reg aClient *cptr)); +EXTERN int m_reconnect __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_info __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_links __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_summon __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_stats __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_users __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_error __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_help __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_lusers __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_connect __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_wallops __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_time __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_admin __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_trace __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_motd __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_close __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN char *find_server_string __P((int snum)); +EXTERN int find_server_num __P((char *sname)); +#if defined(OPER_REHASH) || defined(LOCOP_REHASH) +EXTERN int m_rehash __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +#endif /* OPER_REHASH || LOCOP_REHASH */ +#if defined(OPER_RESTART) || defined(LOCOP_RESTART) +EXTERN int m_restart __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +#endif /* OPER_RESTART || LOCOP_RESTART */ +#if defined(OPER_DIE) || defined(LOCOP_DIE) +EXTERN int m_die __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +#endif /* OPER_DIE || LOCOP_DIE */ +#undef EXTERN diff --git a/ircd/s_service.c b/ircd/s_service.c new file mode 100644 index 0000000..a86bd02 --- /dev/null +++ b/ircd/s_service.c @@ -0,0 +1,708 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_service.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 rcsid[] = "@(#)$Id: s_service.c,v 1.30 1999/07/02 16:49:37 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_SERVICE_C +#include "s_externs.h" +#undef S_SERVICE_C + +aService *svctop = NULL; + +aService *make_service(cptr) +aClient *cptr; +{ + Reg aService *svc = cptr->service; + + if (svc) + return svc; + + cptr->service = svc = (aService *)MyMalloc(sizeof(*svc)); + bzero((char *)svc, sizeof(*svc)); + svc->bcptr = cptr; + if (svctop) + svctop->prevs = svc; + svc->nexts = svctop; + svc->prevs = NULL; /* useless */ + svctop = svc; + return svc; +} + + +void free_service(cptr) +aClient *cptr; +{ + Reg aService *serv; + + if ((serv = cptr->service)) + { + if (serv->nexts) + serv->nexts->prevs = serv->prevs; + if (serv->prevs) + serv->prevs->nexts = serv->nexts; + if (svctop == serv) + svctop = serv->nexts; + if (serv->servp) + free_server(serv->servp, cptr); + if (serv->server) + MyFree(serv->server); + MyFree((char *)serv); + cptr->service = NULL; + } +} + + +static aClient *best_service(name, cptr) +char *name; +aClient *cptr; +{ + Reg aClient *acptr = NULL; + Reg aClient *bcptr; + Reg aService *sp; + int len = strlen(name); + + if (!index(name, '@') || !(acptr = find_service(name, cptr))) + for (sp = svctop; sp; sp = sp->nexts) + if ((bcptr = sp->bcptr) && + !myncmp(name, bcptr->name, len)) + { + acptr = bcptr; + break; + } + return (acptr ? acptr : cptr); +} + + +#ifdef USE_SERVICES +/* +** check_services_butone +** check all local services except `cptr', and send `fmt' according to: +** action type on notice +** server origin +*/ +#if ! USE_STDARG +void check_services_butone(action, server, cptr, fmt, p1, p2, p3, p4, + p5, p6, p7, p8) +long action; +aClient *cptr; /* shouldn't this be named sptr? */ +char *fmt, *server; +void *p1, *p2, *p3, *p4, *p5, *p6, *p7, *p8; +#else +void check_services_butone(long action, char *server, aClient *cptr, char *fmt, ...) +#endif +{ + char nbuf[NICKLEN + USERLEN + HOSTLEN + 3]; + Reg aClient *acptr; + Reg int i; + + *nbuf = '\0'; + for (i = 0; i <= highest_fd; i++) + { + if (!(acptr = local[i]) || !IsService(acptr) || + (cptr && acptr == cptr->from)) + continue; + /* + ** found a (local) service, check if action matches what's + ** wanted AND if it comes from a server matching the dist + */ + if ((acptr->service->wants & action) + && (!server || !match(acptr->service->dist, server))) + if ((acptr->service->wants & SERVICE_WANT_PREFIX) && + cptr && IsRegisteredUser(cptr) && + (action & SERVICE_MASK_PREFIX)) + { +#if USE_STDARG + char buf[2048]; + va_list va; + va_start(va, fmt); + va_arg(va, char *); + vsprintf(buf, fmt+3, va); + va_end(va); +#endif + sprintf(nbuf, "%s!%s@%s", cptr->name, + cptr->user->username,cptr->user->host); + +#if ! USE_STDARG + sendto_one(acptr, fmt, nbuf, p2, p3, p4, p5, + p6, p7, p8); +#else + sendto_one(acptr, ":%s%s", nbuf, buf); +#endif + } + else + { +#if ! USE_STDARG + sendto_one(acptr, fmt, p1, p2, p3, p4, p5, + p6, p7, p8); +#else + va_list va; + va_start(va, fmt); + vsendto_one(acptr, fmt, va); + va_end(va); +#endif + } + } + return; +} + +/* +** sendnum_toone +** send the NICK + USER + UMODE for sptr to cptr according to wants +*/ +static void sendnum_toone (cptr, wants, sptr, umode) +aClient *cptr, *sptr; +char *umode; +int wants; +{ + + if (!*umode) + umode = "+"; + + if (wants & SERVICE_WANT_EXTNICK) + /* extended NICK syntax */ + sendto_one(cptr, "NICK %s %d %s %s %s %s :%s", + (wants & SERVICE_WANT_NICK) ? sptr->name : ".", + sptr->hopcount + 1, + (wants & SERVICE_WANT_USER) ? sptr->user->username + : ".", + (wants & SERVICE_WANT_USER) ? sptr->user->host :".", + (wants & SERVICE_WANT_USER) ? + ((wants & SERVICE_WANT_TOKEN) ? + sptr->user->servp->tok : sptr->user->server) : ".", + (wants & SERVICE_WANT_UMODE) ? umode : "+", + (wants & SERVICE_WANT_USER) ? sptr->info : ""); + else + /* old style NICK + USER + UMODE */ + { + char nbuf[NICKLEN + USERLEN + HOSTLEN + 3]; + char *prefix; + + if (wants & SERVICE_WANT_PREFIX) + { + sprintf(nbuf, "%s!%s@%s", sptr->name, + sptr->user->username, sptr->user->host); + prefix = nbuf; + } + else + prefix = sptr->name; + + if (wants & SERVICE_WANT_NICK) + sendto_one(cptr, "NICK %s :%d", sptr->name, + sptr->hopcount+1); + if (wants & SERVICE_WANT_USER) + sendto_one(cptr, ":%s USER %s %s %s :%s", prefix, + sptr->user->username, sptr->user->host, + (wants & SERVICE_WANT_TOKEN)? + sptr->user->servp->tok : sptr->user->server, + sptr->info); + if (wants & SERVICE_WANT_UMODE|SERVICE_WANT_OPER) + sendto_one(cptr, ":%s MODE %s %s", prefix, sptr->name, + umode); + } +} + +/* +** check_services_num +** check all local services to eventually send NICK + USER + UMODE +** for new client sptr +*/ +void check_services_num(sptr, umode) +aClient *sptr; +char *umode; +{ + Reg aClient *acptr; + Reg int i; + + for (i = 0; i <= highest_fd; i++) + { + if (!(acptr = local[i]) || !IsService(acptr)) + continue; + /* + ** found a (local) service, check if action matches what's + ** wanted AND if it comes from a server matching the dist + */ + if ((acptr->service->wants & SERVICE_MASK_NUM) + && !match(acptr->service->dist, sptr->user->server)) + sendnum_toone(acptr, acptr->service->wants, sptr, + umode); + } +} + + +aConfItem *find_conf_service(cptr, type, aconf) +aClient *cptr; +aConfItem *aconf; +int type; +{ + static char uhost[HOSTLEN+USERLEN+3]; + Reg aConfItem *tmp; + char *s; + struct hostent *hp; + int i; + + for (tmp = conf; tmp; tmp = tmp->next) + { + /* + ** Accept if the *real* hostname (usually sockethost) + ** matches host field of the configuration, the name field + ** is the same, the type match is correct and nobody else + ** is using this S-line. + */ + if (!(tmp->status & CONF_SERVICE)) + continue; + Debug((DEBUG_INFO,"service: cl=%d host (%s) name (%s) port=%d", + tmp->clients, tmp->host, tmp->name, tmp->port)); + Debug((DEBUG_INFO,"service: host (%s) name (%s) type=%d", + cptr->sockhost, cptr->name, type)); + if (tmp->clients || (type && tmp->port != type) || + mycmp(tmp->name, cptr->name)) + continue; + if ((hp = cptr->hostp)) + for (s = hp->h_name, i = 0; s; s = hp->h_aliases[i++]) + { + SPRINTF(uhost, "%s@%s", cptr->username, s); + if (match(tmp->host, uhost) == 0) + return tmp; + } + SPRINTF(uhost, "%s@%s", cptr->username, cptr->sockhost); + if (match(tmp->host, uhost) == 0) + return tmp; + } + return aconf; +} +#endif + + +/* +** m_service +** +** parv[0] = sender prefix +** parv[1] = service name +** parv[2] = server token +** parv[3] = distribution code +** parv[4] = service type +** parv[5] = hopcount +** parv[6] = info +*/ +int m_service(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aClient *acptr = NULL; + Reg aService *svc; +#ifdef USE_SERVICES + Reg aConfItem *aconf; +#endif + aServer *sp = NULL; + char *dist, *server = NULL, *info, *stok; + int type, metric = 0, i; + char *mlname; + + if (sptr->user) + { + sendto_one(sptr, err_str(ERR_ALREADYREGISTRED, parv[0])); + return 1; + } + + if (parc < 7 || *parv[1] == '\0' || *parv[2] == '\0' || + *parv[3] == '\0' || *parv[6] == '\0') + { + sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS, + BadPtr(parv[0]) ? "*" : parv[0]), "SERVICE"); + return 1; + } + + /* Copy parameters into better documenting variables */ + + /* + * Change the sender's origin. + */ + if (IsServer(cptr)) + { + sptr = make_client(cptr); + add_client_to_list(sptr); + strncpyzt(sptr->name, parv[1], sizeof(sptr->name)); + server = parv[2]; + metric = atoi(parv[5]); + sp = find_tokserver(atoi(server), cptr, NULL); + if (!sp) + { + sendto_flag(SCH_ERROR, + "ERROR: SERVICE:%s without SERVER:%s from %s", + sptr->name, server, + get_client_name(cptr, FALSE)); + return exit_client(NULL, sptr, &me, "No Such Server"); + } + if (match(parv[3], ME)) + { + sendto_flag(SCH_ERROR, + "ERROR: SERVICE:%s DIST:%s from %s", sptr->name, + parv[3], get_client_name(cptr, FALSE)); + return exit_client(NULL, sptr, &me, + "Distribution code mismatch"); + } + } +#ifndef USE_SERVICES + else + { + sendto_one(cptr, "ERROR :Server doesn't support services"); + return 1; + } +#endif + + dist = parv[3]; + type = atoi(parv[4]); + info = parv[6]; + +#ifdef USE_SERVICES + if (!IsServer(cptr)) + { + metric = 0; + server = ME; + sp = me.serv; + if (!do_nick_name(parv[1], 0)) + { + sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME, + parv[0]), parv[1]); + return 1; + } + if (strlen(parv[1]) + strlen(server) + 2 >= (size_t) HOSTLEN) + { + sendto_one(acptr, "ERROR :Servicename is too long."); + sendto_flag(SCH_ERROR, + "Access for service %d (%s) denied (%s)", + type, parv[1], "servicename too long"); + return exit_client(cptr, sptr, &me, "Name too long"); + } + + strncpyzt(sptr->name, parv[1], sizeof(sptr->name)); + if (!(aconf = find_conf_service(sptr, type, NULL))) + { + sendto_one(sptr, + "ERROR :Access denied (service %d) %s", + type, get_client_name(sptr, TRUE)); + sendto_flag(SCH_ERROR, + "Access denied (service %d) %s", type, + get_client_name(sptr, TRUE)); + return exit_client(cptr, sptr, &me, "Not enabled"); + } + + if (!BadPtr(aconf->passwd) && + !StrEq(aconf->passwd, sptr->passwd)) + { + sendto_flag(SCH_ERROR, + "Access denied: (passwd mismatch) %s", + get_client_name(sptr, TRUE)); + return exit_client(cptr, sptr, &me, "Bad Password"); + } + + (void)strcat(sptr->name, "@"), strcat(sptr->name, server); + if (find_service(sptr->name, NULL)) + { + sendto_flag(SCH_ERROR, "Service %s already exists", + get_client_name(sptr, TRUE)); + return exit_client(cptr, sptr, &me, "Service Exists"); + } + attach_conf(sptr, aconf); + sendto_one(sptr, rpl_str(RPL_YOURESERVICE, sptr->name), + sptr->name); + sendto_one(sptr, rpl_str(RPL_YOURHOST, sptr->name), + get_client_name(&me, FALSE), version); + sendto_one(sptr, rpl_str(RPL_MYINFO, sptr->name), ME, version); + sendto_flag(SCH_NOTICE, "Service %s connected", + get_client_name(sptr, TRUE)); + istat.is_unknown--; + istat.is_myservice++; + } +#endif + + istat.is_service++; + svc = make_service(sptr); + SetService(sptr); + svc->servp = sp; + sp->refcnt++; + svc->server = mystrdup(sp->bcptr->name); + strncpyzt(svc->dist, dist, HOSTLEN); + if (sptr->info != DefInfo) + MyFree(sptr->info); + if (strlen(info) > REALLEN) info[REALLEN] = '\0'; + sptr->info = mystrdup(info); + svc->wants = 0; + svc->type = type; + sptr->hopcount = metric; + reorder_client_in_list(sptr); + (void)add_to_client_hash_table(sptr->name, sptr); + +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_SERVICE, NULL, sptr, + "SERVICE %s %s %s %d %d :%s", sptr->name, + server, dist, type, metric, info); +#endif + sendto_flag(SCH_SERVICE, "Received SERVICE %s from %s (%s %d %s)", + sptr->name, get_client_name(cptr, TRUE), dist, metric, + info); + + for (i = fdas.highest; i >= 0; i--) + { + if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr) || + acptr == cptr) + continue; + if (match(dist, acptr->name)) + continue; + mlname = my_name_for_link(ME, acptr->serv->nline->port); + if (*mlname == '*' && match(mlname, sptr->service->server)== 0) + stok = me.serv->tok; + else + stok = sp->tok; + sendto_one(acptr, "SERVICE %s %s %s %d %d :%s", sptr->name, + stok, dist, type, metric+1, info); + } + return 0; +} + + +/* +** Returns list of all matching services. +** parv[1] - string to match names against +** parv[2] - type of service +*/ +int m_servlist(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aService *sp; + Reg aClient *acptr; + char *mask = BadPtr(parv[1]) ? "*" : parv[1]; + int type = 0; + + if (parc > 2) + type = BadPtr(parv[2]) ? 0 : atoi(parv[2]); + for (sp = svctop; sp; sp = sp->nexts) + if ((acptr = sp->bcptr) && (!type || type == sp->type) && + (match(mask, acptr->name) == 0)) + sendto_one(sptr, rpl_str(RPL_SERVLIST, parv[0]), + acptr->name, sp->server, sp->dist, + sp->type, acptr->hopcount, acptr->info); + sendto_one(sptr, rpl_str(RPL_SERVLISTEND, parv[0]), mask, type); + return 2; +} + + +#ifdef USE_SERVICES +/* +** m_servset +** +** parv[0] = sender prefix +** parv[1] = data requested +** parv[2] = burst requested (optional) +*/ +int m_servset(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + aClient *acptr; + int burst = 0; + + if (!MyConnect(sptr)) + { + sendto_flag(SCH_ERROR, "%s issued a SERVSET (from %s)", + sptr->name, get_client_name(cptr, TRUE)); + return 1; + } + if (!IsService(sptr) || (IsService(sptr) && sptr->service->wants)) + { + sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0])); + return 1; + } + if (parc < 2) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), + "SERVSET"); + return 1; + } + if (sptr->service->wants) + return 1; + + /* check against configuration */ + sptr->service->wants = atoi(parv[1]) & sptr->service->type; + /* check that service is global for some requests */ + if (strcmp(sptr->service->dist, "*")) + sptr->service->wants &= ~SERVICE_MASK_GLOBAL; + /* allow options */ + sptr->service->wants |= (atoi(parv[1]) & ~SERVICE_MASK_ALL); + /* send accepted SERVSET */ + sendto_one(sptr, ":%s SERVSET %s :%d", sptr->name, sptr->name, + sptr->service->wants); + + if (parc < 3 || + ((burst = sptr->service->wants & atoi(parv[2])) == 0)) + return 0; + + /* + ** services can request a connect burst. + ** it is optional, because most services should not need it, + ** so let's save some bandwidth. + ** + ** tokens are NOT used. (2.8.x like burst) + ** distribution code is respected. + ** service type also respected. + */ + /* cptr->flags |= FLAGS_CBURST; doesn't work.. */ + if (burst & SERVICE_WANT_SERVER) + { + int split; + + for (acptr = &me; acptr; acptr = acptr->prev) + { + if (!IsServer(acptr) && !IsMe(acptr)) + continue; + if (match(sptr->service->dist, acptr->name)) + continue; + split = (MyConnect(acptr) && + mycmp(acptr->name, acptr->sockhost)); + if (split) + sendto_one(sptr,":%s SERVER %s %d %s :[%s] %s", + acptr->serv->up, acptr->name, + acptr->hopcount+1, + acptr->serv->tok, + acptr->sockhost, acptr->info); + else + sendto_one(sptr, ":%s SERVER %s %d %s :%s", + acptr->serv->up, acptr->name, + acptr->hopcount+1, + acptr->serv->tok, + acptr->info); + } + } + + if (burst & (SERVICE_WANT_NICK|SERVICE_WANT_USER|SERVICE_WANT_SERVICE)) + { + char buf[BUFSIZE] = "+"; + + for (acptr = &me; acptr; acptr = acptr->prev) + { + /* acptr->from == acptr for acptr == cptr */ + if (acptr->from == cptr) + continue; + if (IsPerson(acptr)) + { + if (match(sptr->service->dist, + acptr->user->server)) + continue; + if (burst & SERVICE_WANT_UMODE) + send_umode(NULL, acptr, 0, SEND_UMODES, + buf); + else if (burst & SERVICE_WANT_OPER) + send_umode(NULL, acptr, 0, FLAGS_OPER, + buf); + sendnum_toone(sptr, burst, acptr, buf); + } + else if (IsService(acptr)) + { + if (!(burst & SERVICE_WANT_SERVICE)) + continue; + if (match(sptr->service->dist, + acptr->service->server)) + continue; + sendto_one(sptr, "SERVICE %s %s %s %d %d :%s", + acptr->name, acptr->service->server, + acptr->service->dist, + acptr->service->type, + acptr->hopcount + 1, acptr->info); + } + } + } + + if (burst & (SERVICE_WANT_CHANNEL|SERVICE_WANT_VCHANNEL|SERVICE_WANT_MODE|SERVICE_WANT_TOPIC)) + { + char modebuf[MODEBUFLEN], parabuf[MODEBUFLEN]; + aChannel *chptr; + + for (chptr = channel; chptr; chptr = chptr->nextch) + { + if (chptr->users == 0) + continue; + if (burst&(SERVICE_WANT_CHANNEL|SERVICE_WANT_VCHANNEL)) + sendto_one(sptr, "CHANNEL %s %d", + chptr->chname, chptr->users); + if (burst & SERVICE_WANT_MODE) + { + *modebuf = *parabuf = '\0'; + modebuf[1] = '\0'; + channel_modes(&me, modebuf, parabuf, chptr); + sendto_one(sptr, "MODE %s %s", chptr->chname, + modebuf); + } + if ((burst & SERVICE_WANT_TOPIC) && *chptr->topic) + sendto_one(sptr, "TOPIC %s :%s", + chptr->chname, chptr->topic); + } + } + /* cptr->flags ^= FLAGS_CBURST; */ + return 0; +} +#endif + + +/* +** Send query to service. +** parv[1] - string to match name against +** parv[2] - string to send to service +*/ +int m_squery(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + aClient *acptr; + + if (parc <= 2) + { + if (parc == 1) + sendto_one(sptr, err_str(ERR_NORECIPIENT, parv[0]), + "SQUERY"); + else if (parc == 2 || BadPtr(parv[1])) + sendto_one(sptr, err_str(ERR_NOTEXTTOSEND, parv[0])); + return 1; + } + + if ((acptr = best_service(parv[1], NULL))) + if (MyConnect(acptr) && + (acptr->service->wants & SERVICE_WANT_PREFIX)) + sendto_one(acptr, ":%s!%s@%s SQUERY %s :%s", parv[0], + sptr->user->username, sptr->user->host, + acptr->name, parv[2]); + else + sendto_one(acptr, ":%s SQUERY %s :%s", + parv[0], acptr->name, parv[2]); + else + sendto_one(sptr, err_str(ERR_NOSUCHSERVICE, parv[0]), parv[1]); + return 2; +} diff --git a/ircd/s_service_ext.h b/ircd/s_service_ext.h new file mode 100644 index 0000000..a809ff5 --- /dev/null +++ b/ircd/s_service_ext.h @@ -0,0 +1,58 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_service_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_service.c. + */ + +/* External definitions for global variables. + */ +#ifndef S_SERVICE_C +extern aService *svctop; +#endif + +/* External definitions for global functions. + */ +#ifndef S_SERVICE_C +#define EXTERN extern +#else /* S_SERVICE_C */ +#define EXTERN +#endif /* S_SERVICE_C */ +EXTERN aService *make_service __P((aClient *cptr)); +EXTERN void free_service __P((aClient *cptr)); +#ifdef USE_SERVICES +#ifndef USE_STDARG +EXTERN void check_services_butone(); +#else /* USE_STDARG */ +EXTERN void check_services_butone __P((long action, char *server, + aClient *cptr, char *fmt, ...)); +#endif /* USE_STDARG */ +EXTERN void check_services_num __P((aClient *sptr, char *umode)); +EXTERN aConfItem *find_conf_service __P((aClient *cptr, int type, + aConfItem *aconf)); +EXTERN int m_servset __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +#endif /* USE_SERVICES */ +EXTERN int m_service __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_servlist __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_squery __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +#undef EXTERN diff --git a/ircd/s_user.c b/ircd/s_user.c new file mode 100644 index 0000000..1ba4c32 --- /dev/null +++ b/ircd/s_user.c @@ -0,0 +1,2869 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_user.c (formerly ircd/s_msg.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 rcsid[] = "@(#)$Id: s_user.c,v 1.86 1999/07/17 11:47:49 q Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_USER_C +#include "s_externs.h" +#undef S_USER_C + +static char buf[BUFSIZE], buf2[BUFSIZE]; + +static int user_modes[] = { FLAGS_OPER, 'o', + FLAGS_LOCOP, 'O', + FLAGS_INVISIBLE, 'i', + FLAGS_WALLOP, 'w', + FLAGS_RESTRICTED, 'r', + FLAGS_AWAY, 'a', + 0, 0 }; + +/* +** m_functions execute protocol messages on this server: +** +** cptr is always NON-NULL, pointing to a *LOCAL* client +** structure (with an open socket connected!). This +** identifies the physical socket where the message +** originated (or which caused the m_function to be +** executed--some m_functions may call others...). +** +** sptr is the source of the message, defined by the +** prefix part of the message if present. If not +** or prefix not found, then sptr==cptr. +** +** (!IsServer(cptr)) => (cptr == sptr), because +** prefixes are taken *only* from servers... +** +** (IsServer(cptr)) +** (sptr == cptr) => the message didn't +** have the prefix. +** +** (sptr != cptr && IsServer(sptr) means +** the prefix specified servername. (?) +** +** (sptr != cptr && !IsServer(sptr) means +** that message originated from a remote +** user (not local). +** +** combining +** +** (!IsServer(sptr)) means that, sptr can safely +** taken as defining the target structure of the +** message in this server. +** +** *Always* true (if 'parse' and others are working correct): +** +** 1) sptr->from == cptr (note: cptr->from == cptr) +** +** 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr +** *cannot* be a local connection, unless it's +** actually cptr!). [MyConnect(x) should probably +** be defined as (x == x->from) --msa ] +** +** parc number of variable parameter strings (if zero, +** parv is allowed to be NULL) +** +** parv a NULL terminated list of parameter pointers, +** +** parv[0], sender (prefix string), if not present +** this points to an empty string. +** parv[1]...parv[parc-1] +** pointers to additional parameters +** parv[parc] == NULL, *always* +** +** note: it is guaranteed that parv[0]..parv[parc-1] are all +** non-NULL pointers. +*/ + +/* +** next_client +** Local function to find the next matching client. The search +** can be continued from the specified client entry. Normal +** usage loop is: +** +** for (x = client; x = next_client(x,mask); x = x->next) +** HandleMatchingClient; +** +*/ +aClient *next_client(next, ch) +Reg aClient *next; /* First client to check */ +Reg char *ch; /* search string (may include wilds) */ +{ + Reg aClient *tmp = next; + + next = find_client(ch, tmp); + if (tmp && tmp->prev == next) + return NULL; + if (next != tmp) + return next; + for ( ; next; next = next->next) + if (!match(ch,next->name) || !match(next->name,ch)) + break; + return next; +} + +/* +** hunt_server +** +** Do the basic thing in delivering the message (command) +** across the relays to the specific server (server) for +** actions. +** +** Note: The command is a format string and *MUST* be +** of prefixed style (e.g. ":%s COMMAND %s ..."). +** Command can have only max 8 parameters. +** +** server parv[server] is the parameter identifying the +** target server. +** +** *WARNING* +** parv[server] is replaced with the pointer to the +** real servername from the matched client (I'm lazy +** now --msa). +** +** returns: (see #defines) +*/ +int hunt_server(cptr, sptr, command, server, parc, parv) +aClient *cptr, *sptr; +char *command, *parv[]; +int server, parc; + { + aClient *acptr; + + /* + ** Assume it's me, if no server + */ + if (parc <= server || BadPtr(parv[server]) || + match(ME, parv[server]) == 0 || + match(parv[server], ME) == 0) + return (HUNTED_ISME); + /* + ** These are to pickup matches that would cause the following + ** message to go in the wrong direction while doing quick fast + ** non-matching lookups. + */ + if ((acptr = find_client(parv[server], NULL))) + if (acptr->from == sptr->from && !MyConnect(acptr)) + acptr = NULL; + /* Match *.masked.servers */ + if (!acptr && (acptr = find_server(parv[server], NULL))) + if (acptr->from == sptr->from && !MyConnect(acptr)) + acptr = NULL; + /* Remote services@servers */ + if (!acptr && (acptr = find_service(parv[server], NULL))) + if (acptr->from == sptr->from && !MyConnect(acptr)) + acptr = NULL; + if (!acptr) + for (acptr = client, (void)collapse(parv[server]); + (acptr = next_client(acptr, parv[server])); + acptr = acptr->next) + { + if (acptr->from == sptr->from && !MyConnect(acptr)) + continue; + /* + * Fix to prevent looping in case the parameter for + * some reason happens to match someone from the from + * link --jto + */ + if (IsRegistered(acptr) && (acptr != cptr)) + break; + } + if (acptr) + { + if (!IsRegistered(acptr)) + return HUNTED_ISME; + if (IsMe(acptr) || MyClient(acptr) || MyService(acptr)) + return HUNTED_ISME; + if (match(acptr->name, parv[server])) + parv[server] = acptr->name; + if (IsService(sptr) + && (IsServer(acptr->from) + && match(sptr->service->dist,acptr->name) != 0)) + { + sendto_one(sptr, err_str(ERR_NOSUCHSERVER, parv[0]), + parv[server]); + return(HUNTED_NOSUCH); + } + sendto_one(acptr, command, parv[0], + parv[1], parv[2], parv[3], parv[4], + parv[5], parv[6], parv[7], parv[8]); + return(HUNTED_PASS); + } + sendto_one(sptr, err_str(ERR_NOSUCHSERVER, parv[0]), parv[server]); + return(HUNTED_NOSUCH); + } + +/* +** 'do_nick_name' ensures that the given parameter (nick) is +** really a proper string for a nickname (note, the 'nick' +** may be modified in the process...) +** +** RETURNS the length of the final NICKNAME (0, if +** nickname is illegal) +** +** Nickname characters are in range +** 'A'..'}', '_', '-', '0'..'9' +** anything outside the above set will terminate nickname. +** In addition, the first character cannot be '-' +** or a Digit. +** Finally forbid the use of "anonymous" because of possible +** abuses related to anonymous channnels. -kalt +** +** Note: +** '~'-character should be allowed, but +** a change should be global, some confusion would +** result if only few servers allowed it... +*/ + +int do_nick_name(nick, server) +char *nick; +int server; +{ + Reg char *ch; + + if (*nick == '-') /* first character '-' */ + return 0; + + if (isdigit(*nick) && !server) /* first character in [0..9] */ + return 0; + + if (!strcasecmp(nick, "anonymous")) + return 0; + + for (ch = nick; *ch && (ch - nick) < NICKLEN; ch++) + if (!isvalid(*ch) || isspace(*ch)) + break; + + *ch = '\0'; + + return (ch - nick); +} + + +/* +** canonize +** +** reduce a string of duplicate list entries to contain only the unique +** items. Unavoidably O(n^2). +*/ +char *canonize(buffer) +char *buffer; +{ + static char cbuf[BUFSIZ]; + Reg char *s, *t, *cp = cbuf; + Reg int l = 0; + char *p = NULL, *p2; + + *cp = '\0'; + + for (s = strtoken(&p, buffer, ","); s; s = strtoken(&p, NULL, ",")) + { + if (l) + { + for (p2 = NULL, t = strtoken(&p2, cbuf, ","); t; + t = strtoken(&p2, NULL, ",")) + if (!mycmp(s, t)) + break; + else if (p2) + p2[-1] = ','; + } + else + t = NULL; + if (!t) + { + if (l) + *(cp-1) = ','; + else + l = 1; + (void)strcpy(cp, s); + if (p) + cp += (p - s); + } + else if (p2) + p2[-1] = ','; + } + return cbuf; +} + +/* +** ereject_user +** extracted from register_user for clarity +** early rejection of a user connection, with logging. +*/ +int +ereject_user(cptr, shortm, longm) +aClient *cptr; +char *shortm, *longm; +{ +#if defined(USE_SYSLOG) && defined(SYSLOG_CONN) + syslog(LOG_NOTICE, "%s ( %s ): <none>@%s [%s] %c\n", + myctime(cptr->firsttime), shortm, longm, + (IsUnixSocket(cptr)) ? me.sockhost : + ((cptr->hostp) ? cptr->hostp->h_name : cptr->sockhost), + cptr->auth, cptr->exitc); +#endif +#if defined(FNAME_CONNLOG) || defined(USE_SERVICES) + sendto_flog(cptr, shortm, 0, "<none>", + (IsUnixSocket(cptr)) ? me.sockhost : + ((cptr->hostp) ? cptr->hostp->h_name : cptr->sockhost)); +#endif + return exit_client(cptr, cptr, &me, longm); +} + +/* +** register_user +** This function is called when both NICK and USER messages +** have been accepted for the client, in whatever order. Only +** after this the USER message is propagated. +** +** NICK's must be propagated at once when received, although +** it would be better to delay them too until full info is +** available. Doing it is not so simple though, would have +** to implement the following: +** +** 1) user telnets in and gives only "NICK foobar" and waits +** 2) another user far away logs in normally with the nick +** "foobar" (quite legal, as this server didn't propagate +** it). +** 3) now this server gets nick "foobar" from outside, but +** has already the same defined locally. Current server +** would just issue "KILL foobar" to clean out dups. But, +** this is not fair. It should actually request another +** nick from local user or kill him/her... +*/ + +int register_user(cptr, sptr, nick, username) +aClient *cptr; +aClient *sptr; +char *nick, *username; +{ + Reg aConfItem *aconf; + aClient *acptr; + aServer *sp = NULL; + anUser *user = sptr->user; + short oldstatus = sptr->status; + char *parv[3]; +#ifndef NO_PREFIX + char prefix; +#endif + int i; + + user->last = timeofday; + parv[0] = sptr->name; + parv[1] = parv[2] = NULL; + + if (MyConnect(sptr)) + { + char *reason = NULL; + +#if defined(USE_IAUTH) + static time_t last = 0; + static u_int count = 0; + + if (iauth_options & XOPT_EARLYPARSE && DoingXAuth(cptr)) + { + cptr->flags |= FLAGS_WXAUTH; + /* fool check_pings() and give iauth more time! */ + cptr->firsttime = timeofday; + cptr->lasttime = timeofday; + strncpyzt(sptr->user->username, username, USERLEN+1); + if (sptr->passwd[0]) + sendto_iauth("%d P %s", sptr->fd,sptr->passwd); + sendto_iauth("%d U %s", sptr->fd, username); + return 1; + } + if (!DoneXAuth(sptr) && (iauth_options & XOPT_REQUIRED)) + { + char *reason; + + if (iauth_options & XOPT_NOTIMEOUT) + { + count += 1; + if (timeofday - last > 300) + { + sendto_flag(SCH_AUTH, + "iauth may not be running! (refusing new user connections)"); + last = timeofday; + } + reason = "No iauth!"; + } + else + reason = "iauth t/o"; + sptr->exitc = EXITC_AUTHFAIL; + return ereject_user(cptr, reason, + "Authentication failure!"); + } + if (timeofday - last > 300 && count) + { + sendto_flag(SCH_AUTH, "%d users rejected.", count); + count = 0; + } + + /* this should not be needed, but there's a bug.. -kalt */ + /* haven't seen any notice like this, ever.. no bug no more? */ + if (*cptr->username == '\0') + { + sendto_flag(SCH_AUTH, + "Ouch! Null username for %s (%d %X)", + get_client_name(cptr, TRUE), cptr->fd, + cptr->flags); + sendto_iauth("%d E Null username [%s] %X", cptr->fd, + get_client_name(cptr, TRUE), cptr->flags); + return exit_client(cptr, sptr, &me, + "Fatal Bug - Try Again"); + } +#endif + /* + ** the following insanity used to be after check_client() + ** but check_client()->attach_Iline() now needs to know the + ** username for global u@h limits. + ** moving this shit here shouldn't be a problem. -krys + ** what a piece of $#@!.. restricted can only be known + ** *after* attach_Iline(), so it matters and I have to move + ** come of it back below. so global u@h limits really suck. + */ +#ifndef NO_PREFIX + /* + ** ident is fun.. ahem + ** prefixes used: + ** none I line with ident + ** ^ I line with OTHER type ident + ** ~ I line, no ident + ** + i line with ident + ** = i line with OTHER type ident + ** - i line, no ident + */ + if (!(sptr->flags & FLAGS_GOTID)) + prefix = '~'; + else + if (*sptr->username == '-' || + index(sptr->username, '@')) + prefix = '^'; + else + prefix = '\0'; + + /* OTHER type idents have '-' prefix (from s_auth.c), */ + /* and they are not supposed to be used as userid (rfc1413) */ + /* @ isn't valid in usernames (m_user()) */ + if (sptr->flags & FLAGS_GOTID && *sptr->username != '-' && + index(sptr->username, '@') == NULL) + strncpyzt(buf2, sptr->username, USERLEN+1); + else /* No ident, or unusable ident string */ + /* because username may point to user->username */ + strncpyzt(buf2, username, USERLEN+1); + + if (prefix) + { + *user->username = prefix; + strncpy(&user->username[1], buf2, USERLEN); + } + else + strncpy(user->username, buf2, USERLEN+1); + user->username[USERLEN] = '\0'; + /* eos */ +#else + strncpyzt(user->username, username, USERLEN+1); +#endif + + if (sptr->exitc == EXITC_AREF || sptr->exitc == EXITC_AREFQ) + { + if (sptr->exitc == EXITC_AREF) + sendto_flag(SCH_LOCAL, + "Denied connection from %s.", + get_client_host(sptr)); + return ereject_user(cptr, " Denied ","Denied access"); + } + if ((i = check_client(sptr))) + { + struct msg_set { char *shortm; char *longm; }; + + static struct msg_set exit_msg[7] = { + { "G u@h max", "Too many user connections (global)" }, + { "G IP max", "Too many host connections (global)" }, + { "L u@h max", "Too many user connections (local)" }, + { "L IP max", "Too many host connections (local)" }, + { " max ", "Too many connections" }, + { " No Auth ", "Unauthorized connection" }, + { " Failure ", "Connect failure" } }; + + i += 7; + if (i < 0 || i > 6) /* in case.. */ + i = 6; + + ircstp->is_ref++; + sptr->exitc = EXITC_REF; + sendto_flag(SCH_LOCAL, "%s from %s.", + exit_msg[i].longm, get_client_host(sptr)); + return ereject_user(cptr, exit_msg[i].shortm, + exit_msg[i].longm); + } + +#ifndef NO_PREFIX + if (IsRestricted(sptr)) + { + if (!(sptr->flags & FLAGS_GOTID)) + prefix = '-'; + else + if (*sptr->username == '-' || + index(sptr->username, '@')) + prefix = '='; + else + prefix = '+'; + *user->username = prefix; + strncpy(&user->username[1], buf2, USERLEN); + user->username[USERLEN] = '\0'; + } +#endif + + aconf = sptr->confs->value.aconf; + if (IsUnixSocket(sptr)) + strncpyzt(user->host, me.sockhost, HOSTLEN+1); + else + strncpyzt(user->host, sptr->sockhost, HOSTLEN+1); + + if (!BadPtr(aconf->passwd) && + !StrEq(sptr->passwd, aconf->passwd)) + { + ircstp->is_ref++; + sendto_one(sptr, err_str(ERR_PASSWDMISMATCH, parv[0])); + return exit_client(cptr, sptr, &me, "Bad Password"); + } + bzero(sptr->passwd, sizeof(sptr->passwd)); + /* + * following block for the benefit of time-dependent K:-lines + */ + if (find_kill(sptr, 1, &reason)) + { + /*char buf[100];*/ + + sendto_flag(SCH_LOCAL, "K-lined %s@%s.", + user->username, sptr->sockhost); + ircstp->is_ref++; + sptr->exitc = EXITC_REF; +#if defined(USE_SYSLOG) && defined(SYSLOG_CONN) + syslog(LOG_NOTICE, "%s ( K lined ): %s@%s [%s] %c\n", + myctime(sptr->firsttime), user->username, + user->host, sptr->auth, '-'); +#endif +#if defined(FNAME_CONNLOG) || defined(USE_SERVICES) + sendto_flog(sptr, " K lined ", 0, user->username, + user->host); +#endif + if (reason) + sprintf(buf, "K-lined: %.80s", reason); + return exit_client(cptr, sptr, &me, (reason) ? buf : + "K-lined"); + } +#ifdef R_LINES + if (find_restrict(sptr)) + { + sendto_flag(SCH_LOCAL, "R-lined %s@%s.", + user->username, sptr->sockhost); + ircstp->is_ref++; + sptr->exitc = EXITC_REF; +# if defined(USE_SYSLOG) && defined(SYSLOG_CONN) + syslog(LOG_NOTICE, "%s ( R lined ): %s@%s [%s] %c\n", + myctime(sptr->firsttime), user->username, + user->host, sptr->username, '-'); +# endif +# if defined(FNAME_CONNLOG) || defined(USE_SERVICES) + sendto_flog(sptr, " R lined ", 0, user->username, + user->host); +# endif + return exit_client(cptr, sptr, &me , "R-lined"); + } +#endif + if (oldstatus == STAT_MASTER && MyConnect(sptr)) + (void)m_oper(&me, sptr, 1, parv); +/* *user->tok = '1'; + user->tok[1] = '\0';*/ + sp = user->servp; + } + else + strncpyzt(user->username, username, USERLEN+1); + SetClient(sptr); + if (MyConnect(sptr)) + { + sprintf(buf, "%s!%s@%s", nick, user->username, user->host); + sptr->exitc = EXITC_REG; + sendto_one(sptr, rpl_str(RPL_WELCOME, nick), buf); + /* This is a duplicate of the NOTICE but see below...*/ + sendto_one(sptr, rpl_str(RPL_YOURHOST, nick), + get_client_name(&me, FALSE), version); + sendto_one(sptr, rpl_str(RPL_CREATED, nick), creation); + sendto_one(sptr, rpl_str(RPL_MYINFO, parv[0]), + ME, version); + (void)m_lusers(sptr, sptr, 1, parv); + (void)m_motd(sptr, sptr, 1, parv); + nextping = timeofday; + } + else if (IsServer(cptr)) + { + acptr = find_server(user->server, NULL); + if (acptr && acptr->from != cptr) + { + sendto_one(cptr, ":%s KILL %s :%s (%s != %s[%s])", + ME, sptr->name, ME, user->server, + acptr->from->name, acptr->from->sockhost); + sptr->flags |= FLAGS_KILLED; + return exit_client(cptr, sptr, &me, + "USER server wrong direction"); + } + } + + send_umode(NULL, sptr, 0, SEND_UMODES, buf); + for (i = fdas.highest; i >= 0; i--) + { /* Find my leaf servers and feed the new client to them */ + if ((acptr = local[fdas.fd[i]]) == cptr || IsMe(acptr)) + continue; + if ((aconf = acptr->serv->nline) && + !match(my_name_for_link(ME, aconf->port), + user->server)) + sendto_one(acptr, "NICK %s %d %s %s %s %s :%s", + nick, sptr->hopcount+1, + user->username, user->host, + me.serv->tok, (*buf) ? buf : "+", + sptr->info); + else + sendto_one(acptr, "NICK %s %d %s %s %s %s :%s", + nick, sptr->hopcount+1, + user->username, user->host, + user->servp->tok, + (*buf) ? buf : "+", sptr->info); + } /* for(my-leaf-servers) */ + if (MyConnect(sptr)) + { + if (IsRestricted(sptr)) + sendto_one(sptr, err_str(ERR_RESTRICTED, nick)); + send_umode(sptr, sptr, 0, ALL_UMODES, buf); + } + + if (IsInvisible(sptr)) /* Can be initialized in m_user() */ + istat.is_user[1]++; /* Local and server defaults +i */ + else + istat.is_user[0]++; + if (MyConnect(sptr)) + { + istat.is_unknown--; + istat.is_myclnt++; + } +#ifdef USE_SERVICES +#if 0 + check_services_butone(SERVICE_WANT_NICK, user->server, NULL, + "NICK %s :%d", nick, sptr->hopcount+1); + check_services_butone(SERVICE_WANT_USER, user->server, sptr, + ":%s USER %s %s %s :%s", nick, user->username, + user->host, user->server, sptr->info); + if (MyConnect(sptr)) /* all modes about local users */ + send_umode(NULL, sptr, 0, ALL_UMODES, buf); + check_services_butone(SERVICE_WANT_UMODE, user->server, sptr, + ":%s MODE %s :%s", nick, nick, buf); +#endif + if (MyConnect(sptr)) /* all modes about local users */ + send_umode(NULL, sptr, 0, ALL_UMODES, buf); + check_services_num(sptr, buf); +#endif + return 1; + } + +/* +** m_nick +** parv[0] = sender prefix +** parv[1] = nickname +** the following are only used between servers since version 2.9 +** parv[2] = hopcount +** parv[3] = username (login name, account) +** parv[4] = client host name +** parv[5] = server token +** parv[6] = users mode +** parv[7] = users real name info +*/ +int m_nick(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + aClient *acptr; + int delayed = 0; + char nick[NICKLEN+2], *s, *user, *host; + Link *lp = NULL; + + if (IsService(sptr)) + { + sendto_one(sptr, err_str(ERR_ALREADYREGISTRED, parv[0])); + return 1; + } + + if (parc < 2) + { + sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN, parv[0])); + return 1; + } + if (MyConnect(sptr) && (s = (char *)index(parv[1], '~'))) + *s = '\0'; + strncpyzt(nick, parv[1], NICKLEN+1); + + if (parc == 8 && cptr->serv) + { + user = parv[3]; + host = parv[4]; + } + else + { + if (sptr->user) + { + user = sptr->username; + host = sptr->user->host; + } + else + user = host = ""; + } + /* + * if do_nick_name() returns a null name OR if the server sent a nick + * name and do_nick_name() changed it in some way (due to rules of nick + * creation) then reject it. If from a server and we reject it, + * and KILL it. -avalon 4/4/92 + */ + if (do_nick_name(nick, IsServer(cptr)) == 0 || + (IsServer(cptr) && strcmp(nick, parv[1]))) + { + sendto_one(sptr, err_str(ERR_ERRONEUSNICKNAME, parv[0]), + parv[1]); + + if (IsServer(cptr)) + { + ircstp->is_kill++; + sendto_flag(SCH_KILL, "Bad Nick: %s From: %s %s", + parv[1], parv[0], + get_client_name(cptr, FALSE)); + sendto_one(cptr, ":%s KILL %s :%s (%s <- %s[%s])", + ME, parv[1], ME, parv[1], + nick, cptr->name); + if (sptr != cptr) /* bad nick change */ + { + sendto_serv_butone(cptr, + ":%s KILL %s :%s (%s <- %s!%s@%s)", + ME, parv[0], ME, + get_client_name(cptr, FALSE), + parv[0], user, host); + sptr->flags |= FLAGS_KILLED; + return exit_client(cptr,sptr,&me,"BadNick"); + } + } + return 2; + } + + /* + ** Check against nick name collisions. + ** + ** Put this 'if' here so that the nesting goes nicely on the screen :) + ** We check against server name list before determining if the nickname + ** is present in the nicklist (due to the way the below for loop is + ** constructed). -avalon + */ + if ((acptr = find_server(nick, NULL))) + if (MyConnect(sptr)) + { + sendto_one(sptr, err_str(ERR_NICKNAMEINUSE, parv[0]), + nick); + return 2; /* NICK message ignored */ + } + /* + ** acptr already has result from previous find_server() + */ + if (acptr) + { + /* + ** We have a nickname trying to use the same name as + ** a server. Send out a nick collision KILL to remove + ** the nickname. As long as only a KILL is sent out, + ** there is no danger of the server being disconnected. + ** Ultimate way to jupiter a nick ? >;-). -avalon + */ + sendto_flag(SCH_KILL, + "Nick collision on %s (%s@%s)%s <- (%s@%s)%s", + sptr->name, + (acptr->user) ? acptr->user->username : "???", + (acptr->user) ? acptr->user->host : "???", + acptr->from->name, user, host, + get_client_name(cptr, FALSE)); + ircstp->is_kill++; + sendto_one(cptr, ":%s KILL %s :%s (%s <- %s)", + ME, sptr->name, ME, acptr->from->name, + /* NOTE: Cannot use get_client_name + ** twice here, it returns static + ** string pointer--the other info + ** would be lost + */ + get_client_name(cptr, FALSE)); + sptr->flags |= FLAGS_KILLED; + return exit_client(cptr, sptr, &me, "Nick/Server collision"); + } + if (!(acptr = find_client(nick, NULL))) + { + aClient *acptr2; + + if (IsServer(cptr) || !(bootopt & BOOT_PROT)) + goto nickkilldone; + if ((acptr2 = get_history(nick, (long)(KILLCHASETIMELIMIT))) && + !MyConnect(acptr2)) + /* + ** Lock nick for KCTL so one cannot nick collide + ** (due to kill chase) people who recently changed + ** their nicks. --Beeth + */ + delayed = 1; + else + /* + ** Let ND work + */ + delayed = find_history(nick, (long)(DELAYCHASETIMELIMIT)); + if (!delayed) + goto nickkilldone; /* No collisions, all clear... */ + } + /* + ** If acptr == sptr, then we have a client doing a nick + ** change between *equivalent* nicknames as far as server + ** is concerned (user is changing the case of his/her + ** nickname or somesuch) + */ + if (acptr == sptr) + if (strcmp(acptr->name, nick) != 0) + /* + ** Allows change of case in his/her nick + */ + goto nickkilldone; /* -- go and process change */ + else + /* + ** This is just ':old NICK old' type thing. + ** Just forget the whole thing here. There is + ** no point forwarding it to anywhere, + ** especially since servers prior to this + ** version would treat it as nick collision. + */ + return 2; /* NICK Message ignored */ + /* + ** Note: From this point forward it can be assumed that + ** acptr != sptr (point to different client structures). + */ + /* + ** If the older one is "non-person", the new entry is just + ** allowed to overwrite it. Just silently drop non-person, + ** and proceed with the nick. This should take care of the + ** "dormant nick" way of generating collisions... + */ + if (acptr && IsUnknown(acptr) && MyConnect(acptr)) + { + (void) exit_client(acptr, acptr, &me, "Overridden"); + goto nickkilldone; + } + /* + ** Decide, we really have a nick collision and deal with it + */ + if (!IsServer(cptr)) + { + /* + ** NICK is coming from local client connection. Just + ** send error reply and ignore the command. + */ + sendto_one(sptr, err_str((delayed) ? ERR_UNAVAILRESOURCE + : ERR_NICKNAMEINUSE, + parv[0]), nick); + return 2; /* NICK message ignored */ + } + /* + ** NICK was coming from a server connection. Means that the same + ** nick is registered for different users by different server. + ** This is either a race condition (two users coming online about + ** same time, or net reconnecting) or just two net fragments becoming + ** joined and having same nicks in use. We cannot have TWO users with + ** same nick--purge this NICK from the system with a KILL... >;) + ** + ** The client indicated by 'acptr' is dead meat, give at least some + ** indication of the reason why we are just dropping it cold. + */ + sendto_one(acptr, err_str(ERR_NICKCOLLISION, acptr->name), + acptr->name, user, host); + /* + ** This seemingly obscure test (sptr == cptr) differentiates + ** between "NICK new" (TRUE) and ":old NICK new" (FALSE) forms. + */ + if (sptr == cptr) + { + sendto_flag(SCH_KILL, + "Nick collision on %s (%s@%s)%s <- (%s@%s)%s", + acptr->name, + (acptr->user) ? acptr->user->username : "???", + (acptr->user) ? acptr->user->host : "???", + acptr->from->name, + user, host, get_client_name(cptr, FALSE)); + /* + ** A new NICK being introduced by a neighbouring + ** server (e.g. message type "NICK new" received) + */ + ircstp->is_kill++; + sendto_serv_butone(NULL, + ":%s KILL %s :%s ((%s@%s)%s <- (%s@%s)%s)", + ME, acptr->name, ME, + (acptr->user) ? acptr->user->username:"???", + (acptr->user) ? acptr->user->host : "???", + acptr->from->name, user, host, + /* NOTE: Cannot use get_client_name twice + ** here, it returns static string pointer: + ** the other info would be lost + */ + get_client_name(cptr, FALSE)); + acptr->flags |= FLAGS_KILLED; + return exit_client(NULL, acptr, &me, "Nick collision"); + } + /* + ** A NICK change has collided (e.g. message type + ** ":old NICK new". This requires more complex cleanout. + ** Both clients must be purged from this server, the "new" + ** must be killed from the incoming connection, and "old" must + ** be purged from all outgoing connections. + */ + sendto_flag(SCH_KILL, "Nick change collision %s!%s@%s to %s %s <- %s", + sptr->name, user, host, acptr->name, acptr->from->name, + get_client_name(cptr, FALSE)); + ircstp->is_kill++; + sendto_serv_butone(NULL, /* KILL old from outgoing servers */ + ":%s KILL %s :%s (%s(%s) <- %s)", + ME, sptr->name, ME, acptr->from->name, + acptr->name, get_client_name(cptr, FALSE)); + ircstp->is_kill++; + sendto_serv_butone(NULL, /* Kill new from incoming link */ + ":%s KILL %s :%s (%s <- %s(%s))", + ME, acptr->name, ME, acptr->from->name, + get_client_name(cptr, FALSE), sptr->name); + acptr->flags |= FLAGS_KILLED; + (void)exit_client(NULL, acptr, &me, "Nick collision(new)"); + sptr->flags |= FLAGS_KILLED; + return exit_client(cptr, sptr, &me, "Nick collision(old)"); + +nickkilldone: + if (IsServer(sptr)) + { + char *pv[7]; + + if (parc != 8) + { + sendto_flag(SCH_NOTICE, + "Bad NICK param count (%d) for %s from %s via %s", + parc, parv[1], sptr->name, + get_client_name(cptr, FALSE)); + sendto_one(cptr, ":%s KILL %s :%s (Bad NICK %d)", + ME, nick, ME, parc); + return 0; + } + /* A server introducing a new client, change source */ + sptr = make_client(cptr); + add_client_to_list(sptr); + if (parc > 2) + sptr->hopcount = atoi(parv[2]); + (void)strcpy(sptr->name, nick); + + pv[0] = sptr->name; + pv[1] = parv[3]; + pv[2] = parv[4]; + pv[3] = parv[5]; + pv[4] = parv[7]; + pv[5] = parv[6]; + pv[6] = NULL; + (void)add_to_client_hash_table(nick, sptr); + return m_user(cptr, sptr, 6, pv); + } + else if (sptr->name[0]) /* NICK received before, changing */ + { + if (MyConnect(sptr)) + { + if (!IsPerson(sptr)) /* Unregistered client */ + return 2; /* Ignore new NICKs */ + if (IsRestricted(sptr)) + { + sendto_one(sptr, + err_str(ERR_RESTRICTED, nick)); + return 2; + } + /* is the user banned on any channel ? */ + for (lp = sptr->user->channel; lp; lp = lp->next) + if (can_send(sptr, lp->value.chptr) ==MODE_BAN) + break; + } + /* + ** Client just changing his/her nick. If he/she is + ** on a channel, send note of change to all clients + ** on that channel. Propagate notice to other servers. + */ + sendto_common_channels(sptr, ":%s NICK :%s", parv[0], nick); + if (sptr->user) /* should always be true.. */ + { + add_history(sptr, sptr); +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_NICK, + sptr->user->server, sptr, + ":%s NICK :%s", parv[0], nick); +#endif + } + else + sendto_flag(SCH_NOTICE, + "Illegal NICK change: %s -> %s from %s", + parv[0], nick, get_client_name(cptr,TRUE)); + sendto_serv_butone(cptr, ":%s NICK :%s", parv[0], nick); + if (sptr->name[0]) + (void)del_from_client_hash_table(sptr->name, sptr); + (void)strcpy(sptr->name, nick); + } + else + { + /* Client setting NICK the first time */ + + /* This had to be copied here to avoid problems.. */ + (void)strcpy(sptr->name, nick); + if (sptr->user) + /* + ** USER already received, now we have NICK. + ** *NOTE* For servers "NICK" *must* precede the + ** user message (giving USER before NICK is possible + ** only for local client connection!). register_user + ** may reject the client and call exit_client for it + ** --must test this and exit m_nick too!!! + */ + if (register_user(cptr, sptr, nick, + sptr->user->username) + == FLUSH_BUFFER) + return FLUSH_BUFFER; + } + /* + ** Finally set new nick name. + */ + (void)add_to_client_hash_table(nick, sptr); + if (lp) + return 15; + else + return 3; +} + +/* +** m_message (used in m_private() and m_notice()) +** the general function to deliver MSG's between users/channels +** +** parv[0] = sender prefix +** parv[1] = receiver list +** parv[2] = message text +** +** massive cleanup +** rev argv 6/91 +** +*/ + +static int m_message(cptr, sptr, parc, parv, notice) +aClient *cptr, *sptr; +char *parv[]; +int parc, notice; +{ + Reg aClient *acptr; + Reg char *s; + aChannel *chptr; + char *nick, *server, *p, *cmd, *user, *host; + int count = 0, penalty = 0; + + cmd = notice ? MSG_NOTICE : MSG_PRIVATE; + + if (parc < 2 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NORECIPIENT, parv[0]), cmd); + return 1; + } + + if (parc < 3 || *parv[2] == '\0') + { + sendto_one(sptr, err_str(ERR_NOTEXTTOSEND, parv[0])); + return 1; + } + + if (MyConnect(sptr)) + parv[1] = canonize(parv[1]); + for (p = NULL, nick = strtoken(&p, parv[1], ","); nick; + nick = strtoken(&p, NULL, ","), penalty++) + { + /* + ** restrict destination list to MAXPENALTY/2 recipients to + ** solve SPAM problem --Yegg + */ + if (2*penalty >= MAXPENALTY) { + if (!notice) + sendto_one(sptr, err_str(ERR_TOOMANYTARGETS, + parv[0]), + "Too many",nick,"No Message Delivered"); + continue; + } + /* + ** nickname addressed? + */ + if ((acptr = find_person(nick, NULL))) + { + if (!notice && MyConnect(sptr) && + acptr->user && (acptr->user->flags & FLAGS_AWAY)) + sendto_one(sptr, rpl_str(RPL_AWAY, parv[0]), + acptr->name, + (acptr->user->away) ? + acptr->user->away : "Gone"); + sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", + parv[0], cmd, nick, parv[2]); + continue; + } + /* + ** channel msg? + */ + if ((IsPerson(sptr) || IsService(sptr) || IsServer(sptr)) && + (chptr = find_channel(nick, NullChn))) + { + if (can_send(sptr, chptr) == 0 || IsServer(sptr)) + sendto_channel_butone(cptr, sptr, chptr, + ":%s %s %s :%s", + parv[0], cmd, nick, + parv[2]); + else if (!notice) + sendto_one(sptr, err_str(ERR_CANNOTSENDTOCHAN, + parv[0]), nick); + continue; + } + + /* + ** the following two cases allow masks in NOTICEs + ** (for OPERs only) + ** + ** Armin, 8Jun90 (gruner@informatik.tu-muenchen.de) + */ + if ((*nick == '$' || *nick == '#') && IsAnOper(sptr)) + { + if (!(s = (char *)rindex(nick, '.'))) + { + sendto_one(sptr, err_str(ERR_NOTOPLEVEL, + parv[0]), nick); + continue; + } + while (*++s) + if (*s == '.' || *s == '*' || *s == '?') + break; + if (*s == '*' || *s == '?') + { + sendto_one(sptr, err_str(ERR_WILDTOPLEVEL, + parv[0]), nick); + continue; + } + sendto_match_butone(IsServer(cptr) ? cptr : NULL, + sptr, nick + 1, + (*nick == '#') ? MATCH_HOST : + MATCH_SERVER, + ":%s %s %s :%s", parv[0], + cmd, nick, parv[2]); + continue; + } + + /* + ** nick!user@host addressed? + */ + if ((user = (char *)index(nick, '!')) && + (host = (char *)index(nick, '@'))) + { + *user = '\0'; + *host = '\0'; + if ((acptr = find_person(nick, NULL)) && + !mycmp(user+1, acptr->user->username) && + !mycmp(host+1, acptr->user->host)) + { + sendto_prefix_one(acptr, sptr, ":%s %s %s :%s", + parv[0], cmd, nick, parv[2]); + *user = '!'; + *host = '@'; + continue; + } + *user = '!'; + *host = '@'; + } + + /* + ** user[%host]@server addressed? + */ + if ((server = (char *)index(nick, '@')) && + (acptr = find_server(server + 1, NULL))) + { + /* + ** Not destined for a user on me :-( + */ + if (!IsMe(acptr)) + { + sendto_one(acptr,":%s %s %s :%s", parv[0], + cmd, nick, parv[2]); + continue; + } + *server = '\0'; + + if ((host = (char *)index(nick, '%'))) + *host++ = '\0'; + + /* + ** Look for users which match the destination host + ** (no host == wildcard) and if one and one only is + ** found connected to me, deliver message! + */ + acptr = find_userhost(nick, host, NULL, &count); + if (server) + *server = '@'; + if (host) + *--host = '%'; + if (acptr) + { + if (count == 1) + sendto_prefix_one(acptr, sptr, + ":%s %s %s :%s", + parv[0], cmd, + nick, parv[2]); + else if (!notice) + sendto_one(sptr, err_str( + ERR_TOOMANYTARGETS, + parv[0]), "Duplicate", nick, + "No Message Delivered"); + continue; + } + } + else if ((host = (char *)index(nick, '%'))) + { + /* + ** user%host addressed? + */ + *host++ = '\0'; + acptr = find_userhost(nick, host, NULL, &count); + *--host = '%'; + if (acptr) + { + if (count == 1) + sendto_prefix_one(acptr, sptr, + ":%s %s %s :%s", + parv[0], cmd, + nick, parv[2]); + else if (!notice) + sendto_one(sptr, err_str( + ERR_TOOMANYTARGETS, + parv[0]), "Duplicate", nick, + "No Message Delivered"); + continue; + } + } + if (!notice) + sendto_one(sptr, err_str(ERR_NOSUCHNICK, parv[0]), + nick); + } + return penalty; +} + +/* +** m_private +** parv[0] = sender prefix +** parv[1] = receiver list +** parv[2] = message text +*/ + +int m_private(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + return m_message(cptr, sptr, parc, parv, 0); +} + +/* +** m_notice +** parv[0] = sender prefix +** parv[1] = receiver list +** parv[2] = notice text +*/ + +int m_notice(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + return m_message(cptr, sptr, parc, parv, 1); +} + +/* +** who_one +** sends one RPL_WHOREPLY to sptr concerning acptr & repchan +*/ +static void who_one(sptr, acptr, repchan, lp) +aClient *sptr, *acptr; +aChannel *repchan; +Link *lp; +{ + char status[5]; + int i = 0; + + if (acptr->user->flags & FLAGS_AWAY) + status[i++] = 'G'; + else + status[i++] = 'H'; + if (IsAnOper(acptr)) + status[i++] = '*'; + if ((repchan != NULL) && (lp == NULL)) + lp = find_user_link(repchan->members, acptr); + if (lp != NULL) + { + if (lp->flags & CHFL_CHANOP) + status[i++] = '@'; + else if (lp->flags & CHFL_VOICE) + status[i++] = '+'; + } + status[i] = '\0'; + sendto_one(sptr, rpl_str(RPL_WHOREPLY, sptr->name), + (repchan) ? (repchan->chname) : "*", acptr->user->username, + acptr->user->host, acptr->user->server, acptr->name, + status, acptr->hopcount, acptr->info); +} + + +/* +** who_channel +** lists all users on a given channel +*/ +static void who_channel(sptr, chptr, oper) +aClient *sptr; +aChannel *chptr; +int oper; +{ + Reg Link *lp; + int member; + + if (!IsAnonymous(chptr)) + { + member = IsMember(sptr, chptr); + if (member || !SecretChannel(chptr)) + for (lp = chptr->members; lp; lp = lp->next) + { + if (oper && !IsAnOper(lp->value.cptr)) + continue; + if (IsInvisible(lp->value.cptr) && !member) + continue; + who_one(sptr, lp->value.cptr, chptr, lp); + } + } + else if (lp = find_user_link(chptr->members, sptr)) + who_one(sptr, lp->value.cptr, chptr, lp); +} + +/* +** who_find +** lists all (matching) users. +** CPU intensive, but what can be done? +*/ +static void who_find(sptr, mask, oper) +aClient *sptr; +char *mask; +int oper; +{ + aChannel *chptr, *ch2ptr; + Link *lp; + int member; + int showperson, isinvis; + aClient *acptr; + + for (acptr = client; acptr; acptr = acptr->next) + { + ch2ptr = NULL; + + if (!IsPerson(acptr)) + continue; + if (oper && !IsAnOper(acptr)) + continue; + showperson = 0; + /* + * Show user if they are on the same channel, or not + * invisible and on a non secret channel (if any). + * Do this before brute force match on all relevant + * fields since these are less cpu intensive (I + * hope :-) and should provide better/more shortcuts + * -avalon + */ + isinvis = IsInvisible(acptr); + for (lp = acptr->user->channel; lp; lp = lp->next) + { + chptr = lp->value.chptr; + if (IsAnonymous(chptr)) + continue; + member = IsMember(sptr, chptr); + if (isinvis && !member) + continue; + if (member || (!isinvis && PubChannel(chptr))) + { + showperson = 1; + if (!IsAnonymous(chptr) || + acptr != sptr) + { + ch2ptr = chptr; + break; + } + } + if (HiddenChannel(chptr) && + !SecretChannel(chptr) && !isinvis) + showperson = 1; + } + if (!acptr->user->channel && !isinvis) + showperson = 1; + /* + ** This is brute force solution, not efficient...? ;( + ** Show entry, if no mask or any of the fields match + ** the mask. --msa + */ + if (showperson && + (!mask || + match(mask, acptr->name) == 0 || + match(mask, acptr->user->username) == 0 || + match(mask, acptr->user->host) == 0 || + match(mask, acptr->user->server) == 0 || + match(mask, acptr->info) == 0)) + who_one(sptr, acptr, ch2ptr, NULL); + } +} + +/* +** m_who +** parv[0] = sender prefix +** parv[1] = nickname mask list +** parv[2] = additional selection flag, only 'o' for now. +*/ +int m_who(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Link *lp; + aChannel *chptr, *mychannel; + char *channame = NULL; + int oper = parc > 2 ? (*parv[2] == 'o' ): 0; /* Show OPERS only */ + int penalty = 0; + char *p, *mask; + + if (parc < 2) + { + who_find(sptr, NULL, oper); + sendto_one(sptr, rpl_str(RPL_ENDOFWHO, parv[0]), "*"); + return 5; + } + + for (p = NULL, mask = strtoken(&p, parv[1], ","); + mask && penalty < MAXPENALTY; + mask = strtoken(&p, NULL, ",")) + { + channame = NULL; + mychannel = NullChn; + clean_channelname(mask); + if (sptr->user && (lp = sptr->user->channel)) + mychannel = lp->value.chptr; + /* + ** Following code is some ugly hacking to preserve the + ** functions of the old implementation. (Also, people + ** will complain when they try to use masks like "12tes*" + ** and get people on channel 12 ;) --msa + */ + if (!mask || *mask == '\0') /* !mask always false? */ + mask = NULL; + else if (mask[1] == '\0' && mask[0] == '*') + { + mask = NULL; + if (mychannel) + channame = mychannel->chname; + } + else if (mask[1] == '\0' && mask[0] == '0') + /* "WHO 0" for irc.el */ + mask = NULL; + else + channame = mask; + (void)collapse(mask); + + if (IsChannelName(channame)) + { + chptr = find_channel(channame, NULL); + if (chptr) + who_channel(sptr, chptr, oper); + penalty += 1; + } + else + { + who_find(sptr, mask, oper); + if (mask && (int)strlen(mask) > 4) + penalty += 3; + else + penalty += 5; + } + sendto_one(sptr, rpl_str(RPL_ENDOFWHO, parv[0]), + BadPtr(mask) ? "*" : mask); + } + return penalty; +} + +/* send_whois() is used by m_whois() to send whois reply to sptr, for acptr */ +static void +send_whois(sptr, acptr) +aClient *sptr, *acptr; +{ + static anUser UnknownUser = + { + NULL, /* channel */ + NULL, /* invited */ + NULL, /* uwas */ + NULL, /* away */ + 0, /* last */ + 1, /* refcount */ + 0, /* joined */ + 0, /* flags */ + NULL, /* servp */ + NULL, /* next, prev, bcptr */ + "<Unknown>", /* user */ + "<Unknown>", /* host */ + "<Unknown>", /* server */ + }; + Link *lp; + anUser *user; + aChannel *chptr; + aClient *a2cptr; + int len, mlen; + char *name; + + user = acptr->user ? acptr->user : &UnknownUser; + name = (!*acptr->name) ? "?" : acptr->name; + + a2cptr = find_server(user->server, NULL); + + sendto_one(sptr, rpl_str(RPL_WHOISUSER, sptr->name), + name, user->username, user->host, acptr->info); + + mlen = strlen(ME) + strlen(sptr->name) + 6 + strlen(name); + + for (len = 0, *buf = '\0', lp = user->channel; lp; lp = lp->next) + { + chptr = lp->value.chptr; + if ((!IsAnonymous(chptr) || acptr == sptr) && + ShowChannel(sptr, chptr)) + { + if (len + strlen(chptr->chname) + > (size_t) BUFSIZE - 4 - mlen) + { + sendto_one(sptr, ":%s %d %s %s :%s", ME, + RPL_WHOISCHANNELS, sptr->name, name, + buf); + *buf = '\0'; + len = 0; + } + if (is_chan_op(acptr, chptr)) + *(buf + len++) = '@'; + else if (has_voice(acptr, chptr)) + *(buf + len++) = '+'; + if (len) + *(buf + len) = '\0'; + (void)strcpy(buf + len, chptr->chname); + len += strlen(chptr->chname); + (void)strcat(buf + len, " "); + len++; + } + } + if (buf[0] != '\0') + sendto_one(sptr, rpl_str(RPL_WHOISCHANNELS, sptr->name), name, + buf); + + sendto_one(sptr, rpl_str(RPL_WHOISSERVER, sptr->name), + name, user->server, + a2cptr ? a2cptr->info:"*Not On This Net*"); + + if (user->flags & FLAGS_AWAY) + sendto_one(sptr, rpl_str(RPL_AWAY, sptr->name), name, + (user->away) ? user->away : "Gone"); + + if (IsAnOper(acptr)) + sendto_one(sptr, rpl_str(RPL_WHOISOPERATOR, sptr->name), name); + + if (acptr->user && MyConnect(acptr)) + sendto_one(sptr, rpl_str(RPL_WHOISIDLE, sptr->name), + name, timeofday - user->last); +} + +/* +** m_whois +** parv[0] = sender prefix +** parv[1] = nickname masklist +*/ +int m_whois(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Link *lp; + aClient *acptr; + aChannel *chptr; + char *nick, *tmp; + char *p = NULL; + int found = 0; + + if (parc < 2) + { + sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN, parv[0])); + return 1; + } + + if (parc > 2) + { + if (hunt_server(cptr,sptr,":%s WHOIS %s :%s", 1,parc,parv) != + HUNTED_ISME) + return 3; + parv[1] = parv[2]; + } + + parv[1] = canonize(parv[1]); + + for (tmp = parv[1]; (nick = strtoken(&p, tmp, ",")); tmp = NULL) + { + int invis, showperson, member, wilds; + + found &= 0x0f; /* high/boolean, low/counter */ + (void)collapse(nick); + wilds = (index(nick, '?') || index(nick, '*')); + /* + * We're no longer allowing remote users to generate + * requests with wildcard, nor local users with more + * than one wildcard target per command. + * Max 3 targets per command allowed. + */ + if ((wilds && (!MyConnect(sptr) || p)) || found++ > 3) + break; + + if (!wilds) + { + acptr = hash_find_client(nick, (aClient *)NULL); + if (!acptr || !IsPerson(acptr)) + sendto_one(sptr, + err_str(ERR_NOSUCHNICK, parv[0]), + nick); + else + send_whois(sptr, acptr); + continue; + } + + for (acptr = client; (acptr = next_client(acptr, nick)); + acptr = acptr->next) + { + if (IsServer(acptr) || IsService(acptr)) + continue; + /* + * I'm always last :-) and acptr->next == NULL!! + */ + if (IsMe(acptr)) + break; + /* + * 'Rules' established for sending a WHOIS reply: + * - if wildcards are being used don't send a reply if + * the querier isnt any common channels and the + * client in question is invisible and wildcards are + * in use (allow exact matches only); + * - only send replies about common or public channels + * the target user(s) are on; + */ + invis = (acptr->user) ? + (acptr->user->flags & FLAGS_INVISIBLE) : 0; + member = (acptr->user && acptr->user->channel) ? 1 : 0; + showperson = (wilds && !invis && !member) || !wilds; + for (lp = (acptr->user) ? acptr->user->channel : NULL; + lp; lp = lp->next) + { + chptr = lp->value.chptr; + if (IsAnonymous(chptr)) + continue; + member = IsMember(sptr, chptr); + if (invis && !member) + continue; + if (member || (!invis && PubChannel(chptr))) + { + showperson = 1; + break; + } + if (!invis && HiddenChannel(chptr) && + !SecretChannel(chptr)) + showperson = 1; + } + if (!showperson) + continue; + + found |= 0x10; + + send_whois(sptr, acptr); + } + if (!(found & 0x10)) + { + if (strlen(nick) > (size_t) NICKLEN) + nick[NICKLEN] = '\0'; + sendto_one(sptr, err_str(ERR_NOSUCHNICK, parv[0]), + nick); + } + if (p) + p[-1] = ','; + } + sendto_one(sptr, rpl_str(RPL_ENDOFWHOIS, parv[0]), parv[1]); + + return 2; +} + +/* +** m_user +** parv[0] = sender prefix +** parv[1] = username (login name, account) +** parv[2] = client host name (used only from other servers) +** parv[3] = server host name (used only from other servers) +** parv[4] = users real name info +** parv[5] = users mode (is only used internally by the server, +** NULL otherwise) +*/ +int m_user(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ +#define UFLAGS (FLAGS_INVISIBLE|FLAGS_WALLOP) + char *username, *host, *server, *realname; + anUser *user; + + /* Reject new USER */ + if (IsServer(sptr) || IsService(sptr) || sptr->user) + { + sendto_one(sptr, err_str(ERR_ALREADYREGISTRED, parv[0])); + return 1; + } + if (parc > 2 && (username = (char *)index(parv[1],'@'))) + *username = '\0'; + if (parc < 5 || *parv[1] == '\0' || *parv[2] == '\0' || + *parv[3] == '\0' || *parv[4] == '\0') + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "USER"); + if (IsServer(cptr)) + { + /* send error */ + sendto_flag(SCH_NOTICE, + "bad USER param count for %s from %s", + parv[0], get_client_name(cptr, FALSE)); + /* + ** and kill it, as there's no reason to expect more + ** USER messages about it, or we'll create a ghost. + */ + sendto_one(cptr, + ":%s KILL %s :%s (bad USER param count)", + ME, parv[0], ME); + sptr->flags |= FLAGS_KILLED; + exit_client(NULL, sptr, &me, "bad USER param count"); + } + return 1; + } + + /* Copy parameters into better documenting variables */ + + username = (parc < 2 || BadPtr(parv[1])) ? "<bad-boy>" : parv[1]; + host = (parc < 3 || BadPtr(parv[2])) ? "<nohost>" : parv[2]; + server = (parc < 4 || BadPtr(parv[3])) ? "<noserver>" : parv[3]; + realname = (parc < 5 || BadPtr(parv[4])) ? "<bad-realname>" : parv[4]; + + user = make_user(sptr); + + if (!MyConnect(sptr)) + { + aClient *acptr = NULL; + aServer *sp = NULL; + + if (!(sp = find_tokserver(atoi(server), cptr, NULL))) + { + /* + ** Why? Why do we keep doing this? + ** s_service.c had the same kind of kludge. + ** Can't we get rid of this? - krys + */ + acptr = find_server(server, NULL); + if (acptr) + sendto_flag(SCH_ERROR, + "ERROR: SERVER:%s uses wrong syntax for NICK (%s)", + get_client_name(cptr, FALSE), + parv[0]); + } + if (acptr) + sp = acptr->serv; + else if (!sp) + { + sendto_flag(SCH_ERROR, + "ERROR: USER:%s without SERVER:%s from %s", + parv[0], server, + get_client_name(cptr, FALSE)); + ircstp->is_nosrv++; + return exit_client(NULL, sptr, &me, "No Such Server"); + } + user->servp = sp; + user->servp->refcnt++; + + Debug((DEBUG_DEBUG, "from %s user %s server %s -> %#x %s", + parv[0], username, server, sp, sp->bcptr->name)); + strncpyzt(user->host, host, sizeof(user->host)); + user->server = find_server_string(sp->snum); + goto user_finish; + } + + user->servp = me.serv; + me.serv->refcnt++; +#ifndef NO_DEFAULT_INVISIBLE + SetInvisible(sptr); +#endif + if (sptr->flags & FLAGS_RILINE) + sptr->user->flags |= FLAGS_RESTRICTED; + sptr->user->flags |= (UFLAGS & atoi(host)); + strncpyzt(user->host, host, sizeof(user->host)); + user->server = find_server_string(me.serv->snum); + +user_finish: + reorder_client_in_list(sptr); + if (sptr->info != DefInfo) + MyFree(sptr->info); + if (strlen(realname) > REALLEN) + realname[REALLEN] = '\0'; + sptr->info = mystrdup(realname); + if (sptr->name[0]) /* NICK already received, now we have USER... */ + { + if ((parc == 6) && IsServer(cptr)) /* internal m_user() */ + { + char *pv[4]; + + pv[0] = ME; + pv[1] = sptr->name; + pv[2] = parv[5]; + pv[3] = NULL; + m_umode(NULL, sptr, 3, pv);/*internal fake call again*/ + /* The internal m_umode does NOT propagate to 2.8 + ** servers. (it can NOT since NICK/USER hasn't been + ** sent yet). See register_user() + */ + } + return register_user(cptr, sptr, sptr->name, username); + } + else + strncpyzt(sptr->user->username, username, USERLEN+1); + return 2; +} + +/* +** m_quit +** parv[0] = sender prefix +** parv[1] = comment +*/ +int m_quit(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + static char quitc[] = "I Quit"; + register char *comment = (parc > 1 && parv[1]) ? parv[1] : quitc; + + if (MyClient(sptr) || MyService(sptr)) + if (!strncmp("Local Kill", comment, 10) || + !strncmp(comment, "Killed", 6)) + comment = quitc; + if (strlen(comment) > (size_t) TOPICLEN) + comment[TOPICLEN] = '\0'; + return IsServer(sptr) ? 0 : exit_client(cptr, sptr, sptr, comment); + } + +/* +** m_kill +** parv[0] = sender prefix +** parv[1] = kill victim +** parv[2] = kill path +*/ +int m_kill(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + aClient *acptr; + char *inpath = get_client_name(cptr,FALSE); + char *user, *path, *killer; + int chasing = 0; + + if (parc < 2 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "KILL"); + return 1; + } + + user = parv[1]; + path = parv[2]; /* Either defined or NULL (parc >= 2!!) */ + + if (IsAnOper(cptr)) + { + if (BadPtr(path)) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), + "KILL"); + return 1; + } + if (strlen(path) > (size_t) TOPICLEN) + path[TOPICLEN] = '\0'; + } + + if (!(acptr = find_client(user, NULL))) + { + /* + ** If the user has recently changed nick, we automaticly + ** rewrite the KILL for this new nickname--this keeps + ** servers in synch when nick change and kill collide + */ + if (!(acptr = get_history(user, (long)KILLCHASETIMELIMIT))) + { + if (!IsServer(sptr)) + sendto_one(sptr, err_str(ERR_NOSUCHNICK, + parv[0]), user); + return 1; + } + sendto_one(sptr,":%s NOTICE %s :KILL changed from %s to %s", + ME, parv[0], user, acptr->name); + chasing = 1; + } + if (!MyConnect(acptr) && IsLocOp(cptr)) + { + sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0])); + return 1; + } + if (IsServer(acptr) || IsMe(acptr)) + { + sendto_flag(SCH_ERROR, "%s tried to KILL server %s: %s %s %s", + sptr->name, acptr->name, parv[0], parv[1], parv[2]); + sendto_one(sptr, err_str(ERR_CANTKILLSERVER, parv[0]), + acptr->name); + return 1; + } + +#ifdef LOCAL_KILL_ONLY + if (MyOper(sptr) && !MyConnect(acptr)) + { + sendto_one(sptr, ":%s NOTICE %s :Nick %s isnt on your server", + ME, parv[0], acptr->name); + return 1; + } +#endif + if (!IsServer(cptr)) + { + /* + ** The kill originates from this server, initialize path. + ** (In which case the 'path' may contain user suplied + ** explanation ...or some nasty comment, sigh... >;-) + ** + ** ...!operhost!oper + ** ...!operhost!oper (comment) + */ + if (IsUnixSocket(cptr)) /* Don't use get_client_name syntax */ + inpath = me.sockhost; + else + inpath = cptr->sockhost; + if (!BadPtr(path)) + { + SPRINTF(buf, "%s%s (%s)", + cptr->name, IsOper(sptr) ? "" : "(L)", path); + path = buf; + } + else + path = cptr->name; + } + else if (BadPtr(path)) + path = "*no-path*"; /* Bogus server sending??? */ + /* + ** Notify all *local* opers about the KILL (this includes the one + ** originating the kill, if from this server--the special numeric + ** reply message is not generated anymore). + ** + ** Note: "acptr->name" is used instead of "user" because we may + ** have changed the target because of the nickname change. + */ + if (IsLocOp(sptr) && !MyConnect(acptr)) + { + sendto_one(sptr, err_str(ERR_NOPRIVILEGES, parv[0])); + return 1; + } + sendto_flag(SCH_KILL, + "Received KILL message for %s. From %s Path: %s!%s", + acptr->name, parv[0], inpath, path); +#if defined(USE_SYSLOG) && defined(SYSLOG_KILL) + if (IsOper(sptr)) + syslog(LOG_DEBUG,"KILL From %s For %s Path %s!%s", + parv[0], acptr->name, inpath, path); +#endif + /* + ** And pass on the message to other servers. Note, that if KILL + ** was changed, the message has to be sent to all links, also + ** back. + ** Suicide kills are NOT passed on --SRB + */ + if (!MyConnect(acptr) || !MyConnect(sptr) || !IsAnOper(sptr)) + { + sendto_serv_butone(cptr, ":%s KILL %s :%s!%s", + parv[0], acptr->name, inpath, path); + if (chasing && !IsClient(cptr)) + sendto_one(cptr, ":%s KILL %s :%s!%s", + ME, acptr->name, inpath, path); + acptr->flags |= FLAGS_KILLED; + } +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_KILL, NULL, sptr, + ":%s KILL %s :%s!%s", parv[0], acptr->name, + inpath, path); +#endif + + /* + ** Tell the victim she/he has been zapped, but *only* if + ** the victim is on current server--no sense in sending the + ** notification chasing the above kill, it won't get far + ** anyway (as this user don't exist there any more either) + */ + if (MyConnect(acptr)) + sendto_prefix_one(acptr, sptr,":%s KILL %s :%s!%s", + parv[0], acptr->name, inpath, path); + /* + ** Set FLAGS_KILLED. This prevents exit_one_client from sending + ** the unnecessary QUIT for this. (This flag should never be + ** set in any other place) + */ + if (MyConnect(acptr) && MyConnect(sptr) && IsAnOper(sptr)) + { + acptr->exitc = EXITC_KILL; + SPRINTF(buf2, "Local Kill by %s (%s)", sptr->name, + BadPtr(parv[2]) ? sptr->name : parv[2]); + } + else + { + if ((killer = index(path, ' '))) + { + while (killer > path && *killer != '!') + killer--; + if (killer != path) + killer++; + } + else + killer = path; + SPRINTF(buf2, "Killed (%s)", killer); + } + return exit_client(cptr, acptr, sptr, buf2); +} + +/*********************************************************************** + * m_away() - Added 14 Dec 1988 by jto. + * Not currently really working, I don't like this + * call at all... + * + * ...trying to make it work. I don't like it either, + * but perhaps it's worth the load it causes to net. + * This requires flooding of the whole net like NICK, + * USER, MODE, etc messages... --msa + ***********************************************************************/ + +/* +** m_away +** parv[0] = sender prefix +** parv[1] = away message +*/ +int m_away(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg char *away, *awy2 = parv[1]; + int len; + + away = sptr->user->away; + + if (parc < 2 || !*awy2) /* Marking as not away */ + { + if (away) + { + istat.is_away--; + istat.is_awaymem -= (strlen(away) + 1); + MyFree(away); + sptr->user->away = NULL; + } + if (sptr->user->flags & FLAGS_AWAY) + sendto_serv_butone(cptr, ":%s MODE %s :-a", parv[0], + parv[0]); + /* sendto_serv_butone(cptr, ":%s AWAY", parv[0]); */ + if (MyConnect(sptr)) + sendto_one(sptr, rpl_str(RPL_UNAWAY, parv[0])); +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_AWAY, NULL, sptr, + ":%s AWAY", parv[0]); +#endif + sptr->user->flags &= ~FLAGS_AWAY; + return 1; + } + + /* Marking as away */ + + if ((len = strlen(awy2)) > (size_t) TOPICLEN) + { + len = TOPICLEN; + awy2[TOPICLEN] = '\0'; + } + len++; + /* sendto_serv_butone(cptr, ":%s AWAY :%s", parv[0], awy2); */ +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_AWAY, NULL, sptr, + ":%s AWAY :%s", parv[0], awy2); +#endif + + if (away) + { + istat.is_awaymem -= (strlen(away) + 1); + away = (char *)MyRealloc(away, len); + istat.is_awaymem += len; + } + else + { + istat.is_away++; + istat.is_awaymem += len; + away = (char *)MyMalloc(len); + sendto_serv_butone(cptr, ":%s MODE %s :+a", parv[0], parv[0]); + } + + sptr->user->flags |= FLAGS_AWAY; + if (MyConnect(sptr)) + { + sptr->user->away = away; + (void)strcpy(away, awy2); + sendto_one(sptr, rpl_str(RPL_NOWAWAY, parv[0])); + } + return 2; +} + +/* +** m_ping +** parv[0] = sender prefix +** parv[1] = origin +** parv[2] = destination +*/ +int m_ping(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + aClient *acptr; + char *origin, *destination; + + if (parc < 2 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NOORIGIN, parv[0])); + return 1; + } + origin = parv[1]; + destination = parv[2]; /* Will get NULL or pointer (parc >= 2!!) */ + + acptr = find_client(origin, NULL); + if (!acptr) + acptr = find_server(origin, NULL); + if (!acptr || acptr != sptr) + origin = cptr->name; + if (!BadPtr(destination) && mycmp(destination, ME) != 0) + { + if ((acptr = find_server(destination, NULL))) + sendto_one(acptr,":%s PING %s :%s", parv[0], + origin, destination); + else + { + sendto_one(sptr, err_str(ERR_NOSUCHSERVER, parv[0]), + destination); + return 1; + } + } + else + sendto_one(sptr, ":%s PONG %s :%s", ME, + (destination) ? destination : ME, origin); + return 1; + } + +/* +** m_pong +** parv[0] = sender prefix +** parv[1] = origin +** parv[2] = destination +*/ +int m_pong(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + aClient *acptr; + char *origin, *destination; + + if (parc < 2 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NOORIGIN, parv[0])); + return 1; + } + + origin = parv[1]; + destination = parv[2]; + cptr->flags &= ~FLAGS_PINGSENT; + sptr->flags &= ~FLAGS_PINGSENT; + + if (!BadPtr(destination) && mycmp(destination, ME) != 0) + { + if ((acptr = find_client(destination, NULL)) || + (acptr = find_server(destination, NULL))) { + if (!(MyClient(sptr) && mycmp(origin, sptr->name))) + sendto_one(acptr,":%s PONG %s %s", + parv[0], origin, destination); + } else + sendto_one(sptr, err_str(ERR_NOSUCHSERVER, parv[0]), + destination); + return 2; + } +#ifdef DEBUGMODE + else + Debug((DEBUG_NOTICE, "PONG: %s %s", origin, + destination ? destination : "*")); +#endif + return 1; + } + + +/* +** m_oper +** parv[0] = sender prefix +** parv[1] = oper name +** parv[2] = oper password +*/ +int m_oper(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + aConfItem *aconf; + char *name, *password, *encr; +#ifdef CRYPT_OPER_PASSWORD + char salt[3]; + extern char *crypt(); +#endif /* CRYPT_OPER_PASSWORD */ + + name = parc > 1 ? parv[1] : NULL; + password = parc > 2 ? parv[2] : NULL; + + if (!IsServer(cptr) && (BadPtr(name) || BadPtr(password))) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "OPER"); + return 1; + } + + /* if message arrived from server, trust it, and set to oper */ + + if ((IsServer(cptr) || IsMe(cptr)) && !IsOper(sptr)) + { + /* we never get here, do we?? (counters!) -krys */ + sptr->user->flags |= FLAGS_OPER; + sendto_serv_butone(cptr, ":%s MODE %s :+o", parv[0], parv[0]); + if (IsMe(cptr)) + sendto_one(sptr, rpl_str(RPL_YOUREOPER, parv[0])); +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_OPER, sptr->user->server, + sptr, ":%s MODE %s :+o", parv[0], + parv[0]); +#endif + return 1; + } + else if (IsAnOper(sptr)) + { + if (MyConnect(sptr)) + sendto_one(sptr, rpl_str(RPL_YOUREOPER, parv[0])); + return 1; + } + if (!(aconf = find_conf_exact(name, sptr->username, sptr->sockhost, + CONF_OPS)) && + !(aconf = find_conf_exact(name, sptr->username, +#ifdef INET6 + (char *)inetntop(AF_INET6, + (char *)&cptr->ip, + mydummy, MYDUMMY_SIZE), +#else + (char *)inetntoa((char *)&cptr->ip), +#endif + CONF_OPS))) + { + sendto_one(sptr, err_str(ERR_NOOPERHOST, parv[0])); + return 1; + } +#ifdef CRYPT_OPER_PASSWORD + /* use first two chars of the password they send in as salt */ + + /* passwd may be NULL. Head it off at the pass... */ + salt[0] = '\0'; + if (password && aconf->passwd) + { + /* Determine if MD5 or DES */ + if (strncmp(aconf->passwd, "$1$", 3)) + { + salt[0] = aconf->passwd[0]; + salt[1] = aconf->passwd[1]; + } + else + { + salt[0] = aconf->passwd[3]; + salt[1] = aconf->passwd[4]; + } + salt[2] = '\0'; + encr = crypt(password, salt); + } + else + encr = ""; +#else + encr = password; +#endif /* CRYPT_OPER_PASSWORD */ + + if ((aconf->status & CONF_OPS) && + StrEq(encr, aconf->passwd) && !attach_conf(sptr, aconf)) + { + int old = (sptr->user->flags & ALL_UMODES); + char *s; + + s = index(aconf->host, '@'); + *s++ = '\0'; +#ifdef OPER_REMOTE + if (aconf->status == CONF_LOCOP) +#else + if ((match(s,me.sockhost) && !IsLocal(sptr)) || + aconf->status == CONF_LOCOP) +#endif + SetLocOp(sptr); + else + SetOper(sptr); + *--s = '@'; + sendto_flag(SCH_NOTICE, "%s (%s@%s) is now operator (%c)", + parv[0], sptr->user->username, sptr->user->host, + IsOper(sptr) ? 'o' : 'O'); + send_umode_out(cptr, sptr, old); + sendto_one(sptr, rpl_str(RPL_YOUREOPER, parv[0])); +#if !defined(CRYPT_OPER_PASSWORD) && (defined(FNAME_OPERLOG) ||\ + (defined(USE_SYSLOG) && defined(SYSLOG_OPER))) + encr = ""; +#endif +#if defined(USE_SYSLOG) && defined(SYSLOG_OPER) + syslog(LOG_INFO, "OPER (%s) (%s) by (%s!%s@%s) [%s@%s]", + name, encr, + parv[0], sptr->user->username, sptr->user->host, + sptr->auth, IsUnixSocket(sptr) ? sptr->sockhost : +#ifdef INET6 + inet_ntop(AF_INET6, (char *)&sptr->ip), mydummy, MYDUMMY_SIZE); +#else + inetntoa((char *)&sptr->ip)); +#endif +#endif +#ifdef FNAME_OPERLOG + { + 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(sptr) && + (logfile = open(FNAME_OPERLOG, O_WRONLY|O_APPEND)) != -1) + { + (void)alarm(0); + SPRINTF(buf, "%s OPER (%s) (%s) by (%s!%s@%s) [%s@%s]\n", + myctime(timeofday), name, encr, + parv[0], sptr->user->username, sptr->user->host, + sptr->auth, IsUnixSocket(sptr) ? sptr->sockhost : +#ifdef INET6 + inetntop(AF_INET6, (char *)&sptr->ip, mydummy, + MYDUMMY_SIZE)); +#else + inetntoa((char *)&sptr->ip)); +#endif + (void)alarm(3); + (void)write(logfile, buf, strlen(buf)); + (void)alarm(0); + (void)close(logfile); + } + (void)alarm(0); + /* Modification by pjg */ + } +#endif +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_OPER, sptr->user->server, + sptr, ":%s MODE %s :+%c", parv[0], + parv[0], IsOper(sptr) ? 'O' : 'o'); +#endif + if (IsAnOper(sptr)) + istat.is_oper++; + } + else + { + (void)detach_conf(sptr, aconf); + sendto_one(sptr,err_str(ERR_PASSWDMISMATCH, parv[0])); + } + return 3; + } + +/*************************************************************************** + * m_pass() - Added Sat, 4 March 1989 + ***************************************************************************/ + +/* +** m_pass +** parv[0] = sender prefix +** parv[1] = password +** parv[2] = protocol & server versions (server only) +** parv[3] = server id & options (server only) +** parv[4] = (optional) link options (server only) +*/ +int m_pass(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; + { + char *password = parc > 1 ? parv[1] : NULL; + + if (BadPtr(password)) + { + sendto_one(cptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "PASS"); + return 1; + } + /* Temporarily store PASS pwd *parameters* into info field */ + if (parc > 2 && parv[2]) + { + strncpyzt(buf, parv[2], 15); + if (parc > 3 && parv[3]) + { + strcat(buf, " "); + strncat(buf, parv[3], 100); + if (parc > 4 && parv[4]) + { + strcat(buf, " "); + strncat(buf, parv[4], 5); + } + } + if (cptr->info != DefInfo) + MyFree(cptr->info); + cptr->info = mystrdup(buf); + } + strncpyzt(cptr->passwd, password, sizeof(cptr->passwd)); + return 1; + } + +/* + * m_userhost added by Darren Reed 13/8/91 to aid clients and reduce + * the need for complicated requests like WHOIS. It returns user/host + * information only (no spurious AWAY labels or channels). + */ +int m_userhost(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + char *p = NULL; + aClient *acptr; + Reg char *s; + Reg int i, len; + int idx = 1; + + if (parc < 2) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), + "USERHOST"); + return 1; + } + + (void)strcpy(buf, rpl_str(RPL_USERHOST, parv[0])); + len = strlen(buf); + *buf2 = '\0'; + + for (i = 5, s = strtoken(&p, parv[idx], " "); i && s; i--) + { + if ((acptr = find_person(s, NULL))) + { + if (*buf2) + (void)strcat(buf, " "); + SPRINTF(buf2, "%s%s=%c%s@%s", acptr->name, + IsAnOper(acptr) ? "*" : "", + (acptr->user->flags & FLAGS_AWAY) ? '-' : '+', + acptr->user->username, acptr->user->host); + (void)strncat(buf, buf2, sizeof(buf) - len); + len += strlen(buf2); + if (len > BUFSIZE - (NICKLEN + 5 + HOSTLEN + USERLEN)) + { + sendto_one(sptr, "%s", buf); + (void)strcpy(buf, rpl_str(RPL_USERHOST, + parv[0])); + len = strlen(buf); + *buf2 = '\0'; + } + } + s = strtoken(&p, (char *)NULL, " "); + if (!s && parv[++idx]) + { + p = NULL; + s = strtoken(&p, parv[idx], " "); + } + } + sendto_one(sptr, "%s", buf); + return 1; +} + +/* + * m_ison added by Darren Reed 13/8/91 to act as an efficent user indicator + * with respect to cpu/bandwidth used. Implemented for NOTIFY feature in + * clients. Designed to reduce number of whois requests. Can process + * nicknames in batches as long as the maximum buffer length. + * + * format: + * ISON :nicklist + */ + +int m_ison(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aClient *acptr; + Reg char *s, **pav = parv; + Reg int len = 0; + char *p = NULL; + + if (parc < 2) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "ISON"); + return 1; + } + + (void)strcpy(buf, rpl_str(RPL_ISON, *parv)); + len = strlen(buf); + + for (s = strtoken(&p, *++pav, " "); s; s = strtoken(&p, NULL, " ")) + if ((acptr = find_person(s, NULL))) + { + (void) strcpy(buf + len, acptr->name); + len += strlen(acptr->name); + (void) strcpy(buf + len++, " "); + } + sendto_one(sptr, "%s", buf); + return 1; +} + +/* + * m_umode() added 15/10/91 By Darren Reed. + * parv[0] - sender (can be NULL, see below..) + * parv[1] - username to change mode for + * parv[2] - modes to change + */ +int m_umode(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg int flag; + Reg int *s; + Reg char **p, *m; + aClient *acptr = NULL; + int what, setflags, penalty = 0; + + what = MODE_ADD; + + if (parc < 2) + { + sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS, parv[0]), "MODE"); + return 1; + } + + if (cptr && !(acptr = find_person(parv[1], NULL))) + { + if (MyConnect(sptr)) + sendto_one(sptr, err_str(ERR_NOSUCHCHANNEL, parv[0]), + parv[1]); + return 1; + } + if (cptr == NULL) + /* internal call which has to be handled in a special way */ + acptr = sptr; + + if ((cptr != NULL) && + ((IsServer(sptr) || sptr != acptr || acptr->from != sptr->from))) + { + if (IsServer(cptr)) + sendto_ops_butone(NULL, &me, + ":%s WALLOPS :MODE for User %s From %s!%s", + ME, parv[1], + get_client_name(cptr, FALSE), sptr->name); + else + sendto_one(sptr, err_str(ERR_USERSDONTMATCH, parv[0])); + return 1; + } + + if (parc < 3) + { + m = buf; + *m++ = '+'; + for (s = user_modes; (flag = *s) && (m - buf < BUFSIZE - 4); + s += 2) + if (sptr->user->flags & flag) + *m++ = (char)(*(s+1)); + *m = '\0'; + sendto_one(sptr, rpl_str(RPL_UMODEIS, parv[0]), buf); + return 1; + } + + /* find flags already set for user */ + setflags = 0; + for (s = user_modes; (flag = *s); s += 2) + if (sptr->user->flags & flag) + setflags |= flag; + + /* + * parse mode change string(s) + */ + for (p = &parv[2]; p && *p; p++ ) + for (m = *p; *m; m++) + switch(*m) + { + case '+' : + what = MODE_ADD; + break; + case '-' : + what = MODE_DEL; + break; + /* we may not get these, + * but they shouldnt be in default + */ + case ' ' : + case '\n' : + case '\r' : + case '\t' : + break; + case 'a' : /* fall through case */ + /* users should use the AWAY message */ + if (cptr && !IsServer(cptr)) + break; + if (what == MODE_DEL && sptr->user->away) + { + istat.is_away--; + istat.is_awaymem -= (strlen(sptr->user->away) + 1); + MyFree(sptr->user->away); + sptr->user->away = NULL; +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_AWAY, + sptr->user->server, sptr, + ":%s AWAY", parv[0]); +#endif + } +#ifdef USE_SERVICES + if (what == MODE_ADD) + check_services_butone(SERVICE_WANT_AWAY, + sptr->user->server, sptr, + ":%s AWAY :", parv[0]); +#endif + default : + for (s = user_modes; (flag = *s); s += 2) + if (*m == (char)(*(s+1))) + { + if (what == MODE_ADD) + sptr->user->flags |= flag; + else + sptr->user->flags &= ~flag; + penalty += 1; + break; + } + if (flag == 0 && MyConnect(sptr)) + sendto_one(sptr, err_str( + ERR_UMODEUNKNOWNFLAG, parv[0]), + *m); + break; + } + /* + * stop users making themselves operators too easily + */ + if (cptr) + { + if (!(setflags & FLAGS_OPER) && IsOper(sptr) && + !IsServer(cptr)) + ClearOper(sptr); + if (!(setflags & FLAGS_LOCOP) && IsLocOp(sptr) && + !IsServer(cptr)) + sptr->user->flags &= ~FLAGS_LOCOP; + if ((setflags & FLAGS_RESTRICTED) && + !(sptr->user->flags & FLAGS_RESTRICTED)) + { + sendto_one(sptr, err_str(ERR_RESTRICTED, parv[0])); + SetRestricted(sptr); + /* Can't return; here since it could mess counters */ + } + if ((setflags & (FLAGS_OPER|FLAGS_LOCOP)) && !IsAnOper(sptr) && + MyConnect(sptr)) + det_confs_butmask(sptr, CONF_CLIENT); + + /* + * compare new flags with old flags and send string which + * will cause servers to update correctly. + */ + if (!IsInvisible(sptr) && (setflags & FLAGS_INVISIBLE)) + { + istat.is_user[1]--; + istat.is_user[0]++; + } + if (IsInvisible(sptr) && !(setflags & FLAGS_INVISIBLE)) + { + istat.is_user[1]++; + istat.is_user[0]--; + } + send_umode_out(cptr, sptr, setflags); + } + + /* update counters */ + if (IsOper(sptr) && !(setflags & FLAGS_OPER)) + { + istat.is_oper++; +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_OPER, sptr->user->server, + sptr, ":%s MODE %s :+o", parv[0], + parv[0]); +#endif + } + else if (!IsOper(sptr) && (setflags & FLAGS_OPER)) + { + istat.is_oper--; +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_OPER, sptr->user->server, + sptr, ":%s MODE %s :-o", parv[0], + parv[0]); +#endif + } + else if (MyConnect(sptr) && !IsLocOp(sptr) && (setflags & FLAGS_LOCOP)) + { + istat.is_oper--; +#ifdef USE_SERVICES + check_services_butone(SERVICE_WANT_OPER, sptr->user->server, + sptr, ":%s MODE %s :-O", parv[0], + parv[0]); +#endif + } + + return penalty; +} + +/* + * send the MODE string for user (user) to connection cptr + * -avalon + */ +void send_umode(cptr, sptr, old, sendmask, umode_buf) +aClient *cptr, *sptr; +int old, sendmask; +char *umode_buf; +{ + Reg int *s, flag; + Reg char *m; + int what = MODE_NULL; + + if (!sptr->user) + return; + /* + * build a string in umode_buf to represent the change in the user's + * mode between the new (sptr->flag) and 'old'. + */ + m = umode_buf; + *m = '\0'; + for (s = user_modes; (flag = *s); s += 2) + { + if (MyClient(sptr) && !(flag & sendmask)) + continue; + if ((flag & old) && !(sptr->user->flags & flag)) + { + if (what == MODE_DEL) + *m++ = *(s+1); + else + { + what = MODE_DEL; + *m++ = '-'; + *m++ = *(s+1); + } + } + else if (!(flag & old) && (sptr->user->flags & flag)) + { + if (what == MODE_ADD) + *m++ = *(s+1); + else + { + what = MODE_ADD; + *m++ = '+'; + *m++ = *(s+1); + } + } + } + *m = '\0'; + if (*umode_buf && cptr) + sendto_one(cptr, ":%s MODE %s :%s", + sptr->name, sptr->name, umode_buf); +} + +/* + * added Sat Jul 25 07:30:42 EST 1992 + */ +void send_umode_out(cptr, sptr, old) +aClient *cptr, *sptr; +int old; +{ + Reg int i; + Reg aClient *acptr; + + send_umode(NULL, sptr, old, SEND_UMODES, buf); + + if (*buf) + for (i = fdas.highest; i >= 0; i--) + { + if (!(acptr = local[fdas.fd[i]]) || !IsServer(acptr)) + continue; + if (acptr == cptr || acptr == sptr) + continue; + sendto_one(acptr, ":%s MODE %s :%s", + sptr->name, sptr->name, buf); + } + + if (cptr && MyClient(cptr)) + send_umode(cptr, sptr, old, ALL_UMODES, buf); +#ifdef USE_SERVICES + /* buf contains all modes for local users, and iow only for remotes */ + if (*buf) + check_services_butone(SERVICE_WANT_UMODE, NULL, sptr, + ":%s MODE %s :%s", sptr->name, + sptr->name, buf); +#endif +} diff --git a/ircd/s_user_ext.h b/ircd/s_user_ext.h new file mode 100644 index 0000000..2feec20 --- /dev/null +++ b/ircd/s_user_ext.h @@ -0,0 +1,60 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_user_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_user.c. + */ + +/* External definitions for global functions. + */ +#ifndef S_USER_C +#define EXTERN extern +#else /* S_USER_C */ +#define EXTERN +#endif /* S_USER_C */ +EXTERN aClient *next_client __P((Reg aClient *next, Reg char *ch)); +EXTERN int hunt_server __P((aClient *cptr, aClient *sptr, char *command, + int server, int parc, char *parv[])); +EXTERN int do_nick_name __P((char *nick, int server)); +EXTERN int ereject_user __P((aClient *, char *, char *)); +EXTERN int register_user __P((aClient *, aClient *, char *, char *)); +EXTERN char *canonize __P((char *buffer)); +EXTERN int m_nick __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_private __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_notice __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_who __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_whois __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_user __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_quit __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_kill __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_away __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_ping __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_pong __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_oper __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_pass __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_userhost __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN int m_ison __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN int m_umode __P((aClient *cptr, aClient *sptr, int parc, char *parv[])); +EXTERN void send_umode __P((aClient *cptr, aClient *sptr, int old, + int sendmask, char *umode_buf)); +EXTERN void send_umode_out __P((aClient *cptr, aClient *sptr, int old)); +#undef EXTERN diff --git a/ircd/s_zip.c b/ircd/s_zip.c new file mode 100644 index 0000000..819c9a9 --- /dev/null +++ b/ircd/s_zip.c @@ -0,0 +1,261 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_zip.c + * Copyright (C) 1996 Christophe Kalt + * + * 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 rcsid[] = "@(#)$Id: s_zip.c,v 1.7 1998/12/24 16:29:17 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define S_ZIP_C +#include "s_externs.h" +#undef S_ZIP_C + +#ifdef ZIP_LINKS + +/* +** Important note: +** The provided buffers for compression *MUST* be big +** enough for any operation to complete. +** +** s_bsd.c current settings are that the biggest packet size is 16k +** (but socket buffers are set to 8k..) +*/ + +/* +** size of the buffer holding compressed data +** +** outgoing data: +** must be enough to hold compressed data resulting of the compression +** of up to ZIP_MAXIMUM bytes +** incoming data: +** must be enough to hold what was just read +** (cptr->zip->inbuf should never hold more than ONE compression block. +** The biggest block allowed for compression is ZIP_MAXIMUM bytes) +*/ +#define ZIP_BUFFER_SIZE (MAX(ZIP_MAXIMUM, READBUF_SIZE)) + +/* +** size of the buffer where zlib puts compressed data +** should be enough to hold uncompressed data resulting of the +** uncompression of zipbuffer +** +** tests show that an average ratio is around 40%, +** in some very particular cases, ratio can be VERY low, BUT: +** +** s_bsd.c/read_packet() is now smart enough to detect when uncompression +** stopped because the buffer is too small, and calls dopacket() again +** to finish the work (as many times as needed). +*/ +#define UNZIP_BUFFER_SIZE 4*ZIP_BUFFER_SIZE + +/* buffers */ +static char unzipbuf[UNZIP_BUFFER_SIZE]; +static char zipbuf[ZIP_BUFFER_SIZE]; + +/* +** zip_init +** Initialize compression structures for a server. +** If failed, zip_free() has to be called. +*/ +int zip_init(cptr) +aClient *cptr; +{ + cptr->zip = (aZdata *) MyMalloc(sizeof(aZdata)); + cptr->zip->outcount = 0; + + cptr->zip->in = (z_stream *) MyMalloc(sizeof(z_stream)); + cptr->zip->in->avail_in = 0; + cptr->zip->in->total_in = 0; + cptr->zip->in->total_out = 0; + cptr->zip->in->zalloc = (alloc_func)0; + cptr->zip->in->zfree = (free_func)0; + cptr->zip->in->data_type = Z_ASCII; + if (inflateInit(cptr->zip->in) != Z_OK) + { + cptr->zip->out = NULL; + return -1; + } + + cptr->zip->out = (z_stream *) MyMalloc(sizeof(z_stream)); + cptr->zip->out->total_in = 0; + cptr->zip->out->total_out = 0; + cptr->zip->out->zalloc = (alloc_func)0; + cptr->zip->out->zfree = (free_func)0; + cptr->zip->out->data_type = Z_ASCII; + if (deflateInit(cptr->zip->out, ZIP_LEVEL) != Z_OK) + return -1; + + return 0; +} + +/* +** zip_free +*/ +void zip_free(cptr) +aClient *cptr; +{ + cptr->flags &= ~FLAGS_ZIP; + if (cptr->zip) + { + if (cptr->zip->in) + inflateEnd(cptr->zip->in); + MyFree((char *)cptr->zip->in); + if (cptr->zip->out) + deflateEnd(cptr->zip->out); + MyFree((char *)cptr->zip->out); + MyFree((char *)cptr->zip); + cptr->zip = NULL; + } +} + +/* +** unzip_packet +** Unzip the content of the buffer, don't worry about any leftover. +** +** will return the uncompressed buffer, length will be updated. +** if a fatal error occurs, length will be set to -1 +*/ +char * unzip_packet(cptr, buffer, length) +aClient *cptr; +char *buffer; +int *length; +{ + Reg z_stream *zin = cptr->zip->in; + int r; + + if (*length != 0 && zin->avail_in != 0) + { + sendto_flag(SCH_ERROR, + "assertion failed in unzip_packet(): %d %d", + *length, zin->avail_in); + sendto_flag(SCH_ERROR, "Please report to ircd-bugs@irc.org"); + *length = -1; + return NULL; + } + if (*length) + { + zin->next_in = buffer; + zin->avail_in = *length; + } + zin->next_out = unzipbuf; + zin->avail_out = UNZIP_BUFFER_SIZE; + switch (r = inflate(zin, Z_PARTIAL_FLUSH)) + { + case Z_OK: + cptr->flags &= ~FLAGS_ZIPRQ; + *length = UNZIP_BUFFER_SIZE - zin->avail_out; + return unzipbuf; + + case Z_BUF_ERROR: /*no progress possible or output buffer too small*/ + if (zin->avail_out == 0) + { + sendto_flag(SCH_ERROR, + "inflate() returned Z_BUF_ERROR: %s", + (zin->msg) ? zin->msg : "?"); + *length = -1; + } + break; + + case Z_DATA_ERROR: /* the buffer might not be compressed.. */ + if ((cptr->flags & FLAGS_ZIPRQ) && + !strncmp("ERROR ", buffer, 6)) + { + cptr->flags &= ~(FLAGS_ZIP | FLAGS_ZIPRQ); + /* + * This is not sane at all. But if other server + * has sent an error now, it is probably closing + * the link as well. + */ + return buffer; + } + + /* no break */ + + default: /* error ! */ + /* should probably mark link as dead or something... */ + sendto_flag(SCH_ERROR, "inflate() error(%d): %s", r, + (zin->msg) ? zin->msg : "?"); + *length = -1; /* report error condition */ + break; + } + return NULL; +} + +/* +** zip_buffer +** Zip the content of cptr->zip->outbuf and of the buffer, +** put anything left in cptr->zip->outbuf, update cptr->zip->outcount +** +** if flush is set, then all available data will be compressed, +** otherwise, compression only occurs if there's enough to compress, +** or if we are reaching the maximum allowed size during a connect burst. +** +** will return the uncompressed buffer, length will be updated. +** if a fatal error occurs, length will be set to -1 +*/ +char * zip_buffer(cptr, buffer, length, flush) +aClient *cptr; +char *buffer; +int *length, flush; +{ + Reg z_stream *zout = cptr->zip->out; + int r; + + if (buffer) + { + /* concatenate buffer in cptr->zip->outbuf */ + bcopy(buffer, cptr->zip->outbuf + cptr->zip->outcount,*length); + cptr->zip->outcount += *length; + } + *length = 0; + + if (!flush && ((cptr->zip->outcount < ZIP_MINIMUM) || + ((cptr->zip->outcount < (ZIP_MAXIMUM - BUFSIZE)) && + CBurst(cptr)))) + return NULL; + + zout->next_in = cptr->zip->outbuf; + zout->avail_in = cptr->zip->outcount; + zout->next_out = zipbuf; + zout->avail_out = ZIP_BUFFER_SIZE; + + switch (r = deflate(zout, Z_PARTIAL_FLUSH)) + { + case Z_OK: + if (zout->avail_in) + { + /* can this occur?? I hope not... */ + sendto_flag(SCH_ERROR, + "deflate() didn't process all available data!"); + } + cptr->zip->outcount = 0; + *length = ZIP_BUFFER_SIZE - zout->avail_out; + return zipbuf; + + default: /* error ! */ + sendto_flag(SCH_ERROR, "deflate() error(%d): %s", r, + (zout->msg) ? zout->msg : "?"); + *length = -1; + break; + } + return NULL; +} + +#endif /* ZIP_LINKS */ diff --git a/ircd/s_zip_ext.h b/ircd/s_zip_ext.h new file mode 100644 index 0000000..6ab86d1 --- /dev/null +++ b/ircd/s_zip_ext.h @@ -0,0 +1,38 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/s_zip_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/s_zip.c. + */ + +/* External definitions for global functions. + */ +#ifndef S_ZIP_C +#define EXTERN extern +#else /* S_ZIP_C */ +#define EXTERN +#endif /* S_ZIP_C */ +#ifdef ZIP_LINKS +EXTERN int zip_init __P((aClient *cptr)); +EXTERN void zip_free __P((aClient *cptr)); +EXTERN char *unzip_packet __P((aClient *cptr, char *buffer, int *length)); +EXTERN char *zip_buffer __P((aClient *cptr, char *buffer, int *length, + int flush)); +#endif /* ZIP_LINKS */ +#undef EXTERN diff --git a/ircd/service_def.h b/ircd/service_def.h new file mode 100644 index 0000000..02a1d9d --- /dev/null +++ b/ircd/service_def.h @@ -0,0 +1,54 @@ + +/* The different things a service can `sniff' */ + +#define SERVICE_WANT_SERVICE 0x00000001 /* other services signing on/off */ +#define SERVICE_WANT_OPER 0x00000002 /* operators, included in _UMODE */ +#define SERVICE_WANT_UMODE 0x00000004 /* user modes, iow + local modes */ +#define SERVICE_WANT_AWAY 0x00000008 /* away isn't propaged anymore.. */ +#define SERVICE_WANT_KILL 0x00000010 /* KILLs */ +#define SERVICE_WANT_NICK 0x00000020 /* all NICKs (new user, change) */ +#define SERVICE_WANT_USER 0x00000040 /* USER signing on */ +#define SERVICE_WANT_QUIT 0x00000080 /* all QUITs (users signing off) */ +#define SERVICE_WANT_SERVER 0x00000100 /* servers signing on */ +#define SERVICE_WANT_WALLOP 0x00000200 /* wallops */ +#define SERVICE_WANT_SQUIT 0x00000400 /* servers signing off */ +#define SERVICE_WANT_RQUIT 0x00000800 /* regular user QUITs (these which + are also sent between servers) */ +#define SERVICE_WANT_MODE 0x00001000 /* channel modes (not +ov) */ +#define SERVICE_WANT_CHANNEL 0x00002000 /* channel creations/destructions */ +#define SERVICE_WANT_VCHANNEL 0x00004000 /* channel joins/parts */ +#define SERVICE_WANT_TOPIC 0x00008000 /* channel topics */ + +#define SERVICE_WANT_ERRORS 0x01000000 /* &ERRORS */ +#define SERVICE_WANT_NOTICES 0x02000000 /* &NOTICES */ +#define SERVICE_WANT_LOCAL 0x04000000 /* &LOCAL */ +#define SERVICE_WANT_NUMERICS 0x08000000 /* &NUMERICS */ + +#define SERVICE_WANT_USERLOG 0x10000000 /* FNAME_USERLOG */ +#define SERVICE_WANT_CONNLOG 0x20000000 /* FNAME_CONNLOG */ + +/* masks */ +#define SERVICE_MASK_GLOBAL 0x00007000 /*for these,service must be global*/ +#define SERVICE_MASK_PREFIX 0x00000FFF /* these actions have a prefix */ +#define SERVICE_MASK_ALL 0x3F00FFFF /* all possible actions */ +#define SERVICE_MASK_NUM (SERVICE_WANT_NICK|SERVICE_WANT_USER|\ + SERVICE_WANT_UMODE) + +/* options */ +#define SERVICE_WANT_PREFIX 0x00010000 /* to receive n!u@h instead of n */ +#define SERVICE_WANT_TOKEN 0x00020000 /* use serv token instead of name */ +#define SERVICE_WANT_EXTNICK 0x00040000 /* user extended NICK syntax */ + +/* A couple example types of services */ +#define SERVICE_ALL SERVICE_MASK_ALL /* 4095 */ +#define SERVICE_NICK SERVICE_WANT_NICK | \ + SERVICE_WANT_QUIT | \ + SERVICE_WANT_AWAY /* 168 */ +#define SERVICE_USERS SERVICE_WANT_NICK | \ + SERVICE_WANT_USER | \ + SERVICE_WANT_QUIT | \ + SERVICE_WANT_AWAY | \ + SERVICE_WANT_UMODE /* 236 */ +#define SERVICE_LINKS SERVICE_WANT_SERVER | \ + SERVICE_WANT_SQUIT | \ + SERVICE_WANT_WALLOP /* 1792 */ diff --git a/ircd/sys_def.h b/ircd/sys_def.h new file mode 100644 index 0000000..72cd68e --- /dev/null +++ b/ircd/sys_def.h @@ -0,0 +1,31 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/sys_def.h + * 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. + */ + +#if defined(DEBUGMODE) && !defined(CLIENT_COMPILE) && \ + !defined(CHKCONF_COMPILE) && defined(DO_DEBUG_MALLOC) +# define free(x) MyFree(x) +#else +# define MyFree(x) if ((x) != NULL) free(x) +#endif + +#define SETSOCKOPT(fd, o1, o2, p1, o3) setsockopt(fd, o1, o2, (char *)p1,\ + (SOCK_LEN_TYPE) sizeof(o3)) + +#define GETSOCKOPT(fd, o1, o2, p1, p2) getsockopt(fd, o1, o2, (char *)p1,\ + (SOCK_LEN_TYPE *)p2) diff --git a/ircd/version.c.SH.in b/ircd/version.c.SH.in new file mode 100644 index 0000000..9bdb9c4 --- /dev/null +++ b/ircd/version.c.SH.in @@ -0,0 +1,113 @@ +#! /bin/sh + +echo "Building 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="`(cd ../ircd; @SUM@ s_serv.c)`" +sumsuser="`(cd ../ircd; @SUM@ s_user.c)`" +sumchan="`(cd ../ircd; @SUM@ channel.c)`" +sumsbsd="`(cd ../ircd; @SUM@ s_bsd.c)`" +sumhash="`(cd ../ircd; @SUM@ hash.c)`" +sumsmisc="`(cd ../ircd; @SUM@ s_misc.c)`" +sumircd="`(cd ../ircd; @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 }}'` + +cat >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. + */ + +#ifndef lint +static char rcsid[] = "@(#)\$Id: version.c.SH.in,v 1.9 1999/07/21 22:59:54 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define VERSION_C +#include "s_externs.h" +#undef VERSION_C + +char *generation = "$generation"; +char *creation = "$creation"; +char *version; /* Filled by make_version() */ +char *pass_version = PATCHLEVEL; + +char *infotext[] = + { + "IRC --", + "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:", + "", + "syrk Christophe Kalt kalt@stealth.net", + "", + "Thanks to the following people for help with preparing 2.10", + "", + "Beeth Piotr Kucharski chopin@sgh.waw.pl", + "Q Kurt Roeckx Q@ping.be", + "Core Magnus Tjernstrom d92-mtm@ludd.luth.se", + "", + "Those who helped in prior versions and continue to be helpful:", + "", + "Jarkko Oikarinen", + "Darren Reed Vesa Ruokonen", + "Matthew Green Chuck Kane Matt Lyle", + "Markku Savela Greg Lindahl Armin Gruner", + "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! diff --git a/ircd/version_ext.h b/ircd/version_ext.h new file mode 100644 index 0000000..5729c6f --- /dev/null +++ b/ircd/version_ext.h @@ -0,0 +1,32 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/version_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/version.c. + */ + +/* External definitions for global variables. + */ +#ifndef VERSION_C +extern char *generation; +extern char *creation; +extern char *version; +extern char *pass_version; +extern char *infotext[]; +#endif /* VERSION_C */ diff --git a/ircd/whowas.c b/ircd/whowas.c new file mode 100644 index 0000000..0dec472 --- /dev/null +++ b/ircd/whowas.c @@ -0,0 +1,464 @@ +/************************************************************************ + * 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 rcsid[] = "@(#)$Id: whowas.c,v 1.6 1999/06/27 19:08:46 kalt Exp $"; +#endif + +#include "os.h" +#include "s_defines.h" +#define WHOWAS_C +#include "s_externs.h" +#undef WHOWAS_C + +static aName *was; +int ww_index = 0, ww_size = MAXCONNECTIONS*2; +static aLock *locked; +int lk_index = 0, lk_size = MAXCONNECTIONS*2; + +static void grow_history() +{ + int osize = ww_size; + + Debug((DEBUG_ERROR, "Whowas/grow_history ww:%d, lk:%d, #%d, %#x/%#x", + ww_size, lk_size, numclients, was, locked)); + ww_size = (int)((float)numclients * 1.1); + was = (aName *)MyRealloc((char *)was, sizeof(*was) * ww_size); + bzero((char *)(was + osize), sizeof(*was) * (ww_size - osize)); + lk_size = (int)((float)numclients * 1.1); + locked = (aLock *)MyRealloc((char *)locked, sizeof(*locked) * lk_size); + bzero((char *)(locked + osize), sizeof(*locked) * (lk_size - osize)); + Debug((DEBUG_ERROR, "Whowas/grow_history %#x/%#x", was, locked)); + ircd_writetune(tunefile); +} + + +/* +** add_history +** Add the currently defined name of the client to history. +** usually called before changing to a new name (nick). +** Client must be a fully registered user (specifically, +** the user structure must have been allocated). +** if nodelay is NULL, then the nickname will be subject to NickDelay +*/ +void add_history(cptr, nodelay) +Reg aClient *cptr, *nodelay; +{ + Reg aName *np; + Reg Link *uwas; + + cptr->user->refcnt++; + + np = &was[ww_index]; + + if ((np->ww_online && (np->ww_online != &me)) + && !(np->ww_user && np->ww_user->uwas)) +#ifdef DEBUGMODE + dumpcore("whowas[%d] %#x %#x %#x", ww_index, np->ww_online, + np->ww_user, np->ww_user->uwas); +#else + sendto_flag(SCH_ERROR, "whowas[%d] %#x %#x %#x", ww_index, + np->ww_online, np->ww_user, np->ww_user->uwas); +#endif + /* + ** The entry to be overwritten in was[] is still online. + ** its uwas has to be updated + */ + if (np->ww_online && (np->ww_online != &me)) + { + Reg Link **old_uwas; + + old_uwas = &(np->ww_user->uwas); + /* (*old_uwas) should NEVER happen to be NULL. -krys */ + while ((*old_uwas)->value.i != ww_index) + old_uwas = &((*old_uwas)->next); + uwas = *old_uwas; + *old_uwas = uwas->next; + free_link(uwas); + free_user(np->ww_user, np->ww_online); + istat.is_wwuwas--; + } + else if (np->ww_user) + { + /* + ** Testing refcnt here is quite ugly, and unexact. + ** Nonetheless, the result is almost correct, and another + ** ugly thing in free_server() shoud make it exact. + ** The problem is that 1 anUser structure might be + ** referenced several times from whowas[] but is only counted + ** once. One knows when to add, not when to substract - krys + */ + if (np->ww_user->refcnt == 1) + { + istat.is_wwusers--; + if (np->ww_user->away) + { + istat.is_wwaways--; + istat.is_wwawaysmem -=strlen(np->ww_user->away) + + 1; + } + } + free_user(np->ww_user, NULL); + } + + if (np->ww_logout != 0) + { + int elapsed = timeofday - np->ww_logout; + + /* some stats */ + ircstp->is_wwcnt++; + ircstp->is_wwt += elapsed; + if (elapsed < ircstp->is_wwmt) + ircstp->is_wwmt = elapsed; + if (elapsed > ircstp->is_wwMt) + ircstp->is_wwMt = elapsed; + + if (np->ww_online == NULL) + { + if (locked[lk_index].logout) + { + elapsed = timeofday - locked[lk_index].logout; + /* some stats first */ + ircstp->is_lkcnt++; + ircstp->is_lkt += elapsed; + if (elapsed < ircstp->is_lkmt) + ircstp->is_lkmt = elapsed; + if (elapsed > ircstp->is_lkMt) + ircstp->is_lkMt = elapsed; + } + + /* + ** This nickname has to be locked, thus copy it to the + ** lock[] array. + */ + strncpyzt(locked[lk_index].nick, np->ww_nick, NICKLEN); + locked[lk_index++].logout = np->ww_logout; + if (lk_index >= lk_size) + lk_index = 0; + } + } + + if (nodelay == cptr) /* &me is NOT a valid value, see off_history() */ + { + /* + ** The client is online, np->ww_online is going to point to + ** it. The client user struct has to point to this entry + ** as well for faster off_history() + ** this uwas, and the ww_online form a pair. + */ + uwas = make_link(); + istat.is_wwuwas++; + /* + ** because of reallocs, one can not store a pointer inside + ** the array. store the index instead. + */ + uwas->value.i = ww_index; + uwas->flags = timeofday; + uwas->next = cptr->user->uwas; + cptr->user->uwas = uwas; + } + + np->ww_logout = timeofday; + np->ww_user = cptr->user; + np->ww_online = (nodelay != NULL) ? nodelay : NULL; + + strncpyzt(np->ww_nick, cptr->name, NICKLEN+1); + strncpyzt(np->ww_info, cptr->info, REALLEN+1); + + ww_index++; + if ((ww_index == ww_size) && (numclients > ww_size)) + grow_history(); + if (ww_index >= ww_size) + 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; +{ + Reg aName *wp, *wp2; + Reg int i = 0; + + wp = wp2 = &was[ww_index]; + timelimit = timeofday - timelimit; + + do { + if (!mycmp(nick, wp->ww_nick) && wp->ww_logout >= timelimit) + break; + wp++; + if (wp == &was[ww_size]) + i = 1, wp = was; + } while (wp != wp2); + + if (wp != wp2 || !i) + if (wp->ww_online == &me) + return (NULL); + else + return (wp->ww_online); + return (NULL); +} + +/* +** find_history +** Returns 1 if a user was using the given nickname within +** the timelimit. Returns 0, if none found... +*/ +int find_history(nick, timelimit) +char *nick; +time_t timelimit; +{ + Reg aName *wp, *wp2; + Reg aLock *lp, *lp2; + Reg int i = 0; + + wp = wp2 = &was[ww_index]; +#ifdef RANDOM_NDELAY + timelimit = timeofday - timelimit - (lk_index % 60); +#else + timelimit = timeofday - timelimit; +#endif + + do { + if (!mycmp(nick, wp->ww_nick) && + (wp->ww_logout >= timelimit) && (wp->ww_online == NULL)) + break; + wp++; + if (wp == &was[ww_size]) + i = 1, wp = was; + } while (wp != wp2); + if ((wp != wp2 || !i) && (wp->ww_online == NULL)) + return (1); + + lp = lp2 = &locked[lk_index]; + i = 0; + do { + if (!myncmp(nick, lp->nick, NICKLEN) && + (lp->logout >= timelimit)) + break; + lp++; + if (lp == &locked[lk_size]) + i = 1, lp = locked; + } while (lp != lp2); + if (lp != lp2 || !i) + return (1); + + return (0); +} + +/* +** off_history +** This must be called when the client structure is about to +** be released. History mechanism keeps pointers to client +** structures and it must know when they cease to exist. This +** also implicitly calls AddHistory. +*/ +void off_history(cptr) +Reg aClient *cptr; +{ + Reg Link *uwas; + + /* + ** If the client has uwas entry/ies, there are also entries in + ** the whowas array which point back to it. + ** They have to be removed, by pairs + */ + while ((uwas = cptr->user->uwas)) + { + if (was[uwas->value.i].ww_online != cptr) +#ifdef DEBUGMODE + dumpcore("was[%d]: %#x != %#x", uwas->value.i, + was[uwas->value.i].ww_online, cptr); +#else + sendto_flag(SCH_ERROR, "was[%d]: %#x != %#x", + uwas->value.i, + was[uwas->value.i].ww_online, cptr); +#endif + /* + ** using &me to make ww_online non NULL (nicknames to be + ** locked). &me can safely be used, it is constant. + */ + was[uwas->value.i].ww_online = &me; + cptr->user->uwas = uwas->next; + free_link(uwas); + istat.is_wwuwas--; + } + + istat.is_wwusers++; + if (cptr->user->away) + { + istat.is_wwaways++; + istat.is_wwawaysmem += strlen(cptr->user->away) + 1; + } + + return; +} + +void initwhowas() +{ + Reg int i; + + was = (aName *)MyMalloc(sizeof(*was) * ww_size); + + for (i = 0; i < ww_size; i++) + bzero((char *)&was[i], sizeof(aName)); + locked = (aLock *)MyMalloc(sizeof(*locked) * lk_size); + for (i = 0; i < lk_size; i++) + bzero((char *)&locked[i], sizeof(aLock)); + + ircstp->is_wwmt = ircstp->is_lkmt = DELAYCHASETIMELIMIT + * DELAYCHASETIMELIMIT; + return; +} + + +/* +** m_whowas +** parv[0] = sender prefix +** parv[1] = nickname queried +*/ +int m_whowas(cptr, sptr, parc, parv) +aClient *cptr, *sptr; +int parc; +char *parv[]; +{ + Reg aName *wp, *wp2 = NULL; + Reg int j = 0; + Reg anUser *up = NULL; + int max = -1; + char *p, *nick, *s; + + if (parc < 2) + { + sendto_one(sptr, err_str(ERR_NONICKNAMEGIVEN, parv[0])); + return 1; + } + if (parc > 2) + max = atoi(parv[2]); + if (parc > 3) + if (hunt_server(cptr,sptr,":%s WHOWAS %s %s :%s", 3,parc,parv)) + return 3; + + parv[1] = canonize(parv[1]); + if (!MyConnect(sptr)) + max = MIN(max, 20); + + for (s = parv[1]; (nick = strtoken(&p, s, ",")); s = NULL) + { + wp = wp2 = &was[ww_index - 1]; + + do { + if (wp < was) + wp = &was[ww_size - 1]; + if (mycmp(nick, wp->ww_nick) == 0) + { + up = wp->ww_user; + sendto_one(sptr, rpl_str(RPL_WHOWASUSER, + parv[0]), wp->ww_nick, up->username, + up->host, wp->ww_info); + sendto_one(sptr, rpl_str(RPL_WHOISSERVER, + parv[0]), wp->ww_nick, up->server, + myctime(wp->ww_logout)); + if (up->away) + sendto_one(sptr, rpl_str(RPL_AWAY, + parv[0]), + wp->ww_nick, up->away); + j++; + } + if (max > 0 && j >= max) + break; + wp--; + } while (wp != wp2); + + if (up == NULL) + { + if (strlen(parv[1]) > (size_t) NICKLEN) + parv[1][NICKLEN] = '\0'; + sendto_one(sptr, err_str(ERR_WASNOSUCHNICK, parv[0]), + parv[1]); + } + + if (p) + p[-1] = ','; + } + sendto_one(sptr, rpl_str(RPL_ENDOFWHOWAS, parv[0]), parv[1]); + return 2; + } + + +/* +** for debugging...counts related structures stored in whowas array. +*/ +void count_whowas_memory(wwu, wwa, wwam, wwuw) +int *wwu, *wwa, *wwuw; +u_long *wwam; +{ + Reg anUser *tmp; + Reg Link *tmpl; + Reg int i, j; + int u = 0, a = 0, w = 0; + u_long am = 0; + + for (i = 0; i < ww_size; i++) + if ((tmp = was[i].ww_user)) + { + for (j = 0; j < i; j++) + if (was[j].ww_user == tmp) + break; + if (j < i) + continue; + if (was[i].ww_online == NULL || + was[i].ww_online == &me) + { + u++; + if (tmp->away) + { + a++; + am += (strlen(tmp->away)+1); + } + } + else + { + tmpl = tmp->uwas; + while (tmpl) + { + w++; + tmpl = tmpl->next; + } + } + } + *wwu = u; + *wwa = a; + *wwam = am; + *wwuw = w; + + return; +} diff --git a/ircd/whowas_def.h b/ircd/whowas_def.h new file mode 100644 index 0000000..d1ba12f --- /dev/null +++ b/ircd/whowas_def.h @@ -0,0 +1,34 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/whowas_def.h + * 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. + */ + +/* +** WHOWAS structure moved here from whowas.c +*/ +typedef struct aname { + anUser *ww_user; + aClient *ww_online; + time_t ww_logout; + char ww_nick[NICKLEN+1]; + char ww_info[REALLEN+1]; +} aName; + +typedef struct alock { + time_t logout; + char nick[NICKLEN]; +} aLock; diff --git a/ircd/whowas_ext.h b/ircd/whowas_ext.h new file mode 100644 index 0000000..f65d437 --- /dev/null +++ b/ircd/whowas_ext.h @@ -0,0 +1,47 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/whowas_ext.h + * Copyright (C) 1997 Alain Nissen + * + * 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 contains external definitions for global variables and functions + defined in ircd/whowas.c. + */ + +/* External definitions for global variables. + */ +#ifndef WHOWAS_C +extern int ww_index, ww_size; +extern int lk_index, lk_size; +#endif /* WHOWAS_C */ + +/* External definitions for global functions. + */ +#ifndef WHOWAS_C +#define EXTERN extern +#else /* WHOWAS_C */ +#define EXTERN +#endif /* WHOWAS_C */ +EXTERN void add_history __P((Reg aClient *cptr, Reg aClient *nodelay)); +EXTERN aClient *get_history __P((char *nick, time_t timelimit)); +EXTERN int find_history __P((char *nick, time_t timelimit)); +EXTERN void off_history __P((Reg aClient *cptr)); +EXTERN void initwhowas(); +EXTERN int m_whowas __P((aClient *cptr, aClient *sptr, int parc, + char *parv[])); +EXTERN void count_whowas_memory __P((int *wwu, int *wwa, u_long *wwam, + int *wwuw)); +#undef EXTERN diff --git a/support/Makefile.in b/support/Makefile.in new file mode 100644 index 0000000..1cebf69 --- /dev/null +++ b/support/Makefile.in @@ -0,0 +1,488 @@ +#************************************************************************ +#* IRC - Internet Relay Chat, 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. +#* +#* $Id: Makefile.in,v 1.45 1999/07/22 12:17:15 kalt Exp $ +#* +#*/ + +# ------------------------------------------------------------------------- +# Start of system configuration section. +# +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +# compiler program +CC = @CC@ +# compiler flags used for the server +S_CFLAGS = @CFLAGS@ -I. -I../ircd -I../common @IRC_ZLIB_INCLUDE@ +# compiler flags used for the authentication slave +A_CFLAGS = @CFLAGS@ -I. -I../iauth -I../common @IRC_ZLIB_INCLUDE@ +# compiler flags used for chkconfig +CC_CFLAGS = @CFLAGS@ -I. -I../ircd -I../common +# compiler flags used for the client +C_CFLAGS = @CFLAGS@ -I. -I../irc -I../common +# compiler flags used for other things (in contrib/) +O_CFLAGS = @CFLAGS@ -I. -I../common -DCONTRIB_COMPILE +# linker flags +LDFLAGS = @LDFLAGS@ +# required libraries, except zlib and curses/termcap +LIBS = @LIBS@ +MATHLIBS = -lm +# zlib, eventually +ZLIBS = @IRC_ZLIB_LIBRARY@ +# for DSM support (dlopen(), dlsym(), dlclose()) +DLIBS = @IRC_DLIB@ +# curses library +CURSESLIBS = @IRC_CURSES_TERMCAP_LIBRARY@ +# install and related programs +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +MKDIRHIER = ../support/mkdirhier + +# +# Binary names +# +CLIENT = irc +SERVER = ircd +IAUTH = iauth +IRCDWATCH = ircdwatch + +# +# Directories definitions +# +# Directory in which to install irc. +client_bin_dir = @bindir@ +# Directory in which to install ircd, iauth, ircdwatch, mkpasswd and chkconf. +server_bin_dir = @sbindir@ +# Directory in which to install the client manual page. +client_man_dir = @mandir@/man1 +# Directory in which to install the configuration manual page. +conf_man_dir = @mandir@/man5 +# Directory in which to install the server manual page. +server_man_dir = @mandir@/man8 +# Directory where config files (ircd.conf, ircd.motd and iauth.conf) live. +ircd_conf_dir = @sysconfdir@ +# Directory where state files (ircd.pid, ircd.tune) live. +ircd_var_dir = @localstatedir@ +# Directory where log files (users, opers, rejects and auth) live. +ircd_log_dir = @logdir@ + +# +# Most of these PATHs are hardcoded in the binaries. +# They should all be absolute. +# +# Path to server binary +IRCD_PATH = $(server_bin_dir)/$(SERVER) +# Path to authentification slave binary +IAUTH_PATH = $(server_bin_dir)/$(IAUTH) +# Path to the m4 configuration file +IRCDM4_PATH = $(ircd_conf_dir)/ircd.m4 + +# server configuration file +IRCDCONF_PATH = $(ircd_conf_dir)/ircd.conf +# server Message Of The Day +IRCDMOTD_PATH = $(ircd_conf_dir)/ircd.motd +# authentication slave configuration file +IAUTHCONF_PATH = $(ircd_conf_dir)/iauth.conf +# server PID file +IRCDPID_PATH = $(ircd_var_dir)/ircd.pid +# server state file +IRCDTUNE_PATH = $(ircd_var_dir)/ircd.tune +# ircdwatch PID file +IRCDWATCHPID_PATH = $(ircd_var_dir)/ircdwatch.pid + +# Define these filenames to maintain a list of persons who log +# into this server. Logging will stop when the file does not exist. +# Logging will be disabled also if you do not define this. +FNAME_USERLOG = $(ircd_log_dir)/users +FNAME_OPERLOG = $(ircd_log_dir)/opers +FNAME_CONNLOG = $(ircd_log_dir)/rejects +FNAME_AUTHLOG = $(ircd_log_dir)/auth + +# files used for debugging purposes +IRCDDBG_PATH = $(ircd_log_dir)/ircd.log +IAUTHDBG_PATH = $(ircd_log_dir)/iauth.log + +# Access mode for irc. +irc_mode = 755 + +# Access mode for ircd. +ircd_mode = 711 + +# +# TK line service configuration +# +# TK line service binary +TKSERV = tkserv +# TK line service logfile +TKSERV_LOGFILE = $(ircd_log_dir)/tkserv.log +# TK line service access file +TKSERV_ACCESSFILE = $(ircd_conf_dir)/tkserv.access +# IRCD config file without path (from CPATH) +TKSERV_IRCD_CONF = ircd.conf + +# End of system configuration section. +# ------------------------------------------------------------------------ +# Please don't change anything below this point - no need really - I hope. + +RM = rm -f + +CLIENT_COMMON_OBJS = clbsd.o cldbuf.o clpacket.o clsend.o clmatch.o \ + clparse.o clsupport.o +CLIENT_OBJS = c_bsd.o c_msg.o c_numeric.o c_version.o edit.o help.o \ + ignore.o irc.o screen.o str.o swear.o c_debug.o ctcp.o + +SERVER_COMMON_OBJS = bsd.o dbuf.o packet.o send.o match.o parse.o \ + support.o +SERVER_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_id.o s_misc.o s_numeric.o \ + s_serv.o s_service.o s_user.o s_zip.o whowas.o \ + res_init.o res_comp.o res_mkquery.o + +IAUTH_COMMON_OBJS = clsupport.o clmatch.o # This is a little evil +IAUTH_OBJS = iauth.o a_conf.o a_io.o a_log.o \ + mod_lhex.o mod_pipe.o mod_rfc931.o mod_socks.o +IAUTH = iauth + +CHKCONF_COMMON_OBJS = match.o +CHKCONF_OBJS = chkconf.o +CHKCONF = chkconf + +help: + @echo "Choose one of the following:" + @echo " all : build everything" + @echo " server : build server programs" + @echo " ircd : build the irc daemon" + @echo " iauth : build the authentication slave" + @echo " chkconf : build the configuration file checker" + @echo " ircd-mkpasswd : build ircd-mkpasswd" + @echo " ircdwatch : build ircdwatch" + @echo " client : build the client" + @echo " $(TKSERV) : build tkserv" + @echo + @echo " install : build and install server and client programs" + @echo " install-server : build and install server programs" + @echo " install-client : build and install client program" + @echo " install-tkserv : build and install tkserv" + +all: server client + +server: $(SERVER) $(IAUTH) $(CHKCONF) ircd-mkpasswd $(IRCDWATCH) + +client: $(CLIENT) + +$(SERVER): $(SERVER_COMMON_OBJS) $(SERVER_OBJS) + $(RM) $@ + ./version.c.SH + $(CC) $(S_CFLAGS) -c -o version.o version.c + $(CC) $(LDFLAGS) -o $@ $(SERVER_COMMON_OBJS) version.o $(SERVER_OBJS) $(ZLIBS) $(MATHLIBS) $(LIBS) + +$(IAUTH): $(IAUTH_COMMON_OBJS) $(IAUTH_OBJS) + $(RM) $@ + $(CC) $(LDFLAGS) -o $@ $(IAUTH_COMMON_OBJS) $(IAUTH_OBJS) $(LIBS) $(DLIBS) + +$(CLIENT): $(CLIENT_COMMON_OBJS) $(CLIENT_OBJS) + $(RM) $@ + $(CC) $(LDFLAGS) -o $@ $(CLIENT_COMMON_OBJS) $(CLIENT_OBJS) $(CURSESLIBS) $(LIBS) + +$(CHKCONF): $(CHKCONF_COMMON_OBJS) $(CHKCONF_OBJS) + $(RM) $@ + $(CC) $(LDFLAGS) -o $@ $(CHKCONF_COMMON_OBJS) $(CHKCONF_OBJS) $(LIBS) + +# stuff in contrib/ + +$(IRCDWATCH): ircdwatch.o clsupport.o clmatch.o + $(RM) $(IRCDWATCH) + $(CC) -o $(IRCDWATCH) clsupport.o clmatch.o ircdwatch.o + +ircd-mkpasswd: mkpasswd.o + $(RM) ircd-mkpasswd + $(CC) $(LDFLAGS) -o ircd-mkpasswd mkpasswd.o $(LIBS) + +$(TKSERV): tkserv.o + $(RM) $(TKSERV) + $(CC) $(LDFLAGS) -o $(TKSERV) tkserv.o $(LIBS) + +install: install-server install-client + +install-client: client + -@if [ ! -d $(client_bin_dir) ]; then \ + $(MKDIRHIER) $(client_bin_dir); \ + fi + -@if [ ! -d $(client_man_dir) ]; then \ + $(MKDIRHIER) $(client_man_dir); \ + fi + $(INSTALL_PROGRAM) -m $(irc_mode) $(CLIENT) $(client_bin_dir) + (cd ../doc; $(INSTALL_DATA) irc.1 $(client_man_dir)) + @echo "installation of client done." + +install-server: server + -@if [ ! -d $(server_bin_dir) ]; then \ + $(MKDIRHIER) $(server_bin_dir); \ + fi + -@if [ ! -d $(server_man_dir) ]; then \ + $(MKDIRHIER) $(server_man_dir); \ + fi + -@if [ ! -d $(conf_man_dir) ]; then \ + $(MKDIRHIER) $(conf_man_dir); \ + fi + -@if [ ! -d $(ircd_conf_dir) ]; then \ + $(MKDIRHIER) $(ircd_conf_dir); \ + fi + -@if [ ! -d $(ircd_var_dir) ]; then \ + $(MKDIRHIER) $(ircd_var_dir); \ + fi + -@if [ ! -d $(ircd_log_dir) ]; then \ + $(MKDIRHIER) $(ircd_log_dir); \ + fi + $(INSTALL_PROGRAM) -m $(ircd_mode) $(SERVER) $(server_bin_dir) + $(INSTALL_PROGRAM) -m $(ircd_mode) $(IAUTH) $(server_bin_dir) + $(INSTALL_PROGRAM) -m $(ircd_mode) $(CHKCONF) $(server_bin_dir) + $(INSTALL_PROGRAM) -m $(ircd_mode) ircd-mkpasswd $(server_bin_dir) + $(INSTALL_PROGRAM) -m $(ircd_mode) $(IRCDWATCH) $(server_bin_dir) + $(RM) $(IRCDM4_PATH) + ../ircd/buildm4 $(IRCDM4_PATH) + $(INSTALL_DATA) ../doc/ircd.8 $(server_man_dir) + $(INSTALL_DATA) ../doc/iauth.8 $(server_man_dir) + $(INSTALL_DATA) ../doc/iauth.conf.5 $(conf_man_dir) + $(INSTALL_DATA) ../contrib/ircdwatch/ircdwatch.8 $(server_man_dir) + $(INSTALL_DATA) ../doc/example.conf $(ircd_conf_dir) + -@if [ ! -f $(IAUTHCONF_PATH) ]; then \ + $(INSTALL_DATA) ../support/iauth.conf $(IAUTHCONF_PATH); \ + fi + @echo "installation of server done." + +install-tkserv: $(TKSERV) + -@if [ ! -d $(server_bin_dir) ]; then \ + $(MKDIRHIER) $(server_bin_dir); \ + fi + -@if [ ! -d $(ircd_conf_dir) ]; then \ + $(MKDIRHIER) $(ircd_conf_dir); \ + fi + $(INSTALL_PROGRAM) -m $(ircd_mode) $(TKSERV) $(server_bin_dir) + @echo "installation of client done." + +clbsd.o: ../common/bsd.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/bsd.c + +cldbuf.o: ../common/dbuf.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/dbuf.c + +clpacket.o: ../common/packet.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/packet.c + +clsend.o: ../common/send.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/send.c + +clmatch.o: ../common/match.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/match.c + +clparse.o: ../common/parse.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/parse.c + +clsupport.o: ../common/support.c setup.h config.h ../common/patchlevel.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../common/support.c + +c_bsd.o: ../irc/c_bsd.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_bsd.c + +c_msg.o: ../irc/c_msg.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_msg.c + +c_numeric.o: ../irc/c_numeric.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_numeric.c + +c_version.o: ../irc/c_version.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_version.c + +edit.o: ../irc/edit.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/edit.c + +help.o: ../irc/help.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/help.c + +ignore.o: ../irc/ignore.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/ignore.c + +irc.o: ../irc/irc.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/irc.c + +screen.o: ../irc/screen.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/screen.c + +str.o: ../irc/str.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/str.c + +swear.o: ../irc/swear.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/swear.c + +c_debug.o: ../irc/c_debug.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/c_debug.c + +ctcp.o: ../irc/ctcp.c setup.h config.h + $(CC) $(C_CFLAGS) -DCLIENT_COMPILE -c -o $@ ../irc/ctcp.c + +bsd.o: ../common/bsd.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../common/bsd.c + +dbuf.o: ../common/dbuf.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../common/dbuf.c + +packet.o: ../common/packet.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../common/packet.c + +send.o: ../common/send.c setup.h config.h + $(CC) $(S_CFLAGS) -DFNAME_USERLOG="\"$(FNAME_USERLOG)\"" -DFNAME_CONNLOG="\"$(FNAME_CONNLOG)\"" -c -o $@ ../common/send.c + +match.o: ../common/match.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../common/match.c + +parse.o: ../common/parse.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../common/parse.c + +support.o: ../common/support.c setup.h config.h ../common/patchlevel.h + $(CC) $(S_CFLAGS) -c -o $@ ../common/support.c + +channel.o: ../ircd/channel.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/channel.c + +class.o: ../ircd/class.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/class.c + +hash.o: ../common/struct_def.h ../common/os.h ../ircd/hash_def.h \ + ../ircd/hash_ext.h ../common/common_def.h ../ircd/s_bsd.c \ + ../ircd/s_serv.c ../ircd/s_user.c ../ircd/channel.c ../ircd/s_misc.c \ + ../ircd/hash.c ../ircd/ircd.c Makefile setup.h config.h + @cp ../ircd/hash.c . + @/bin/sh ./sums + $(CC) $(S_CFLAGS) -c -o $@ hash.c + @$(RM) hash.c hash.c.old + @touch hash.o + +ircd.o: ../ircd/ircd.c setup.h config.h + $(CC) $(S_CFLAGS) -DIRCDCONF_PATH="\"$(IRCDCONF_PATH)\"" \ + -DIRCDTUNE_PATH="\"$(IRCDTUNE_PATH)\"" \ + -DIRCDMOTD_PATH="\"$(IRCDMOTD_PATH)\"" \ + -DIRCD_PATH="\"$(IRCD_PATH)\"" -DIAUTH_PATH="\"$(IAUTH_PATH)\"" \ + -DIAUTH="\"$(IAUTH)\"" -DIRCDDBG_PATH="\"$(IRCDDBG_PATH)\"" \ + -c -o $@ ../ircd/ircd.c + +list.o: ../ircd/list.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/list.c + +res.o: ../ircd/res.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res.c + +s_auth.o: ../ircd/s_auth.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_auth.c + +s_bsd.o: ../ircd/s_bsd.c setup.h config.h + $(CC) $(S_CFLAGS) -DIRCDPID_PATH="\"$(IRCDPID_PATH)\"" -DIAUTH_PATH="\"$(IAUTH_PATH)\"" -DIAUTH="\"$(IAUTH)\"" -c -o $@ ../ircd/s_bsd.c + +s_conf.o: ../ircd/s_conf.c setup.h config.h + $(CC) $(S_CFLAGS) -DIRCDMOTD_PATH="\"$(IRCDMOTD_PATH)\"" -DIRCDM4_PATH="\"$(IRCDM4_PATH)\"" -c -o $@ ../ircd/s_conf.c + +s_debug.o: ../ircd/s_debug.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_debug.c + +s_err.o: ../ircd/s_err.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_err.c + +s_id.o: ../ircd/s_id.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_id.c + +s_misc.o: ../ircd/s_misc.c setup.h config.h + $(CC) $(S_CFLAGS) -DFNAME_USERLOG="\"$(FNAME_USERLOG)\"" -DFNAME_CONNLOG="\"$(FNAME_CONNLOG)\"" -c -o $@ ../ircd/s_misc.c + +s_numeric.o: ../ircd/s_numeric.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_numeric.c + +s_serv.o: ../ircd/s_serv.c setup.h config.h + $(CC) $(S_CFLAGS) -DIRCDMOTD_PATH="\"$(IRCDMOTD_PATH)\"" -c -o $@ ../ircd/s_serv.c + +s_service.o: ../ircd/s_service.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_service.c + +s_user.o: ../ircd/s_user.c setup.h config.h + $(CC) $(S_CFLAGS) -DFNAME_USERLOG="\"$(FNAME_USERLOG)\"" -DFNAME_CONNLOG="\"$(FNAME_CONNLOG)\"" -DFNAME_OPERLOG="\"$(FNAME_OPERLOG)\"" -c -o $@ ../ircd/s_user.c + +s_zip.o: ../ircd/s_zip.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/s_zip.c + +whowas.o: ../ircd/whowas.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/whowas.c + +res_init.o: ../ircd/res_init.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_init.c + +res_comp.o: ../ircd/res_comp.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_comp.c + +res_mkquery.o: ../ircd/res_mkquery.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_mkquery.c + +iauth.o: ../iauth/iauth.c config.h setup.h + $(CC) $(A_CFLAGS) -c -o $@ ../iauth/iauth.c + +a_conf.o: ../iauth/a_conf.c config.h setup.h + $(CC) $(A_CFLAGS) -DIAUTHCONF_PATH="\"$(IAUTHCONF_PATH)\"" -c -o $@ ../iauth/a_conf.c + +a_dyn.o: ../iauth/a_dyn.c config.h setup.h + $(CC) $(A_CFLAGS) -c -o $@ ../iauth/a_dyn.c + +a_io.o: ../iauth/a_io.c config.h setup.h + $(CC) $(A_CFLAGS) -c -o $@ ../iauth/a_io.c + +a_log.o: ../iauth/a_log.c config.h setup.h + $(CC) $(A_CFLAGS) -DIAUTHDBG_PATH="\"$(IAUTHDBG_PATH)\"" -DFNAME_AUTHLOG="\"$(FNAME_AUTHLOG)\"" -c -o $@ ../iauth/a_log.c + +mod_lhex.o: ../iauth/mod_lhex.c config.h setup.h + $(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_lhex.c + +mod_pipe.o: ../iauth/mod_pipe.c config.h setup.h + $(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_pipe.c + +mod_rfc931.o: ../iauth/mod_rfc931.c config.h setup.h + $(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_rfc931.c + +mod_socks.o: ../iauth/mod_socks.c config.h setup.h + $(CC) $(A_CFLAGS) -c -o $@ ../iauth/mod_socks.c + +chkconf.o: ../ircd/chkconf.c setup.h config.h + $(CC) $(CC_CFLAGS) -DCHKCONF_COMPILE -DIRCDCONF_PATH="\"$(IRCDCONF_PATH)\"" -DIRCDM4_PATH="\"$(IRCDM4_PATH)\"" -c -o $@ ../ircd/chkconf.c + +# stuff in contrib/ + +ircdwatch.o: ../contrib/ircdwatch/ircdwatch.c + $(CC) $(O_CFLAGS) -DIRCDWATCH_PID_FILENAME="\"$(IRCDWATCHPID_PATH)\"" -DIRCD_PATH="\"$(IRCD_PATH)\"" -DIRCDCONF_PATH="\"$(IRCDCONF_PATH)\"" -DIRCDPID_PATH="\"$(IRCDPID_PATH)\"" -c -o $@ ../contrib/ircdwatch/ircdwatch.c + +mkpasswd.o: ../contrib/mkpasswd/mkpasswd.c + $(CC) $(O_CFLAGS) -c -o $@ ../contrib/mkpasswd/mkpasswd.c + +tkserv.o: ../contrib/tkserv/tkserv.c tkconf.h + $(CC) $(O_CFLAGS) -DTKSERV_LOGFILE="\"$(TKSERV_LOGFILE)\"" -DTKSERV_ACCESSFILE="\"$(TKSERV_ACCESSFILE)\"" -DTKSERV_IRCD_CONF="\"$(TKSERV_IRCD_CONF)\"" -DCPATH="\"$(IRCDCONF_PATH)\"" -DPPATH="\"$(IRCDPID_PATH)\"" -c -o $@ ../contrib/tkserv/tkserv.c + +clean: + $(RM) $(CLIENT) $(SERVER) $(IAUTH) $(CHKCONF) ircd-mkpasswd $(IRCDWATCH) $(TKSERV) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut "#"* version.c + +distclean: + @echo "To make distclean, just delete the current directory." + +rcs: + (cd ..; cii -H -R configure common doc include irc ircd support) diff --git a/support/acconfig.h b/support/acconfig.h new file mode 100644 index 0000000..6372a57 --- /dev/null +++ b/support/acconfig.h @@ -0,0 +1,101 @@ +/* $Id: acconfig.h,v 1.9 1999/03/10 00:30:17 kalt Exp $ */ + +/* Define if zlib package must be used for compilation/linking. */ +#undef USE_ZLIB + +/* Define if ncurses library must be used for compilation/linking. */ +#undef USE_NCURSES + +/* Define if cursesX library must be used for compilation/linking. */ +#undef USE_CURSESX + +/* Define if curses library must be used for compilation/linking. */ +#undef USE_CURSES + +/* Define if termcap library must be used for compilation/linking. */ +#undef USE_TERMCAP + +/* Define if the second argument of waitpid must be an "union wait *" instead + of an "int *". */ +#undef USE_UNION_WAIT + +/* Define if int8_t, u_int8_t, int16_t, u_int16_t, int32_t, u_int32_t, u_char, + * u_short, u_int, u_long are not known types. */ +#undef int8_t +#undef u_int8_t +#undef int16_t +#undef u_int16_t +#undef int32_t +#undef u_int32_t +#undef u_char +#undef u_short +#undef u_int +#undef u_long + +/* Define if memcmp is not 8-bit clean. */ +#undef MEMCMP_BROKEN + +/* Define if the operating system is AIX 3.2. */ +#undef AIX_3_2 + +/* Define if the operating system is Solaris 2.x (SunOS 5.x). */ +#undef SOLARIS_2 + +/* Define if the operating system is Solaris 2.3 (SunOS 5.3). */ +#undef SOLARIS_2_3 + +/* Define if the operating system is Solaris 2.[0-2] (SunOS 5.[0-2]). */ +#undef SOLARIS_2_0_2_1_2_2 + +/* Define if <netdb.h> contains bad __const usages (Linux). */ +#undef BAD___CONST_NETDB_H + +/* Define if sys_errlist is declared in stdio.h or errno.h. */ +#undef SYS_ERRLIST_DECLARED + +/* Define if sys_nerr is declared in stdio.h or errno.h. */ +#undef SYS_NERR_DECLARED + +/* Define if errno is declared in errno.h. */ +#undef ERRNO_DECLARED + +/* Define if h_errno is declared in errno.h or netdb.h. */ +#undef H_ERRNO_DECLARED + +/* Define if poll(2) must be used instead of select(2). */ +/* Note: some systems (e.g. linux 2.0.x) have a non-working poll() */ +#undef USE_POLL + +/* Define if the system provides POSIX sigaction. */ +#undef POSIX_SIGNALS + +/* Define if the system provides reliable BSD signals through sigset instead + of signal. */ +/* #define signal sigset */ + +/* Define if the system provides reliable BSD signals. */ +#undef BSD_RELIABLE_SIGNALS + +/* Define if the system provides unreliable SystemV signals. */ +#undef SYSV_UNRELIABLE_SIGNALS + +/* Define if the system provides POSIX non-blocking system. */ +#undef NBLOCK_POSIX + +/* Define if the system provides BSD non-blocking system. */ +#undef NBLOCK_BSD + +/* Define if the system provides SystemV non-blocking system. */ +#undef NBLOCK_SYSV + +/* Define is the system can use variable arguments. */ +#undef USE_STDARG + +/* Define as the resolver configuration file. */ +#undef IRC_RESCONF + +/* Define to enable IPv6 support */ +#undef INET6 + +/* Define to enable dynamically shared iauth module support */ +#undef USE_DSM diff --git a/support/config.guess b/support/config.guess new file mode 100755 index 0000000..b8bc3ba --- /dev/null +++ b/support/config.guess @@ -0,0 +1,954 @@ +#! /bin/sh +# +# $Id: config.guess,v 1.4 1999/01/18 00:24:17 kalt Exp $ +# +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 93, 94, 95, 96, 97, 1998 Free Software Foundation, Inc. +# +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Written by Per Bothner <bothner@cygnus.com>. +# The master version of this file is at the FSF in /home/gd/gnu/lib. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit system type (host/target name). +# +# Only a few systems have been added to this list; please add others +# (but try to keep the structure clean). +# + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 8/24/94.) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15 + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + alpha:OSF1:*:*) + if test $UNAME_RELEASE = "V4.0"; then + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + fi + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + cat <<EOF >dummy.s + .globl main + .ent main +main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//' | tr [[A-Z]] [[a-z]]` + exit 0 ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit 0 ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-cbm-sysv4 + exit 0;; + amiga:NetBSD:*:*) + echo m68k-cbm-netbsd${UNAME_RELEASE} + exit 0 ;; + amiga:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit 0 ;; + arc64:OpenBSD:*:*) + echo mips64el-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + hkmips:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + pmax:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sgi:OpenBSD:*:*) + echo mips-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + wgrisc:OpenBSD:*:*) + echo mipsel-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit 0;; + arm32:NetBSD:*:*) + echo arm-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + SR2?01:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit 0;; + Pyramid*:OSx*:*:*|MIS*:OSx*:*:*|MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit 0 ;; + NILE:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit 0 ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + i86pc:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit 0 ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit 0 ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(head -1 /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit 0 ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit 0 ;; + atari*:NetBSD:*:*) + echo m68k-atari-netbsd${UNAME_RELEASE} + exit 0 ;; + atari*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:NetBSD:*:*) + echo m68k-sun-netbsd${UNAME_RELEASE} + exit 0 ;; + sun3*:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:NetBSD:*:*) + echo m68k-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + mac68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme68k:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + mvme88k:OpenBSD:*:*) + echo m88k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit 0 ;; + macppc:NetBSD:*:*) + echo powerpc-apple-netbsd${UNAME_RELEASE} + exit 0 ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit 0 ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit 0 ;; + 2020:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit 0 ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + sed 's/^ //' << EOF >dummy.c + int main (argc, argv) int argc; char **argv; { + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + ${CC-cc} dummy.c -o dummy \ + && ./dummy `echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` \ + && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo mips-mips-riscos${UNAME_RELEASE} + exit 0 ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit 0 ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit 0 ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit 0 ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit 0 ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88110 ] ; then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \ + -o ${TARGET_BINARY_INTERFACE}x = x ] ; then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else echo i586-dg-dgux${UNAME_RELEASE} + fi + exit 0 ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit 0 ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit 0 ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit 0 ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit 0 ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit 0 ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i?86:AIX:*:*) + echo i386-ibm-aix + exit 0 ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + sed 's/^ //' << EOF >dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo rs6000-ibm-aix3.2.5 + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit 0 ;; + *:AIX:*:4) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | head -1 | awk '{ print $1 }'` + if /usr/sbin/lsattr -EHl ${IBM_CPU_ID} | grep POWER >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=4.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit 0 ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit 0 ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit 0 ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit 0 ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit 0 ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit 0 ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit 0 ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit 0 ;; + 9000/[34678]??:HP-UX:*:*) + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/6?? | 9000/7?? | 9000/80[24] | 9000/8?[13679] | 9000/892 ) + sed 's/^ //' << EOF >dummy.c + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (${CC-cc} dummy.c -o dummy 2>/dev/null ) && HP_ARCH=`./dummy` + rm -f dummy.c dummy + esac + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit 0 ;; + 3050*:HI-UX:*:*) + sed 's/^ //' << EOF >dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + echo unknown-hitachi-hiuxwe2 + exit 0 ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit 0 ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit 0 ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit 0 ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit 0 ;; + i?86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit 0 ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit 0 ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit 0 ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit 0 ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit 0 ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit 0 ;; + CRAY*X-MP:*:*:*) + echo xmp-cray-unicos + exit 0 ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ + exit 0 ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} + exit 0 ;; + CRAY-2:*:*:*) + echo cray2-cray-unicos + exit 0 ;; + F300:UNIX_System_V:*:*) + FUJITSU_SYS=`uname -p | tr [A-Z] [a-z] | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "f300-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit 0 ;; + F301:UNIX_System_V:*:*) + echo f301-fujitsu-uxpv`echo $UNAME_RELEASE | sed 's/ .*//'` + exit 0 ;; + hp3[0-9][05]:NetBSD:*:*) + echo m68k-hp-netbsd${UNAME_RELEASE} + exit 0 ;; + hp300:OpenBSD:*:*) + echo m68k-unknown-openbsd${UNAME_RELEASE} + exit 0 ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit 0 ;; + i?86:BSD/386:*:* | *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit 0 ;; + *:FreeBSD:*:*) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit 0 ;; + *:NetBSD:*:*) + echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + *:OpenBSD:*:*) + echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + exit 0 ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit 0 ;; + i*:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit 0 ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit 0 ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit 0 ;; + *:GNU:*:*) + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit 0 ;; + *:Linux:*:*) + # uname on the ARM produces all sorts of strangeness, and we need to + # filter it out. + case "$UNAME_MACHINE" in + arm* | sa110*) UNAME_MACHINE="arm" ;; + esac + + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. + ld_help_string=`ld --help 2>&1` + ld_supported_emulations=`echo $ld_help_string \ + | sed -ne '/supported emulations:/!d + s/[ ][ ]*/ /g + s/.*supported emulations: *// + s/ .*// + p'` + case "$ld_supported_emulations" in + i?86linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" ; exit 0 ;; + i?86coff) echo "${UNAME_MACHINE}-pc-linux-gnucoff" ; exit 0 ;; + sparclinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + armlinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + m68klinux) echo "${UNAME_MACHINE}-unknown-linux-gnuaout" ; exit 0 ;; + elf32ppc) echo "powerpc-unknown-linux-gnu" ; exit 0 ;; + esac + + if test "${UNAME_MACHINE}" = "alpha" ; then + sed 's/^ //' <<EOF >dummy.s + .globl main + .ent main + main: + .frame \$30,0,\$26,0 + .prologue 0 + .long 0x47e03d80 # implver $0 + lda \$2,259 + .long 0x47e20c21 # amask $2,$1 + srl \$1,8,\$2 + sll \$2,2,\$2 + sll \$0,3,\$0 + addl \$1,\$0,\$0 + addl \$2,\$0,\$0 + ret \$31,(\$26),1 + .end main +EOF + LIBC="" + ${CC-cc} dummy.s -o dummy 2>/dev/null + if test "$?" = 0 ; then + ./dummy + case "$?" in + 7) + UNAME_MACHINE="alpha" + ;; + 15) + UNAME_MACHINE="alphaev5" + ;; + 14) + UNAME_MACHINE="alphaev56" + ;; + 10) + UNAME_MACHINE="alphapca56" + ;; + 16) + UNAME_MACHINE="alphaev6" + ;; + esac + + objdump --private-headers dummy | \ + grep ld.so.1 > /dev/null + if test "$?" = 0 ; then + LIBC="libc1" + fi + fi + rm -f dummy.s dummy + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} ; exit 0 + elif test "${UNAME_MACHINE}" = "mips" ; then + cat >dummy.c <<EOF +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __MIPSEB__ + printf ("%s-unknown-linux-gnu\n", argv[1]); +#endif +#ifdef __MIPSEL__ + printf ("%sel-unknown-linux-gnu\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + else + # Either a pre-BFD a.out linker (linux-gnuoldld) + # or one that does not give us useful --help. + # GCC wants to distinguish between linux-gnuoldld and linux-gnuaout. + # If ld does not provide *any* "supported emulations:" + # that means it is gnuoldld. + echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations:" + test $? != 0 && echo "${UNAME_MACHINE}-pc-linux-gnuoldld" && exit 0 + + case "${UNAME_MACHINE}" in + i?86) + VENDOR=pc; + ;; + *) + VENDOR=unknown; + ;; + esac + # Determine whether the default compiler is a.out or elf + cat >dummy.c <<EOF +#include <features.h> +main(argc, argv) + int argc; + char *argv[]; +{ +#ifdef __ELF__ +# ifdef __GLIBC__ +# if __GLIBC__ >= 2 + printf ("%s-${VENDOR}-linux-gnu\n", argv[1]); +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +# else + printf ("%s-${VENDOR}-linux-gnulibc1\n", argv[1]); +# endif +#else + printf ("%s-${VENDOR}-linux-gnuaout\n", argv[1]); +#endif + return 0; +} +EOF + ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0 + rm -f dummy.c dummy + fi ;; +# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions +# are messed up and put the nodename in both sysname and nodename. + i?86:DYNIX/ptx:4*:*) + echo i386-sequent-sysv4 + exit 0 ;; + i?86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit 0 ;; + i?86:*:4.*:* | i?86:SYSTEM_V:4.*:*) + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_RELEASE} + fi + exit 0 ;; + i?86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')` + (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit 0 ;; + i?86:UnixWare:*:*) + if /bin/uname -X 2>/dev/null >/dev/null ; then + (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + fi + echo ${UNAME_MACHINE}-unixware-${UNAME_RELEASE}-${UNAME_VERSION} + exit 0 ;; + pc:*:*:*) + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit 0 ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit 0 ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit 0 ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit 0 ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit 0 ;; + M68*:*:R3V[567]*:*) + test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;; + 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 4850:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4.3${OS_REL} && exit 0 + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && echo i586-ncr-sysv4.3${OS_REL} && exit 0 ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && echo i486-ncr-sysv4 && exit 0 ;; + m68*:LynxOS:2.*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit 0 ;; + i?86:LynxOS:2.*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + rs6000:LynxOS:2.*:* | PowerPC:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit 0 ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit 0 ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit 0 ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit 0 ;; + PENTIUM:CPunix:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <Richard.M.Bartel@ccMail.Census.GOV> + echo i586-unisys-sysv4 + exit 0 ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <hewes@openmarket.com>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit 0 ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit 0 ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit 0 ;; + news*:NEWS-OS:*:6*) + echo mips-sony-newsos6 + exit 0 ;; + R3000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R4000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit 0 ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit 0 ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit 0 ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit 0 ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +cat >dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +#if !defined (ultrix) + printf ("vax-dec-bsd\n"); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0 +rm -f dummy.c dummy + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit 0 ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit 0 ;; + c34*) + echo c34-convex-bsd + exit 0 ;; + c38*) + echo c38-convex-bsd + exit 0 ;; + c4*) + echo c4-convex-bsd + exit 0 ;; + esac +fi + +#echo '(Unable to guess system type)' 1>&2 + +exit 1 diff --git a/support/config.h.dist b/support/config.h.dist new file mode 100644 index 0000000..4d742c3 --- /dev/null +++ b/support/config.h.dist @@ -0,0 +1,555 @@ +/************************************************************************ + * IRC - Internet Relay Chat, support/config.h + * 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. + */ + +/* + * ircdwatch configuration options. + */ + +/* how often (in seconds) should we check that ircd runs? */ +#define IRCDWATCH_POLLING_INTERVAL 30 + +/* + * should we check for config file changes and HUP the server + * if a change is detected? + */ +#undef IRCDWATCH_HUP_ON_CONFIG_CHANGE + +/* + * although you may not want to log ircd-messages to syslog you + * may want to log when ircdwatch reloads the config or when + * ircd croaks and ircdwatch has to restart it + */ +#define IRCDWATCH_USE_SYSLOG +#ifdef IRCDWATCH_USE_SYSLOG +# define IRCDWATCH_SYSLOG_IDENT "ircdwatch" +# define IRCDWATCH_SYSLOG_OPTIONS (LOG_PID) +# define IRCDWATCH_SYSLOG_FACILITY LOG_DAEMON +#endif + + +/* + * irc[d] configuration options. + * + * Most of the following defines are related to the server, + * some apply to the client. + * + */ + +/* + * If you don't want the server to keep reading the MOTD file from the disk, + * define CACHED_MOTD. The server will store the MOTD in memory, and only + * read it again from the disk when rehashing if the file has changed. + */ +#define CACHED_MOTD + +/* CHROOTDIR + * + * Define for value added security if you are a rooter. + * + * CPATH, MPATH, LPATH, PPATH, TPATH, QPATH, OPATH, + * FNAME_USERLOG, FNAME_OPERLOG, FNAME_CONNLOG, FNAME_AUTHLOG + * must have RPATH as root directory! Set them in Makefile + * + * You may want to define IRC_UID and IRC_GID + */ +#undef CHROOTDIR + +#if defined(CHROOTDIR) + #define ROOT_PATH "/where/to/change/root/dir" +#endif + +/* ENABLE_SUMMON + * + * The SUMMON command requires the ircd to be run as group tty in order + * to work properly in many cases. If you are on a machine where it + * won't work, or simply don't want local users to be summoned, undefine + * this. + */ +#undef ENABLE_SUMMON /* local summon */ +#undef ENABLE_USERS /* enables local /users (same as who/finger output) */ + +/* SHOW_INVISIBLE_LUSERS + * + * As defined this will show the correct invisible count for anyone who does + * LUSERS on your server. On a large net this doesnt mean much, but on a + * small net it might be an advantage to undefine it. + */ +#define SHOW_INVISIBLE_LUSERS + +/* NO_DEFAULT_INVISIBLE + * + * When defined, your users will not automatically be attributed with user + * mode "i" (i == invisible). Invisibility means people dont showup in + * WHO or NAMES unless they are on the same channel as you. + */ +#undef NO_DEFAULT_INVISIBLE + +/* OPER_KILL + * + * If you dont believe operators should be allowed to use the /KILL command + * or believe it is uncessary for them to use it, then leave OPER_KILL + * undefined. This will not affect other operators or servers issuing KILL + * commands however. OPER_REHASH and OPER_RESTART allow operators to + * issue the REHASH and RESTART commands when connected to your server. + * Left undefined they increase the security of your server from wayward + * operators and accidents. Defining OPER_REMOTE removes the restriction + * that O-lines only become fully effective for people on the 'same network' + * as the server. Undefined, it increases the security of the server by + * placing restrictions on where people can use operator powers from. + * The 'LOCOP_' #defines are for making the respective commands available + * to 'local' operators. Note that the 'OPER_' #defines affect both global + * (big O) and local (little o) operators. Defining 'LOCOP_x' has no effect + * if 'OPER_x' is undefined so you can't give local operators more rights + * than global ones. + */ +#undef OPER_KILL +#define OPER_REHASH +#undef OPER_RESTART +#define OPER_DIE +#undef OPER_REMOTE +#undef LOCOP_REHASH +#undef LOCOP_RESTART +#undef LOCOP_DIE + +/* + * Maximum number of network connections your server will allow. This should + * never exceed max. number of open file descrpitors and wont increase this. + * Should remain LOW as possible. Most sites will usually have under 50 or so + * connections. + * if you have a lot of server connections, it may be worth splitting the load + * over 2 or more servers. + * 1 server = 1 connection, 1 user = 1 connection. + * This should be at *least* 4: 2 listen ports (1 tcp, 1 udp) + * 1 dns port, 1 client + */ +#define MAXCONNECTIONS 50 + +/* MAXIMUM LINKS + * + * This define is useful for leaf nodes and gateways. It keeps you from + * connecting to too many places. It works by keeping you from + * connecting to more than "n" nodes which you have C:blah::blah:6667 + * lines for. + * + * Note that any number of nodes can still connect to you. This only + * limits the number that you actively reach out to connect to. + * + * Leaf nodes are nodes which are on the edge of the tree. If you want + * to have a backup link, then sometimes you end up connected to both + * your primary and backup, routing traffic between them. To prevent + * this, #define MAXIMUM_LINKS 1 and set up both primary and + * secondary with C:blah::blah:6667 lines. THEY SHOULD NOT TRY TO + * CONNECT TO YOU, YOU SHOULD CONNECT TO THEM. + * + * Gateways such as the server which connects Australia to the US can + * do a similar thing. Put the American nodes you want to connect to + * in with C:blah::blah:6667 lines, and the Australian nodes with + * C:blah::blah lines. Have the Americans put you in with C:blah::blah + * lines. Then you will only connect to one of the Americans. + * + * This value is only used if you don't have server classes defined, and + * a server is in class 0 (the default class if none is set). + * + */ +#define MAXIMUM_LINKS 1 + +/* + * A pure non-routing leaf server can undefine HUB for best performance. + * If your server is running as a a HUB Server then define this. + * A HUB Server has many servers connect to it at the same as opposed + * to a leaf which just has 1 server (typically the uplink). + */ +/* #define HUB */ + +#ifdef HUB +/* + * MAXSERVERS is the maximum number of servers that will be linked + * to your server at the same time. This number is not a limit, + * it is used to allocate memory when ircd is started. + */ +# define MAXSERVERS 3 +#else +# define MAXSERVERS 1 +#endif + +/* R_LINES: The conf file now allows the existence of R lines, or + * restrict lines. These allow more freedom in the ability to restrict + * who is to sign on and when. What the R line does is call an outside + * program which returns a reply indicating whether to let the person on. + * Because there is another program involved, Delays and overhead could + * result. It is for this reason that there is a line in config.h to + * decide whether it is something you want or need. -Hoppie + * + * The default is no R_LINES as most people probably don't need it. --Jto + */ +#undef R_LINES + +#ifdef R_LINES +/* Also, even if you have R lines defined, you might not want them to be + checked everywhere, since it could cost lots of time and delay. Therefore, + The following two options are also offered: R_LINES_REHASH rechecks for + R lines after a rehash, and R_LINES_OFTEN, which rechecks it as often + as it does K lines. Note that R_LINES_OFTEN is *very* likely to cause + a resource drain, use at your own risk. R_LINES_REHASH shouldn't be too + bad, assuming the programs are fairly short. */ +#define R_LINES_REHASH +#define R_LINES_OFTEN +#endif + +/* + * NOTE: defining CMDLINE_CONFIG and installing ircd SUID or SGID is a MAJOR + * security problem - they can use the "-f" option to read any files + * that the 'new' access lets them. Note also that defining this is + * a major security hole if your ircd goes down and some other user + * starts up the server with a new conf file that has some extra + * O-lines. So don't use this unless you're debugging. + */ +#undef CMDLINE_CONFIG /* allow conf-file to be specified on command line */ + +/* + * To use m4 as a preprocessor on the ircd.conf file, define M4_PREPROC. + * The server will then call m4 each time it reads the ircd.conf file, + * reading m4 output as the server's ircd.conf file. + */ +#undef M4_PREPROC + +/* + * If you wish to have the server send 'vital' messages about server + * through syslog, define USE_SYSLOG. Only system errors and events critical + * to the server are logged although if this is defined with FNAME_USERLOG, + * syslog() is used instead of the above file. It is not recommended that + * this option is used unless you tell the system administrator beforehand + * and obtain their permission to send messages to the system log files. + */ +#undef USE_SYSLOG + +#ifdef USE_SYSLOG +/* + * If you use syslog above, you may want to turn some (none) of the + * spurious log messages for KILL/SQUIT off. + */ +#undef SYSLOG_KILL /* log all operator kills to syslog */ +#undef SYSLOG_SQUIT /* log all remote squits for all servers to syslog */ +#undef SYSLOG_CONNECT /* log remote connect messages for other all servs */ +#undef SYSLOG_USERS /* send userlog stuff to syslog */ +#undef SYSLOG_OPER /* log all users who successfully become an Op */ +#undef SYSLOG_CONN /* log all uncomplete/rejected connections */ + +/* + * If you want to log to a different facility than DAEMON, change + * this define. + */ +#define LOG_FACILITY LOG_DAEMON +#endif /* USE_SYSLOG */ + +/* + * define this if you want to use crypted passwords for operators in your + * ircd.conf file. See contrib/mkpasswd/README for more details on this. + */ +#undef CRYPT_OPER_PASSWORD + +/* + * If you want to store encrypted passwords in N-lines for server links, + * define this. For a C/N pair in your ircd.conf file, the password + * need not be the same for both, as long as hte opposite end has the + * right password in the opposite line. See INSTALL doc for more details. + */ +#undef CRYPT_LINK_PASSWORD + +/* + * define this if you enable summon and if you want summon to look for the + * least idle tty a user is logged in on. + */ +#undef LEAST_IDLE + +/* + * IDLE_FROM_MSG + * + * Idle-time nullified only from privmsg, if undefined idle-time + * is nullified from everything except ping/pong. + * Added 3.8.1992, kny@cs.hut.fi (nam) + */ +#define IDLE_FROM_MSG + +/* + * use these to setup a Unix domain socket to connect clients/servers to. + */ +#undef UNIXPORT + +/* + * IRC_UID + * + * If you start the server as root but wish to have it run as another user, + * define IRC_UID to that UID. This should only be defined if you are running + * as root and even then perhaps not. + */ +#undef IRC_UID +#undef IRC_GID + +#ifdef notdef +#define IRC_UID 65534 /* eg for what to do to enable this feature */ +#define IRC_GID 65534 +#endif + +/* + * CLIENT_FLOOD + * + * this controls the number of bytes the server will allow a client to + * send to the server without processing before disconnecting the client for + * flooding it. Values greater than 8000 make no difference to the server. + */ +#define CLIENT_FLOOD 1000 + +/* Remote query flood protection. */ +#define CHREPLLEN 8192 + +/* Default server for standard client */ +#define UPHOST "irc" + +/* + * If you wish to run services, define USE_SERVICES. + * This can make the server noticeably bigger and slower. + * services are not fully implemented yet, so don't use it unless you really + * know what you are doing. + */ +#undef USE_SERVICES + +/* + * Define the following to make the delay for nicks random. + * Some people believe a bot can exactly time the delay and don't like it, + * I think this is a useless concern. -krys + */ +#undef RANDOM_NDELAY + +/* + * You've read the BOFH saga and you liked it, then define the following. + * + * The two following will change the nick delay and channel delay features + * making them totally user unfriendly but more efficient. + */ +#undef BETTER_NDELAY +#undef BETTER_CDELAY + +/* + * Defining this will enable the use of compressed server-server links. + * In order to have it work, you must have the zlib version 1.0 or higher. + * The library and the include files must have been found by configure, + * if you have installed the zlib after running configure, run it again. + */ +#undef ZIP_LINKS + +/* + * Defining this will add an artificial 2 seconds delay for accepting + * connections. This is the OLD behaviour of the server. + * + * NOTE: Undefining this leads to a significant increase in CPU usage if + * you reject client which keeps connecting. + */ +#define SLOW_ACCEPT + +/* + * Defining this will make the server check for rapid connections from a single + * host and reject new connections from this host if the limit is reached. + * + * NOTE: Enabling this feature will significantly increase the CPU usage + * for servers carrying several hundred clients and getting many connections. + * + * IMPORTANT: This **MUST** defined if SLOW_ACCEPT is NOT defined + */ +#undef CLONE_CHECK + +/* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */ +/* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */ +/* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */ + +/* You shouldn't change anything below this line, unless absolutely needed. */ + +#ifdef OPER_KILL +/* LOCAL_KILL_ONLY + * + * To be used, OPER_KILL must be defined. + * LOCAL_KILL_ONLY restricts KILLs to clients which are connected to the + * server the Operator is connected to (ie lets them deal with local + * problem users or 'ghost' clients + */ +#define LOCAL_KILL_ONLY +#endif + +/* Default server port, used by client. */ +#define PORTNUM 6667 + +/* Maximum length the queue of pending connections to one port may grow to. */ +#define LISTENQUEUE 128 + +/* define DEBUGMODE to enable debugging mode.*/ +#undef DEBUGMODE + +/* + * Time interval to wait and if no messages have been received, then check for + * PINGFREQUENCY and CONNECTFREQUENCY + */ +#define TIMESEC 60 /* Recommended value: 60 */ + +/* + * If daemon doesn't receive anything from any of its links within + * PINGFREQUENCY seconds, then the server will attempt to check for + * an active link with a PING message. If no reply is received within + * (PINGFREQUENCY * 2) seconds, then the connection will be closed. + */ +#define PINGFREQUENCY 120 /* Recommended value: 120 */ + +/* + * If the connection to to uphost is down, then attempt to reconnect every + * CONNECTFREQUENCY seconds. + */ +#define CONNECTFREQUENCY 600 /* Recommended value: 600 */ + +/* + * Often net breaks for a short time and it's useful to try to + * establishing the same connection again faster than CONNECTFREQUENCY + * would allow. But, to keep trying on bad connection, we require + * that connection has been open for certain minimum time + * (HANGONGOODLINK) and we give the net few seconds to steady + * (HANGONRETRYDELAY). This latter has to be long enough that the + * other end of the connection has time to notice it broke too. + */ +#define HANGONRETRYDELAY 30 /* Recommended value: 30 seconds */ +#define HANGONGOODLINK 900 /* Recommended value: 15 minutes */ + +/* + * Number of seconds to wait for write to complete if stuck. + */ +#define WRITEWAITDELAY 15 /* Recommended value: 15 */ + +/* + * Number of seconds to wait for DNS/authentication to complete. + * Note that iauth's default timeout per module is 30 seconds, so this value + * should be at least 30 * number of modules. Extra time should really be + * given to be safe. + */ +#define ACCEPTTIMEOUT 90 /* Recommended value: 90 */ + +/* + * Max time from the nickname change that still causes KILL + * automaticly to switch for the current nick of that user. (seconds) + */ +#define KILLCHASETIMELIMIT 90 /* Recommended value: 90 */ + +/* + * Max time for the channel history and nick delay to be effective. + * It should be the same value on all servers of a same net, and + * be greater than the split durations usually seen. + * DELAYCHASETIMELIMIT is the default. + */ +#define DELAYCHASETIMELIMIT 1800 /* Recommended value: 1800 */ + +/* + * Max time for !channel history, this *MUST* be fairly long (usually + * much longer than the value above) to ensure shortname unicity. + * It makes very little sense to use a short time limit here. + */ +#define LDELAYCHASETIMELIMIT 5400 /* Recommended value: 5400 */ + +/* + * Max number of channels a user is allowed to join. + */ +#define MAXCHANNELSPERUSER 10 /* Recommended value: 10 */ + +/* + * USE_IAUTH makes ircd use the iauth program for authentication. + * it can always be overriden by using the -s switch + */ +#define USE_IAUTH + +#ifdef ZIP_LINKS +/* + * the compression level used. (Suggested values: 3, 4, 5) + * Above 5 will only give a *very* marginal increase in compression for a + * *very* large increase in CPU usage. + */ +# define ZIP_LEVEL 5 +#endif + +#ifdef CLONE_CHECK +/* + * If CLONE_CHECK has been defined, these control how the checks are performed, + * and how the alarm is triggered. + */ +# define CLONE_MAX 2 +# define CLONE_PERIOD 10 +#endif + +/* + * define NO_IDENT if you don't want to support ident (RFC1413). + * it is a VERY bad idea to do so, since this will make it impossible to + * efficientely track abusers. + * NO_PREFIX should always be undefined. + */ +/* #undef NO_IDENT */ +/* #undef NO_PREFIX */ + +/* ------------------------- END CONFIGURATION SECTION -------------------- */ +#ifndef ENABLE_SUMMON +# undef LEAST_IDLE +#endif + +#define SEQ_NOFILE 128 /* For Dynix (sequent OS) users : + * set to your current kernel impl, + * max number of socket connections; + * ignored on other OS. + */ +/* + * safety margin so we can always have one spare fd, for motd/authd or + * whatever else. -5 allows "safety" margin of 1 and space reserved. + */ +#define MAXCLIENTS (MAXCONNECTIONS-5) + +#if defined(CLIENT_FLOOD) +# if (CLIENT_FLOOD > 8000) || (CLIENT_FLOOD < 512) +error CLIENT_FLOOD needs redefining. +# endif +#else +error CLIENT_FLOOD undefined +#endif + +#if defined(ZIP_LINKS) +# if (ZIP_MINIMUM > ZIP_MAXIMUM) +error ZIP_MINIMUM needs redefining. +# endif +#endif + +#if !defined(SLOW_ACCEPT) && !defined(CLONE_CHECK) +# define CLONE_CHECK +# define CLONE_MAX 2 +# define CLONE_PERIOD 10 +#endif + +/* +** you wouldn't want to compress messages one by one.. would you? +** (it's not implemented anyways) +*/ +#ifdef ZIP_LINKS +# define SENDQ_ALWAYS +#endif + +#if ! USE_POLL +# if (MAXCONNECTIONS > FD_SETSIZE) +error FD_SETSIZE must be bigger than MAXCONNECTIONS +# endif +#endif diff --git a/support/config.sub b/support/config.sub new file mode 100644 index 0000000..00bea6e --- /dev/null +++ b/support/config.sub @@ -0,0 +1,955 @@ +#! /bin/sh +# Configuration validation subroutine script, version 1.1. +# Copyright (C) 1991, 92-97, 1998 Free Software Foundation, Inc. +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, 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., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +if [ x$1 = x ] +then + echo Configuration name missing. 1>&2 + echo "Usage: $0 CPU-MFR-OPSYS" 1>&2 + echo "or $0 ALIAS" 1>&2 + echo where ALIAS is a recognized configuration type. 1>&2 + exit 1 +fi + +# First pass through any local machine types. +case $1 in + *local*) + echo $1 + exit 0 + ;; + *) + ;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + linux-gnu*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple) + os= + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco5) + os=sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + tahoe | i860 | m32r | m68k | m68000 | m88k | ns32k | arc | arm \ + | arme[lb] | pyramid | mn10200 | mn10300 | tron | a29k \ + | 580 | i960 | h8300 | hppa | hppa1.0 | hppa1.1 | hppa2.0 \ + | alpha | alphaev5 | alphaev56 | we32k | ns16k | clipper \ + | i370 | sh | powerpc | powerpcle | 1750a | dsp16xx | pdp11 \ + | mips64 | mipsel | mips64el | mips64orion | mips64orionel \ + | mipstx39 | mipstx39el \ + | sparc | sparclet | sparclite | sparc64 | v850) + basic_machine=$basic_machine-unknown + ;; + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i[34567]86) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + vax-* | tahoe-* | i[34567]86-* | i860-* | m32r-* | m68k-* | m68000-* \ + | m88k-* | sparc-* | ns32k-* | fx80-* | arc-* | arm-* | c[123]* \ + | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* \ + | power-* | none-* | 580-* | cray2-* | h8300-* | i960-* \ + | xmp-* | ymp-* | hppa-* | hppa1.0-* | hppa1.1-* | hppa2.0-* \ + | alpha-* | alphaev5-* | alphaev56-* | we32k-* | cydra-* \ + | ns16k-* | pn-* | np1-* | xps100-* | clipper-* | orion-* \ + | sparclite-* | pdp11-* | sh-* | powerpc-* | powerpcle-* \ + | sparc64-* | mips64-* | mipsel-* \ + | mips64el-* | mips64orion-* | mips64orionel-* \ + | mipstx39-* | mipstx39el-* \ + | f301-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-cbm + ;; + amigaos | amigados) + basic_machine=m68k-cbm + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-cbm + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | ymp) + basic_machine=ymp-cray + os=-unicos + ;; + cray2) + basic_machine=cray2-cray + os=-unicos + ;; + [ctj]90-cray) + basic_machine=c90-cray + os=-unicos + ;; + crds | unos) + basic_machine=m68k-crds + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + os=-mvs + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i[34567]86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i[34567]86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i[34567]86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i[34567]86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + miniframe) + basic_machine=m68000-convergent + ;; + mipsel*-linux*) + basic_machine=mipsel-unknown + os=-linux-gnu + ;; + mips*-linux*) + basic_machine=mips-unknown + os=-linux-gnu + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + np1) + basic_machine=np1-gould + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pentium | p5 | k5 | nexen) + basic_machine=i586-pc + ;; + pentiumpro | p6 | k6 | 6x86) + basic_machine=i686-pc + ;; + pentiumii | pentium2) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | nexen-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | k6-* | 6x86-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=rs6000-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + xmp) + basic_machine=xmp-cray + os=-unicos + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + mips) + if [ x$os = x-linux-gnu ]; then + basic_machine=mips-unknown + else + basic_machine=mips-mips + fi + ;; + romp) + basic_machine=romp-ibm + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sparc) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -netbsd* | -openbsd* | -freebsd* | -riscix* \ + | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -uxpv* | -beos*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -ctix* | -uts*) + os=-sysv + ;; + -ns2 ) + os=-nextstep2 + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -xenix) + os=-xenix + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + *-acorn) + os=-riscix1.2 + ;; + arm*-semi) + os=-aout + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-ibm) + os=-aix + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f301-fujitsu) + os=-uxpv + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -hpux*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -vxsim* | -vxworks*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os diff --git a/support/configure b/support/configure new file mode 100755 index 0000000..6af37fe --- /dev/null +++ b/support/configure @@ -0,0 +1,4671 @@ +#! /bin/sh + +# From configure.in Id: configure.in,v 1.45 1999/07/17 21:12:43 kalt Exp + +# Guess values for system-dependent variables and create Makefiles. +# Generated automatically using autoconf version 2.13 +# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. + +# Defaults: +ac_help= +ac_default_prefix=/usr/local +# Any additions from configure.in: +ac_help="$ac_help + --with-zlib checks for zlib; if found, enables compressed links" +ac_help="$ac_help + --without-zlib does not check for zlib; disables compressed links" +ac_help="$ac_help + --without-ncurses does not look for ncurses library, will not use it" +ac_help="$ac_help + --without-cursesX does not look for cursesX library, will not use it" +ac_help="$ac_help + --without-curses does not look for curses library, will not use it" +ac_help="$ac_help + --without-termcap does not look for termcap library, will not use it" +ac_help="$ac_help + --enable-ip6 enables IPv6" +ac_help="$ac_help + --enable-dsm enables dynamically shared modules for iauth" + +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +zlib_include=NONE +zlib_library=NONE +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' +logdir='${prefix}/var/log/ircd' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; } + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR[PREFIX/var/run] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --logdir=DIR log files in DIR [PREFIX/var/log/ircd] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --resconf=FILE use FILE as resolver config file [/etc/resolv.conf] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --zlib-prefix=ZDIR zlib installation prefix is ZDIR + --zlib-include=ZIDIR zlib include files are in ZIDIR [ZDIR/include] + --zlib-library=ZLDIR zlib library files are in ZLDIR [ZDIR/lib] +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -logdir | --logdir | --logdi | --logd) + ac_prev=logdir ;; + -logdir=* | --logdir=* | --logdi=* | --logd=*) + logdir="$ac_optarg/" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -resconf | --resconf | --rescon | --resco | --resc | --res \ + | --re | --r) + ac_prev=irc_resconf ;; + -resconf=* | --resconf=* | --rescon=* | --resco=* | --resc=* \ + | --res=* | --re=* | --r=*) + irc_resconf="$ac_optarg" ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version 2.13" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then + { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; } + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + -zlib-prefix | --zlib-prefix | --zlib-prefi | --zlib-pref \ + | --zlib-pre | --zlib-pr | --zlib-p) + ac_prev=irc_zlib_prefix ;; + -zlib-prefix=* | --zlib-prefix=* | --zlib-prefi=* | --zlib-pref=* \ + | --zlib-pre=* | --zlib-pr=* | --zlib-p=*) + irc_zlib_prefix="$ac_optarg" ;; + + -zlib-include | --zlib-include | --zlib-includ | --zlib-inclu \ + | --zlib-incl | --zlib-inc | --zlib-in | --zlib-i) + ac_prev=irc_zlib_include ;; + -zlib-include=* | --zlib-include=* | --zlib-includ=* | --zlib-inclu=* \ + | --zlib-incl=* | --zlib-inc=* | --zlib-in=* | --zlib-i=*) + irc_zlib_include="$ac_optarg" ;; + + -zlib-library | --zlib-library | --zlib-librar | --zlib-libra | --zlib-libr \ + | --zlib-lib | --zlib-li | --zlib-l) + ac_prev=irc_zlib_library ;; + -zlib-library=* | --zlib-library=* | --zlib-librar=* | --zlib-libra=* \ + | --zlib-libr=* | --zlib-lib=* | --zlib-li=* | --zlib-l=*) + irc_zlib_library="$ac_optarg" ;; + + -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; } + ;; + + *) + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then + echo "configure: warning: $ac_option: invalid host type" 1>&2 + fi + if test "x$nonopt" != xNONE; then + { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; } +fi + + + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +# File descriptor usage: +# 0 standard input +# 1 file creation +# 2 errors and warnings +# 3 some systems may open it to /dev/tty +# 4 used on the Kubota Titan +# 6 checking for... messages and results +# 5 compiler messages saved in config.log +if test "$silent" = yes; then + exec 6>/dev/null +else + exec 6>&1 +fi +exec 5>./config.log + +echo "\ +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. +" 1>&5 + +# Strip out --no-create and --no-recursion so they do not pile up. +# Also quote any args containing shell metacharacters. +ac_configure_args= +for ac_arg +do + case "$ac_arg" in + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) ;; + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;; + *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*) + ac_configure_args="$ac_configure_args '$ac_arg'" ;; + *) ac_configure_args="$ac_configure_args $ac_arg" ;; + esac +done + +# NLS nuisances. +# Only set these to C if already set. These must not be set unconditionally +# because not all systems understand e.g. LANG=C (notably SCO). +# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'! +# Non-C LC_CTYPE values break the ctype check. +if test "${LANG+set}" = set; then LANG=C; export LANG; fi +if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi +if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi +if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -rf conftest* confdefs.h +# AIX cpp loses on an empty file, so make sure it contains at least a newline. +echo > confdefs.h + +# A filename unique to this package, relative to the directory that +# configure is in, which we can look for to find out if srcdir is correct. +ac_unique_file=../ircd/ircd.c + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then its parent. + ac_prog=$0 + ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'` + test "x$ac_confdir" = "x$ac_prog" && ac_confdir=. + srcdir=$ac_confdir + if test ! -r $srcdir/$ac_unique_file; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r $srcdir/$ac_unique_file; then + if test "$ac_srcdir_defaulted" = yes; then + { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; } + else + { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; } + fi +fi +srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'` + +# Prefer explicitly selected file to automatically selected ones. +if test -z "$CONFIG_SITE"; then + if test "x$prefix" != xNONE; then + CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site" + else + CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" + fi +fi +for ac_site_file in $CONFIG_SITE; do + if test -r "$ac_site_file"; then + echo "loading site script $ac_site_file" + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + echo "loading cache $cache_file" + . $cache_file +else + echo "creating cache $cache_file" + > $cache_file +fi + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +ac_exeext= +ac_objext=o +if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then + # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu. + if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then + ac_n= ac_c=' +' ac_t=' ' + else + ac_n=-n ac_c= ac_t= + fi +else + ac_n= ac_c='\c' ac_t= +fi + + + +ac_aux_dir= +for ac_dir in ../support $srcdir/../support; do + if test -f $ac_dir/install-sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f $ac_dir/install.sh; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { echo "configure: error: can not find install-sh or install.sh in ../support $srcdir/../support" 1>&2; exit 1; } +fi +ac_config_guess=$ac_aux_dir/config.guess +ac_config_sub=$ac_aux_dir/config.sub +ac_configure=$ac_aux_dir/configure # This should be Cygnus configure. + + +# Do some error checking and defaulting for the host and target type. +# The inputs are: +# configure --host=HOST --target=TARGET --build=BUILD NONOPT +# +# The rules are: +# 1. You are not allowed to specify --host, --target, and nonopt at the +# same time. +# 2. Host defaults to nonopt. +# 3. If nonopt is not specified, then host defaults to the current host, +# as determined by config.guess. +# 4. Target and build default to nonopt. +# 5. If nonopt is not specified, then target and build default to host. + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +case $host---$target---$nonopt in +NONE---*---* | *---NONE---* | *---*---NONE) ;; +*) { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; } ;; +esac + + +# Make sure we can run config.sub. +if ${CONFIG_SHELL-/bin/sh} $ac_config_sub sun4 >/dev/null 2>&1; then : +else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; } +fi + +echo $ac_n "checking host system type""... $ac_c" 1>&6 +echo "configure:609: checking host system type" >&5 + +host_alias=$host +case "$host_alias" in +NONE) + case $nonopt in + NONE) + if host_alias=`${CONFIG_SHELL-/bin/sh} $ac_config_guess`; then : + else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; } + fi ;; + *) host_alias=$nonopt ;; + esac ;; +esac + +host=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $host_alias` +host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$host" 1>&6 + +echo $ac_n "checking target system type""... $ac_c" 1>&6 +echo "configure:630: checking target system type" >&5 + +target_alias=$target +case "$target_alias" in +NONE) + case $nonopt in + NONE) target_alias=$host_alias ;; + *) target_alias=$nonopt ;; + esac ;; +esac + +target=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $target_alias` +target_cpu=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +target_vendor=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$target" 1>&6 + +echo $ac_n "checking build system type""... $ac_c" 1>&6 +echo "configure:648: checking build system type" >&5 + +build_alias=$build +case "$build_alias" in +NONE) + case $nonopt in + NONE) build_alias=$host_alias ;; + *) build_alias=$nonopt ;; + esac ;; +esac + +build=`${CONFIG_SHELL-/bin/sh} $ac_config_sub $build_alias` +build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'` +build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'` +build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'` +echo "$ac_t""$build" 1>&6 + +test "$host_alias" != "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + + + + echo $ac_n "checking cached system tuple""... $ac_c" 1>&6 +echo "configure:673: checking cached system tuple" >&5 + if { test x"${ac_cv_host_system_type+set}" = x"set" && + test x"$ac_cv_host_system_type" != x"$host"; } || + { test x"${ac_cv_build_system_type+set}" = x"set" && + test x"$ac_cv_build_system_type" != x"$build"; } || + { test x"${ac_cv_target_system_type+set}" = x"set" && + test x"$ac_cv_target_system_type" != x"$target"; }; then + echo "$ac_t""different" 1>&6 + + else + echo "$ac_t""ok" 1>&6 + fi + ac_cv_host_system_type="$host" + ac_cv_build_system_type="$build" + ac_cv_target_system_type="$target" + + + +# Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:694: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_CC="gcc" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:724: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_prog_rejected=no + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + break + fi + done + IFS="$ac_save_ifs" +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# -gt 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + set dummy "$ac_dir/$ac_word" "$@" + shift + ac_cv_prog_CC="$@" + fi +fi +fi +fi +CC="$ac_cv_prog_CC" +if test -n "$CC"; then + echo "$ac_t""$CC" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + + test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6 +echo "configure:772: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5 + +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +cat > conftest.$ac_ext << EOF + +#line 783 "configure" +#include "confdefs.h" + +main(){return(0);} +EOF +if { (eval echo configure:788: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + ac_cv_prog_cc_works=yes + # If we can't run a trivial program, we are probably using a cross compiler. + if (./conftest; exit) 2>/dev/null; then + ac_cv_prog_cc_cross=no + else + ac_cv_prog_cc_cross=yes + fi +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + ac_cv_prog_cc_works=no +fi +rm -fr conftest* +ac_ext=c +# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options. +ac_cpp='$CPP $CPPFLAGS' +ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5' +ac_link='${CC-cc} -o conftest${ac_exeext} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5' +cross_compiling=$ac_cv_prog_cc_cross + +echo "$ac_t""$ac_cv_prog_cc_works" 1>&6 +if test $ac_cv_prog_cc_works = no; then + { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; } +fi +echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6 +echo "configure:814: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5 +echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6 +cross_compiling=$ac_cv_prog_cc_cross + +echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6 +echo "configure:819: checking whether we are using GNU C" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.c <<EOF +#ifdef __GNUC__ + yes; +#endif +EOF +if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:828: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then + ac_cv_prog_gcc=yes +else + ac_cv_prog_gcc=no +fi +fi + +echo "$ac_t""$ac_cv_prog_gcc" 1>&6 +ac_test_CFLAGS="${CFLAGS+set}" +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6 +echo "configure:842: checking whether ${CC-cc} accepts -g" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + echo 'void f(){}' > conftest.c +if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then + ac_cv_prog_cc_g=yes +else + ac_cv_prog_cc_g=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_prog_cc_g" 1>&6 + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + CFLAGS="-O2" + fi +else + GCC= +fi + +echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 +echo "configure:867: checking how to run the C preprocessor" >&5 +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then +if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + # This must be in double quotes, not single quotes, because CPP may get + # substituted into the Makefile and "${CC-cc}" will confuse make. + CPP="${CC-cc} -E" + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. + cat > conftest.$ac_ext <<EOF +#line 882 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:888: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -E -traditional-cpp" + cat > conftest.$ac_ext <<EOF +#line 899 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:905: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP="${CC-cc} -nologo -E" + cat > conftest.$ac_ext <<EOF +#line 916 "configure" +#include "confdefs.h" +#include <assert.h> +Syntax Error +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:922: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + : +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + CPP=/lib/cpp +fi +rm -f conftest* +fi +rm -f conftest* +fi +rm -f conftest* + ac_cv_prog_CPP="$CPP" +fi + CPP="$ac_cv_prog_CPP" +else + ac_cv_prog_CPP="$CPP" +fi +echo "$ac_t""$CPP" 1>&6 + +for ac_prog in mawk gawk nawk awk +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:951: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_AWK'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_prog_AWK="$ac_prog" + break + fi + done + IFS="$ac_save_ifs" +fi +fi +AWK="$ac_cv_prog_AWK" +if test -n "$AWK"; then + echo "$ac_t""$AWK" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$AWK" && break +done + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX v4 /usr/bin/installbsd, which does not work if the user is not root +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6 +echo "configure:993: checking for a BSD compatible install" >&5 +if test -z "$INSTALL"; then +if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + elif test $ac_prog = installbsd -a "x`(uname -sv) 2>/dev/null`" = "xAIX 4"; then + # AIX v4 installbsd. Does not work if the user is not root. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +echo "$ac_t""$INSTALL" 1>&6 + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +for ac_prog in md5sum sum cksum +do +# Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo $ac_n "checking for $ac_word""... $ac_c" 1>&6 +echo "configure:1050: checking for $ac_word" >&5 +if eval "test \"`echo '$''{'ac_cv_path_SUM'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + case "$SUM" in + /*) + ac_cv_path_SUM="$SUM" # Let the user override the test with a path. + ;; + ?:/*) + ac_cv_path_SUM="$SUM" # Let the user override the test with a dos path. + ;; + *) + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS=":" + ac_dummy="$PATH" + for ac_dir in $ac_dummy; do + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$ac_word; then + ac_cv_path_SUM="$ac_dir/$ac_word" + break + fi + done + IFS="$ac_save_ifs" + ;; +esac +fi +SUM="$ac_cv_path_SUM" +if test -n "$SUM"; then + echo "$ac_t""$SUM" 1>&6 +else + echo "$ac_t""no" 1>&6 +fi + +test -n "$SUM" && break +done +test -n "$SUM" || SUM="true" + +if test $ac_cv_prog_gcc = yes; then + echo $ac_n "checking whether ${CC-cc} needs -traditional""... $ac_c" 1>&6 +echo "configure:1088: checking whether ${CC-cc} needs -traditional" >&5 +if eval "test \"`echo '$''{'ac_cv_prog_gcc_traditional'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_pattern="Autoconf.*'x'" + cat > conftest.$ac_ext <<EOF +#line 1094 "configure" +#include "confdefs.h" +#include <sgtty.h> +Autoconf TIOCGETP +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +else + rm -rf conftest* + ac_cv_prog_gcc_traditional=no +fi +rm -f conftest* + + + if test $ac_cv_prog_gcc_traditional = no; then + cat > conftest.$ac_ext <<EOF +#line 1112 "configure" +#include "confdefs.h" +#include <termio.h> +Autoconf TCGETA +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "$ac_pattern" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_prog_gcc_traditional=yes +fi +rm -f conftest* + + fi +fi + +echo "$ac_t""$ac_cv_prog_gcc_traditional" 1>&6 + if test $ac_cv_prog_gcc_traditional = yes; then + CC="$CC -traditional" + fi +fi + + +echo $ac_n "checking for AIX""... $ac_c" 1>&6 +echo "configure:1135: checking for AIX" >&5 +if eval "test \"`echo '$''{'irc_cv_aix'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "x`(uname) 2>/dev/null`" = "xAIX"; then + irc_cv_aix="`uname -rv`" +else + irc_cv_aix=no +fi + +fi + +if test "$irc_cv_aix" = no; then + echo "$ac_t""no" 1>&6 +else + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define _ALL_SOURCE 1 +EOF + + if test "x$irc_cv_aix" = "x2 3"; then + cat >> confdefs.h <<\EOF +#define AIX_3_2 1 +EOF + + fi + if test x$CC = xcc; then + CFLAGS="$CFLAGS -O3 -qstrict" + fi +fi + +echo $ac_n "checking for POSIXized ISC""... $ac_c" 1>&6 +echo "configure:1167: checking for POSIXized ISC" >&5 +if test -d /etc/conf/kconfig.d && + grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1 +then + echo "$ac_t""yes" 1>&6 + ISC=yes # If later tests want to check for ISC. + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + if test "$GCC" = yes; then + CC="$CC -posix" + else + CC="$CC -Xp" + fi +else + echo "$ac_t""no" 1>&6 + ISC= +fi + +ac_safe=`echo "minix/config.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for minix/config.h""... $ac_c" 1>&6 +echo "configure:1189: checking for minix/config.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1194 "configure" +#include "confdefs.h" +#include <minix/config.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1199: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + MINIX=yes +else + echo "$ac_t""no" 1>&6 +MINIX= +fi + +if test "$MINIX" = yes; then + cat >> confdefs.h <<\EOF +#define _POSIX_SOURCE 1 +EOF + + cat >> confdefs.h <<\EOF +#define _POSIX_1_SOURCE 2 +EOF + + cat >> confdefs.h <<\EOF +#define _MINIX 1 +EOF + +fi + +echo $ac_n "checking for SGI's cc""... $ac_c" 1>&6 +echo "configure:1237: checking for SGI's cc" >&5 +cat > conftest.$ac_ext <<EOF +#line 1239 "configure" +#include "confdefs.h" +#ifdef sgi +yes +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + if test x$CC = xcc; then + echo "$ac_t""yes" 1>&6 + CC="$CC -cckr" +else + echo "$ac_t""no" 1>&6 +fi +else + rm -rf conftest* + echo "$ac_t""no" 1>&6 +fi +rm -f conftest* + + +echo $ac_n "checking for HPUX's cc""... $ac_c" 1>&6 +echo "configure:1262: checking for HPUX's cc" >&5 +cat > conftest.$ac_ext <<EOF +#line 1264 "configure" +#include "confdefs.h" +#ifdef hpux +yes +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + if test x$CC = xcc; then + echo "$ac_t""yes" 1>&6 + CC="$CC -Ae" +else + echo "$ac_t""no" 1>&6 +fi +else + rm -rf conftest* + echo "$ac_t""no" 1>&6 +fi +rm -f conftest* + + +echo $ac_n "checking for SunOS""... $ac_c" 1>&6 +echo "configure:1287: checking for SunOS" >&5 +if eval "test \"`echo '$''{'irc_cv_sun'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "x`(uname) 2>/dev/null`" = "xSunOS"; then + irc_cv_sun="`uname -r`" +else + irc_cv_sun=no +fi + +fi + +irc_cv_solaris_2=no +if test "$irc_sun" = no; then + echo "$ac_t""no" 1>&6 +else + if uname -r 2>/dev/null | grep "^5" >/dev/null; then + irc_cv_solaris_2="`uname -r | sed -e \"s/^5/2/g\"`" + echo "$ac_t""yes, Solaris $irc_cv_solaris_2" 1>&6 + cat >> confdefs.h <<\EOF +#define SOLARIS_2 1 +EOF + + if echo "$irc_cv_solaris_2" | egrep "^2\.(0|1|2)" >/dev/null; then + cat >> confdefs.h <<\EOF +#define SOLARIS_2_0_2_1_2_2 1 +EOF + + elif echo "$irc_cv_solaris_2" | grep "^2\.3" >/dev/null; then + cat >> confdefs.h <<\EOF +#define SOLARIS_2_3 1 +EOF + + fi + else + echo "$ac_t""yes, SunOS $irc_cv_sun" 1>&6 + fi +fi + +echo $ac_n "checking for Linux""... $ac_c" 1>&6 +echo "configure:1327: checking for Linux" >&5 +if eval "test \"`echo '$''{'irc_cv_linux'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "x`(uname) 2>/dev/null`" = "xLinux"; then + cat > conftest.$ac_ext <<EOF +#line 1333 "configure" +#include "confdefs.h" +#include <netdb.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $AWK "{if (NR > 1) printf(\" \"); printf(\$0)}" | + egrep "struct( | )+hostent( | )+\{.*const.*h_name" >/dev/null 2>&1; then + rm -rf conftest* + irc_cv_linux=bad +else + rm -rf conftest* + irc_cv_linux=good +fi +rm -f conftest* + +else + irc_cv_linux=no +fi + +fi + +if test "$irc_cv_linux" = no; then + echo "$ac_t""no" 1>&6 +elif test "$irc_cv_linux" = good; then + echo "$ac_t""yes, with a good <netdb.h> file" 1>&6 +else + echo "$ac_t""yes, with a bad <netdb.h> file" 1>&6 + cat >> confdefs.h <<\EOF +#define BAD___CONST_NETDB_H 1 +EOF + +fi + +echo $ac_n "checking for Cygwin environment""... $ac_c" 1>&6 +echo "configure:1367: checking for Cygwin environment" >&5 +if eval "test \"`echo '$''{'ac_cv_cygwin'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1372 "configure" +#include "confdefs.h" + +int main() { + +#ifndef __CYGWIN__ +#define __CYGWIN__ __CYGWIN32__ +#endif +return __CYGWIN__; +; return 0; } +EOF +if { (eval echo configure:1383: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_cygwin=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_cygwin=no +fi +rm -f conftest* +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_cygwin" 1>&6 +CYGWIN= +test "$ac_cv_cygwin" = yes && CYGWIN=yes +if test ! -z "$CYGWIN"; then + if test ! -x /bin/mv || test ! -x /bin/rm || test ! -x /bin/sh; then + { echo "configure: error: mv, rm and/or sh is missing from /bin" 1>&2; exit 1; } + fi + echo "configure: warning: The IRC client and the iauth program do not work under the CYGWIN environment." 1>&2 +fi + + +echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 +echo "configure:1408: checking for ANSI C header files" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1413 "configure" +#include "confdefs.h" +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <float.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1421: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + ac_cv_header_stdc=yes +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1438 "configure" +#include "confdefs.h" +#include <string.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "memchr" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. +cat > conftest.$ac_ext <<EOF +#line 1456 "configure" +#include "confdefs.h" +#include <stdlib.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "free" >/dev/null 2>&1; then + : +else + rm -rf conftest* + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. +if test "$cross_compiling" = yes; then + : +else + cat > conftest.$ac_ext <<EOF +#line 1477 "configure" +#include "confdefs.h" +#include <ctype.h> +#define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int main () { int i; for (i = 0; i < 256; i++) +if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); +exit (0); } + +EOF +if { (eval echo configure:1488: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + : +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_header_stdc=no +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_header_stdc" 1>&6 +if test $ac_cv_header_stdc = yes; then + cat >> confdefs.h <<\EOF +#define STDC_HEADERS 1 +EOF + +fi + +echo $ac_n "checking for sys/wait.h that is POSIX.1 compatible""... $ac_c" 1>&6 +echo "configure:1512: checking for sys/wait.h that is POSIX.1 compatible" >&5 +if eval "test \"`echo '$''{'ac_cv_header_sys_wait_h'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1517 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/wait.h> +#ifndef WEXITSTATUS +#define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +#define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif +int main() { +int s; +wait (&s); +s = WIFEXITED (s) ? WEXITSTATUS (s) : 1; +; return 0; } +EOF +if { (eval echo configure:1533: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_sys_wait_h=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_sys_wait_h=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_sys_wait_h" 1>&6 +if test $ac_cv_header_sys_wait_h = yes; then + cat >> confdefs.h <<\EOF +#define HAVE_SYS_WAIT_H 1 +EOF + +fi + +for ac_hdr in stdio.h stdlib.h sys/types.h sys/bitypes.h stddef.h stdarg.h unistd.h ctype.h memory.h ncurses.h curses.h cursesX.h term.h sgtty.h errno.h sys/errno.h sys/syscall.h pwd.h math.h utmp.h fcntl.h signal.h sys/ioctl.h sys/file.h sys/filio.h sys/socket.h sys/stat.h sys/resource.h sys/select.h sys/poll.h stropts.h netdb.h netinet/in.h sys/un.h arpa/inet.h sys/param.h syslog.h sys/syslog.h string.h strings.h sys/time.h time.h sys/times.h netinet/in_systm.h netinfo/ni.h resolv.h arpa/nameser.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:1557: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1562 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:1567: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +echo $ac_n "checking for sys_errlist declaration in stdio.h, errno.h or sys/errno.h""... $ac_c" 1>&6 +echo "configure:1594: checking for sys_errlist declaration in stdio.h, errno.h or sys/errno.h" >&5 +if eval "test \"`echo '$''{'irc_cv_decl_sys_errlist'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1599 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_STDIO_H +#include <stdio.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif +int main() { +char *msg = sys_errlist[0]; +; return 0; } +EOF +if { (eval echo configure:1618: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + irc_cv_decl_sys_errlist=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_cv_decl_sys_errlist=no +fi +rm -f conftest* +fi + +echo "$ac_t""$irc_cv_decl_sys_errlist" 1>&6 +if test $irc_cv_decl_sys_errlist = yes; then + cat >> confdefs.h <<\EOF +#define SYS_ERRLIST_DECLARED 1 +EOF + +fi + +echo $ac_n "checking for sys_nerr declaration in stdio.h, errno.h or sys/errno.h""... $ac_c" 1>&6 +echo "configure:1639: checking for sys_nerr declaration in stdio.h, errno.h or sys/errno.h" >&5 +if eval "test \"`echo '$''{'irc_cv_decl_sys_nerr'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1644 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_STDIO_H +#include <stdio.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif +int main() { +int num = sys_nerr; +; return 0; } +EOF +if { (eval echo configure:1663: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + irc_cv_decl_sys_nerr=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_cv_decl_sys_nerr=no +fi +rm -f conftest* +fi + +echo "$ac_t""$irc_cv_decl_sys_nerr" 1>&6 +if test $irc_cv_decl_sys_nerr = yes; then + cat >> confdefs.h <<\EOF +#define SYS_NERR_DECLARED 1 +EOF + +fi + +echo $ac_n "checking for errno declaration in errno.h or sys/errno.h""... $ac_c" 1>&6 +echo "configure:1684: checking for errno declaration in errno.h or sys/errno.h" >&5 +if eval "test \"`echo '$''{'irc_cv_decl_errno'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1689 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif +int main() { +int num = errno; +; return 0; } +EOF +if { (eval echo configure:1705: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + irc_cv_decl_errno=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_cv_decl_errno=no +fi +rm -f conftest* +fi + +echo "$ac_t""$irc_cv_decl_errno" 1>&6 +if test $irc_cv_decl_errno = yes; then + cat >> confdefs.h <<\EOF +#define ERRNO_DECLARED 1 +EOF + +fi + +echo $ac_n "checking for h_errno declaration in errno.h, sys/errno.h or netdb.h""... $ac_c" 1>&6 +echo "configure:1726: checking for h_errno declaration in errno.h, sys/errno.h or netdb.h" >&5 +if eval "test \"`echo '$''{'irc_cv_decl_h_errno'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1731 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif +#if HAVE_NETDB_H +#include <netdb.h> +#endif +int main() { +int num = h_errno; +; return 0; } +EOF +if { (eval echo configure:1750: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + irc_cv_decl_h_errno=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_cv_decl_h_errno=no +fi +rm -f conftest* +fi + +echo "$ac_t""$irc_cv_decl_h_errno" 1>&6 +if test $irc_cv_decl_h_errno = yes; then + cat >> confdefs.h <<\EOF +#define H_ERRNO_DECLARED 1 +EOF + +fi + +echo $ac_n "checking whether stat file-mode macros are broken""... $ac_c" 1>&6 +echo "configure:1771: checking whether stat file-mode macros are broken" >&5 +if eval "test \"`echo '$''{'ac_cv_header_stat_broken'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1776 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/stat.h> + +#if defined(S_ISBLK) && defined(S_IFDIR) +# if S_ISBLK (S_IFDIR) +You lose. +# endif +#endif + +#if defined(S_ISBLK) && defined(S_IFCHR) +# if S_ISBLK (S_IFCHR) +You lose. +# endif +#endif + +#if defined(S_ISLNK) && defined(S_IFREG) +# if S_ISLNK (S_IFREG) +You lose. +# endif +#endif + +#if defined(S_ISSOCK) && defined(S_IFREG) +# if S_ISSOCK (S_IFREG) +You lose. +# endif +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "You lose" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_header_stat_broken=yes +else + rm -rf conftest* + ac_cv_header_stat_broken=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_header_stat_broken" 1>&6 +if test $ac_cv_header_stat_broken = yes; then + cat >> confdefs.h <<\EOF +#define STAT_MACROS_BROKEN 1 +EOF + +fi + +echo $ac_n "checking whether time.h and sys/time.h may both be included""... $ac_c" 1>&6 +echo "configure:1827: checking whether time.h and sys/time.h may both be included" >&5 +if eval "test \"`echo '$''{'ac_cv_header_time'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1832 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/time.h> +#include <time.h> +int main() { +struct tm *tp; +; return 0; } +EOF +if { (eval echo configure:1841: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_header_time=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_header_time=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_header_time" 1>&6 +if test $ac_cv_header_time = yes; then + cat >> confdefs.h <<\EOF +#define TIME_WITH_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking whether struct tm is in sys/time.h or time.h""... $ac_c" 1>&6 +echo "configure:1862: checking whether struct tm is in sys/time.h or time.h" >&5 +if eval "test \"`echo '$''{'ac_cv_struct_tm'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1867 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <time.h> +int main() { +struct tm *tp; tp->tm_sec; +; return 0; } +EOF +if { (eval echo configure:1875: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_struct_tm=time.h +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_struct_tm=sys/time.h +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_struct_tm" 1>&6 +if test $ac_cv_struct_tm = sys/time.h; then + cat >> confdefs.h <<\EOF +#define TM_IN_SYS_TIME 1 +EOF + +fi + +echo $ac_n "checking for mode_t""... $ac_c" 1>&6 +echo "configure:1896: checking for mode_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_mode_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1901 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])mode_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_mode_t=yes +else + rm -rf conftest* + ac_cv_type_mode_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_mode_t" 1>&6 +if test $ac_cv_type_mode_t = no; then + cat >> confdefs.h <<\EOF +#define mode_t int +EOF + +fi + +echo $ac_n "checking for off_t""... $ac_c" 1>&6 +echo "configure:1929: checking for off_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_off_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1934 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])off_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_off_t=yes +else + rm -rf conftest* + ac_cv_type_off_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_off_t" 1>&6 +if test $ac_cv_type_off_t = no; then + cat >> confdefs.h <<\EOF +#define off_t long +EOF + +fi + +echo $ac_n "checking for pid_t""... $ac_c" 1>&6 +echo "configure:1962: checking for pid_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 1967 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])pid_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_pid_t=yes +else + rm -rf conftest* + ac_cv_type_pid_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_pid_t" 1>&6 +if test $ac_cv_type_pid_t = no; then + cat >> confdefs.h <<\EOF +#define pid_t int +EOF + +fi + +echo $ac_n "checking return type of signal handlers""... $ac_c" 1>&6 +echo "configure:1995: checking return type of signal handlers" >&5 +if eval "test \"`echo '$''{'ac_cv_type_signal'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2000 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <signal.h> +#ifdef signal +#undef signal +#endif +#ifdef __cplusplus +extern "C" void (*signal (int, void (*)(int)))(int); +#else +void (*signal ()) (); +#endif + +int main() { +int i; +; return 0; } +EOF +if { (eval echo configure:2017: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_type_signal=void +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_type_signal=int +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_type_signal" 1>&6 +cat >> confdefs.h <<EOF +#define RETSIGTYPE $ac_cv_type_signal +EOF + + +echo $ac_n "checking for size_t""... $ac_c" 1>&6 +echo "configure:2036: checking for size_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_size_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2041 "configure" +#include "confdefs.h" +#include <sys/types.h> +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "(^|[^a-zA-Z_0-9])size_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_size_t=yes +else + rm -rf conftest* + ac_cv_type_size_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_size_t" 1>&6 +if test $ac_cv_type_size_t = no; then + cat >> confdefs.h <<\EOF +#define size_t unsigned +EOF + +fi + +echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 +echo "configure:2069: checking for uid_t in sys/types.h" >&5 +if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2074 "configure" +#include "confdefs.h" +#include <sys/types.h> +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "uid_t" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_uid_t=yes +else + rm -rf conftest* + ac_cv_type_uid_t=no +fi +rm -f conftest* + +fi + +echo "$ac_t""$ac_cv_type_uid_t" 1>&6 +if test $ac_cv_type_uid_t = no; then + cat >> confdefs.h <<\EOF +#define uid_t int +EOF + + cat >> confdefs.h <<\EOF +#define gid_t int +EOF + +fi + +echo $ac_n "checking whether an union wait * is mandatory in waitpid""... $ac_c" 1>&6 +echo "configure:2103: checking whether an union wait * is mandatory in waitpid" >&5 +if eval "test \"`echo '$''{'irc_cv_type_union_wait'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2108 "configure" +#include "confdefs.h" + +#if HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +int main() { + +int status; +waitpid(-1, &status, 0); + +; return 0; } +EOF +if { (eval echo configure:2121: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + irc_cv_type_union_wait=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + cat > conftest.$ac_ext <<EOF +#line 2129 "configure" +#include "confdefs.h" + +#if HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +int main() { + +union wait status; +waitpid(-1, &status, 0); + +; return 0; } +EOF +if { (eval echo configure:2142: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + irc_cv_type_union_wait=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_cv_type_union_wait=no +fi +rm -f conftest* +fi +rm -f conftest* +fi + +if test $irc_cv_type_union_wait = yes; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define USE_UNION_WAIT 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for int8_t""... $ac_c" 1>&6 +echo "configure:2167: checking for int8_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_int8_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2172 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "int8_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_int8_t=yes +else + rm -rf conftest* + ac_cv_type_int8_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_int8_t" 1>&6 +if test $ac_cv_type_int8_t = no; then + cat >> confdefs.h <<\EOF +#define int8_t char +EOF + +fi + +echo $ac_n "checking for u_int8_t""... $ac_c" 1>&6 +echo "configure:2206: checking for u_int8_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_u_int8_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2211 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "u_int8_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_u_int8_t=yes +else + rm -rf conftest* + ac_cv_type_u_int8_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_u_int8_t" 1>&6 +if test $ac_cv_type_u_int8_t = no; then + cat >> confdefs.h <<\EOF +#define u_int8_t unsigned char +EOF + +fi + +echo $ac_n "checking for int16_t""... $ac_c" 1>&6 +echo "configure:2245: checking for int16_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_int16_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2250 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "int16_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_int16_t=yes +else + rm -rf conftest* + ac_cv_type_int16_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_int16_t" 1>&6 +if test $ac_cv_type_int16_t = no; then + cat >> confdefs.h <<\EOF +#define int16_t short +EOF + +fi + +echo $ac_n "checking for u_int16_t""... $ac_c" 1>&6 +echo "configure:2284: checking for u_int16_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_u_int16_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2289 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "u_int16_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_u_int16_t=yes +else + rm -rf conftest* + ac_cv_type_u_int16_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_u_int16_t" 1>&6 +if test $ac_cv_type_u_int16_t = no; then + cat >> confdefs.h <<\EOF +#define u_int16_t unsigned short +EOF + +fi + +echo $ac_n "checking for int32_t""... $ac_c" 1>&6 +echo "configure:2323: checking for int32_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_int32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2328 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_int32_t=yes +else + rm -rf conftest* + ac_cv_type_int32_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_int32_t" 1>&6 +if test $ac_cv_type_int32_t = no; then + cat >> confdefs.h <<\EOF +#define int32_t int +EOF + +fi + +echo $ac_n "checking for u_int32_t""... $ac_c" 1>&6 +echo "configure:2362: checking for u_int32_t" >&5 +if eval "test \"`echo '$''{'ac_cv_type_u_int32_t'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2367 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "u_int32_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_u_int32_t=yes +else + rm -rf conftest* + ac_cv_type_u_int32_t=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_u_int32_t" 1>&6 +if test $ac_cv_type_u_int32_t = no; then + cat >> confdefs.h <<\EOF +#define u_int32_t unsigned int +EOF + +fi + +echo $ac_n "checking for u_char""... $ac_c" 1>&6 +echo "configure:2401: checking for u_char" >&5 +if eval "test \"`echo '$''{'ac_cv_type_u_char'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2406 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "u_char[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_u_char=yes +else + rm -rf conftest* + ac_cv_type_u_char=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_u_char" 1>&6 +if test $ac_cv_type_u_char = no; then + cat >> confdefs.h <<\EOF +#define u_char unsigned char +EOF + +fi + +echo $ac_n "checking for u_short""... $ac_c" 1>&6 +echo "configure:2440: checking for u_short" >&5 +if eval "test \"`echo '$''{'ac_cv_type_u_short'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2445 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "u_short[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_u_short=yes +else + rm -rf conftest* + ac_cv_type_u_short=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_u_short" 1>&6 +if test $ac_cv_type_u_short = no; then + cat >> confdefs.h <<\EOF +#define u_short unsigned short +EOF + +fi + +echo $ac_n "checking for u_int""... $ac_c" 1>&6 +echo "configure:2479: checking for u_int" >&5 +if eval "test \"`echo '$''{'ac_cv_type_u_int'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2484 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "u_int[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_u_int=yes +else + rm -rf conftest* + ac_cv_type_u_int=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_u_int" 1>&6 +if test $ac_cv_type_u_int = no; then + cat >> confdefs.h <<\EOF +#define u_int unsigned int +EOF + +fi + +echo $ac_n "checking for u_long""... $ac_c" 1>&6 +echo "configure:2518: checking for u_long" >&5 +if eval "test \"`echo '$''{'ac_cv_type_u_long'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2523 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "u_long[^a-zA-Z_0-9]" >/dev/null 2>&1; then + rm -rf conftest* + ac_cv_type_u_long=yes +else + rm -rf conftest* + ac_cv_type_u_long=no +fi +rm -f conftest* + +fi +echo "$ac_t""$ac_cv_type_u_long" 1>&6 +if test $ac_cv_type_u_long = no; then + cat >> confdefs.h <<\EOF +#define u_long unsigned long +EOF + +fi + + +echo $ac_n "checking whether byte ordering is bigendian""... $ac_c" 1>&6 +echo "configure:2558: checking whether byte ordering is bigendian" >&5 +if eval "test \"`echo '$''{'ac_cv_c_bigendian'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_cv_c_bigendian=unknown +# See if sys/param.h defines the BYTE_ORDER macro. +cat > conftest.$ac_ext <<EOF +#line 2565 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/param.h> +int main() { + +#if !BYTE_ORDER || !BIG_ENDIAN || !LITTLE_ENDIAN + bogus endian macros +#endif +; return 0; } +EOF +if { (eval echo configure:2576: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + # It does; now see whether it defined to BIG_ENDIAN or not. +cat > conftest.$ac_ext <<EOF +#line 2580 "configure" +#include "confdefs.h" +#include <sys/types.h> +#include <sys/param.h> +int main() { + +#if BYTE_ORDER != BIG_ENDIAN + not big endian +#endif +; return 0; } +EOF +if { (eval echo configure:2591: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_bigendian=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_bigendian=no +fi +rm -f conftest* +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 +fi +rm -f conftest* +if test $ac_cv_c_bigendian = unknown; then +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 2611 "configure" +#include "confdefs.h" +main () { + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long l; + char c[sizeof (long)]; + } u; + u.l = 1; + exit (u.c[sizeof (long) - 1] == 1); +} +EOF +if { (eval echo configure:2624: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_c_bigendian=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_c_bigendian=yes +fi +rm -fr conftest* +fi + +fi +fi + +echo "$ac_t""$ac_cv_c_bigendian" 1>&6 +if test $ac_cv_c_bigendian = yes; then + cat >> confdefs.h <<\EOF +#define WORDS_BIGENDIAN 1 +EOF + +fi + +echo $ac_n "checking for working const""... $ac_c" 1>&6 +echo "configure:2648: checking for working const" >&5 +if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 2653 "configure" +#include "confdefs.h" + +int main() { + +/* Ultrix mips cc rejects this. */ +typedef int charset[2]; const charset x; +/* SunOS 4.1.1 cc rejects this. */ +char const *const *ccp; +char **p; +/* NEC SVR4.0.2 mips cc rejects this. */ +struct point {int x, y;}; +static struct point const zero = {0,0}; +/* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in an arm + of an if-expression whose if-part is not a constant expression */ +const char *g = "string"; +ccp = &g + (g ? g-g : 0); +/* HPUX 7.0 cc rejects these. */ +++ccp; +p = (char**) ccp; +ccp = (char const *const *) p; +{ /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; +} +{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; +} +{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; +} +{ /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; +} +{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; +} + +; return 0; } +EOF +if { (eval echo configure:2702: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then + rm -rf conftest* + ac_cv_c_const=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + ac_cv_c_const=no +fi +rm -f conftest* +fi + +echo "$ac_t""$ac_cv_c_const" 1>&6 +if test $ac_cv_c_const = no; then + cat >> confdefs.h <<\EOF +#define const +EOF + +fi + + +echo $ac_n "checking for crypt in -lcrypt""... $ac_c" 1>&6 +echo "configure:2724: checking for crypt in -lcrypt" >&5 +ac_lib_var=`echo crypt'_'crypt | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lcrypt $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2732 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char crypt(); + +int main() { +crypt() +; return 0; } +EOF +if { (eval echo configure:2743: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo crypt | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lcrypt $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for socket in -lsocket""... $ac_c" 1>&6 +echo "configure:2771: checking for socket in -lsocket" >&5 +ac_lib_var=`echo socket'_'socket | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lsocket $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2779 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket(); + +int main() { +socket() +; return 0; } +EOF +if { (eval echo configure:2790: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo socket | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lsocket $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for socket in -lnsl""... $ac_c" 1>&6 +echo "configure:2818: checking for socket in -lnsl" >&5 +ac_lib_var=`echo nsl'_'socket | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-lnsl $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2826 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char socket(); + +int main() { +socket() +; return 0; } +EOF +if { (eval echo configure:2837: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_lib=HAVE_LIB`echo nsl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ + -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` + cat >> confdefs.h <<EOF +#define $ac_tr_lib 1 +EOF + + LIBS="-lnsl $LIBS" + +else + echo "$ac_t""no" 1>&6 +fi + + +echo $ac_n "checking for zlib package""... $ac_c" 1>&6 +echo "configure:2866: checking for zlib package" >&5 +# Check whether --with-zlib or --without-zlib was given. +if test "${with_zlib+set}" = set; then + withval="$with_zlib" + : +fi + +# Check whether --with-zlib or --without-zlib was given. +if test "${with_zlib+set}" = set; then + withval="$with_zlib" + : +fi + +if test "x$with_zlib" = xno; then + no_zlib=yes +else +if eval "test \"`echo '$''{'irc_cv_path_zlib'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + no_zlib=yes +no_zlib_include=yes +no_zlib_library=yes +cat > conftest.$ac_ext <<EOF +#line 2889 "configure" +#include "confdefs.h" +#include <zlib.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:2894: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + no_zlib_include= +irc_zlib_include= +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + for irc_dir in "$irc_zlib_include" \ + `test -z "$irc_zlib_prefix" || echo "$irc_zlib_prefix/include"` \ + `echo "$irc_zlib_library" | sed s/lib/include/` \ + /usr/include /usr/local/include /usr/unsupported/include \ + /usr/share/include /usr/local/share/include /include \ + /usr/zlib/include /usr/local/zlib/include \ + /usr/include/zlib /usr/local/include/zlib \ + /usr/unsupported/include/zlib /usr/share/include/zlib \ + /usr/local/share/include/zlib /include/zlib \ + /usr/zlib/include/zlib /usr/local/zlib/include/zlib; \ + do + if test -r "$irc_dir/zlib.h"; then + no_zlib_include= + irc_zlib_include=$irc_dir + break + fi + done + +fi +rm -f conftest* +irc_save_LIBS="$LIBS" +LIBS="-lz $LIBS" +cat > conftest.$ac_ext <<EOF +#line 2928 "configure" +#include "confdefs.h" + +int main() { +inflate() +; return 0; } +EOF +if { (eval echo configure:2935: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + no_zlib_library= +irc_zlib_library= +LIBS="$irc_save_LIBS" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + LIBS="$irc_save_LIBS" +for irc_dir in "$irc_zlib_library" \ + `test -z "$irc_zlib_prefix" || echo "$irc_zlib_prefix/lib"` \ + `echo "$irc_zlib_include" | sed s/include/lib/` \ + /usr/lib /usr/local/lib /usr/unsupported/lib \ + /usr/share/lib /usr/local/share/lib /lib /usr/zlib/lib \ + /usr/local/zlib/lib /usr/lib/zlib /usr/local/lib/zlib \ + /usr/unsupported/lib/zlib /usr/share/lib/zlib \ + /usr/local/share/lib/zlib /lib/zlib \ + /usr/zlib/lib/zlib /usr/local/zlib/lib/zlib; \ +do + for irc_extension in a so sl; do + if test -r $irc_dir/libz.$irc_extension; then + no_zlib_library= + irc_zlib_library=$irc_dir + break 2 + fi + done +done + +fi +rm -f conftest* +if test "x$no_zlib_include" = x && test "x$no_zlib_library" = x; then + no_zlib= +fi +if test "$no_zlib" = yes; then + irc_cv_path_zlib="no_zlib=yes" +else + irc_cv_path_zlib="no_zlib= irc_zlib_include=$irc_zlib_include irc_zlib_library=$irc_zlib_library" +fi +fi + + eval "$irc_cv_path_zlib" +fi +if test "$no_zlib" = yes; then + IRC_ZLIB_LIBRARY= + IRC_ZLIB_INCLUDE= + echo "$ac_t""no" 1>&6 +else + cat >> confdefs.h <<\EOF +#define USE_ZLIB 1 +EOF + + if test "x$irc_zlib_library" = x; then + irc_zlib_library_message="found by the linker" + IRC_ZLIB_LIBRARY=-lz + else + irc_zlib_library_message="in $irc_zlib_library" + IRC_ZLIB_LIBRARY=-L$irc_zlib_library + if test ! "$irc_cv_solaris_2" = no; then + IRC_ZLIB_LIBRARY="$IRC_ZLIB_LIBRARY -R$irc_zlib_library" + fi + IRC_ZLIB_LIBRARY="$IRC_ZLIB_LIBRARY -lz" + fi + if test "x$irc_zlib_include" = x; then + irc_zlib_include_message="found by the compiler" + IRC_ZLIB_INCLUDE= + else + irc_zlib_include_message="in $irc_zlib_include" + IRC_ZLIB_INCLUDE=-I$irc_zlib_include + fi + echo "$ac_t""" 1>&6 + echo "$ac_t"" library $irc_zlib_library_message" 1>&6 + echo "$ac_t"" header $irc_zlib_include_message" 1>&6 +fi + + + +echo $ac_n "checking which curses or termcap library will be used""... $ac_c" 1>&6 +echo "configure:3013: checking which curses or termcap library will be used" >&5 +# Check whether --with-ncurses or --without-ncurses was given. +if test "${with_ncurses+set}" = set; then + withval="$with_ncurses" + : +fi + +# Check whether --with-cursesX or --without-cursesX was given. +if test "${with_cursesX+set}" = set; then + withval="$with_cursesX" + : +fi + +# Check whether --with-curses or --without-curses was given. +if test "${with_curses+set}" = set; then + withval="$with_curses" + : +fi + +# Check whether --with-termcap or --without-termcap was given. +if test "${with_termcap+set}" = set; then + withval="$with_termcap" + : +fi + +if eval "test \"`echo '$''{'irc_cv_curses_termcap'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + irc_save_LIBS="$LIBS" +LIBS="-lncurses $irc_save_LIBS" +cat > conftest.$ac_ext <<EOF +#line 3044 "configure" +#include "confdefs.h" + +int main() { +initscr() +; return 0; } +EOF +if { (eval echo configure:3051: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + irc_ncurses=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_ncurses=no +fi +rm -f conftest* +LIBS="-lcursesX $irc_save_LIBS" +cat > conftest.$ac_ext <<EOF +#line 3063 "configure" +#include "confdefs.h" + +int main() { +initscr() +; return 0; } +EOF +if { (eval echo configure:3070: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + irc_cursesX=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_cursesX=no +fi +rm -f conftest* +LIBS="-lcurses $irc_save_LIBS" +cat > conftest.$ac_ext <<EOF +#line 3082 "configure" +#include "confdefs.h" + +int main() { +initscr() +; return 0; } +EOF +if { (eval echo configure:3089: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + irc_curses=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_curses=no +fi +rm -f conftest* +LIBS="-lcurses -ltermcap $irc_save_LIBS" +cat > conftest.$ac_ext <<EOF +#line 3101 "configure" +#include "confdefs.h" + +int main() { +initscr() +; return 0; } +EOF +if { (eval echo configure:3108: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + irc_curses_termcap=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_curses_termcap=no +fi +rm -f conftest* +LIBS="-ltermcap $irc_save_LIBS" +cat > conftest.$ac_ext <<EOF +#line 3120 "configure" +#include "confdefs.h" + +int main() { +tgetent() +; return 0; } +EOF +if { (eval echo configure:3127: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + irc_termcap=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + irc_termcap=no +fi +rm -f conftest* +LIBS="$irc_save_LIBS" +irc_cv_curses_termcap="irc_ncurses=$irc_ncurses irc_curses=$irc_curses irc_cursesX=$irc_cursesX irc_curses_termcap=$irc_curses_termcap irc_termcap=$irc_termcap" + +fi + +eval $irc_cv_curses_termcap +if test "x$with_ncurses" = xno; then + irc_ncurses=no +fi +if test "x$with_cursesX" = xno; then + irc_cursesX=no +fi +if test "x$with_curses" = xno; then + irc_curses=no + irc_curses_termcap=no +fi +if test "x$with_termcap" = xno; then + irc_termcap=no +fi +if test $irc_ncurses = yes; then + echo "$ac_t""ncurses" 1>&6 + cat >> confdefs.h <<\EOF +#define USE_NCURSES 1 +EOF + + IRC_CURSES_TERMCAP_LIBRARY="-lncurses" +elif test $irc_cursesX = yes; then + echo "$ac_t""cursesX" 1>&6 + cat >> confdefs.h <<\EOF +#define USE_CURSESX 1 +EOF + + IRC_CURSES_TERMCAP_LIBRARY="-lcursesX" +elif test $irc_curses = yes; then + echo "$ac_t""curses" 1>&6 + cat >> confdefs.h <<\EOF +#define USE_CURSES 1 +EOF + + IRC_CURSES_TERMCAP_LIBRARY="-lcurses" +elif test $irc_curses_termcap = yes; then + echo "$ac_t""curses over termcap" 1>&6 + cat >> confdefs.h <<\EOF +#define USE_CURSES 1 +EOF + + IRC_CURSES_TERMCAP_LIBRARY="-lcurses -ltermcap" +elif test $irc_termcap = yes; then + echo "$ac_t""termcap" 1>&6 + cat >> confdefs.h <<\EOF +#define USE_TERMCAP 1 +EOF + + IRC_CURSES_TERMCAP_LIBRARY="-ltermcap" +else + echo "$ac_t""none" 1>&6 + echo "configure: warning: I can't find either ncurses, cursesX, curses or termcap library." 1>&2 + IRC_CURSES_TERMCAP_LIBRARY= +fi + + + +echo $ac_n "checking whether setpgrp takes no argument""... $ac_c" 1>&6 +echo "configure:3200: checking whether setpgrp takes no argument" >&5 +if eval "test \"`echo '$''{'ac_cv_func_setpgrp_void'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: cannot check setpgrp if cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3208 "configure" +#include "confdefs.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +/* + * If this system has a BSD-style setpgrp, which takes arguments, exit + * successfully. + */ +main() +{ + if (setpgrp(1,1) == -1) + exit(0); + else + exit(1); +} + +EOF +if { (eval echo configure:3228: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_setpgrp_void=no +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_setpgrp_void=yes +fi +rm -fr conftest* +fi + + +fi + +echo "$ac_t""$ac_cv_func_setpgrp_void" 1>&6 +if test $ac_cv_func_setpgrp_void = yes; then + cat >> confdefs.h <<\EOF +#define SETPGRP_VOID 1 +EOF + +fi + +echo $ac_n "checking whether setvbuf arguments are reversed""... $ac_c" 1>&6 +echo "configure:3252: checking whether setvbuf arguments are reversed" >&5 +if eval "test \"`echo '$''{'ac_cv_func_setvbuf_reversed'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3260 "configure" +#include "confdefs.h" +#include <stdio.h> +/* If setvbuf has the reversed format, exit 0. */ +main () { + /* This call has the arguments reversed. + A reversed system may check and see that the address of main + is not _IOLBF, _IONBF, or _IOFBF, and return nonzero. */ + if (setvbuf(stdout, _IOLBF, (char *) main, BUFSIZ) != 0) + exit(1); + putc('\r', stdout); + exit(0); /* Non-reversed systems segv here. */ +} +EOF +if { (eval echo configure:3274: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_setvbuf_reversed=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_setvbuf_reversed=no +fi +rm -fr conftest* +fi + +rm -f core core.* *.core +fi + +echo "$ac_t""$ac_cv_func_setvbuf_reversed" 1>&6 +if test $ac_cv_func_setvbuf_reversed = yes; then + cat >> confdefs.h <<\EOF +#define SETVBUF_REVERSED 1 +EOF + +fi + +ac_safe=`echo "vfork.h" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for vfork.h""... $ac_c" 1>&6 +echo "configure:3299: checking for vfork.h" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3304 "configure" +#include "confdefs.h" +#include <vfork.h> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:3309: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define HAVE_VFORK_H 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for working vfork""... $ac_c" 1>&6 +echo "configure:3334: checking for working vfork" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vfork_works'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + echo $ac_n "checking for vfork""... $ac_c" 1>&6 +echo "configure:3340: checking for vfork" >&5 +if eval "test \"`echo '$''{'ac_cv_func_vfork'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3345 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char vfork(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char vfork(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_vfork) || defined (__stub___vfork) +choke me +#else +vfork(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3368: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_vfork=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_vfork=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'vfork`\" = yes"; then + echo "$ac_t""yes" 1>&6 + : +else + echo "$ac_t""no" 1>&6 +fi + +ac_cv_func_vfork_works=$ac_cv_func_vfork +else + cat > conftest.$ac_ext <<EOF +#line 3390 "configure" +#include "confdefs.h" +/* Thanks to Paul Eggert for this test. */ +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_VFORK_H +#include <vfork.h> +#endif +/* On some sparc systems, changes by the child to local and incoming + argument registers are propagated back to the parent. + The compiler is told about this with #include <vfork.h>, + but some compilers (e.g. gcc -O) don't grok <vfork.h>. + Test for this by using a static variable whose address + is put into a register that is clobbered by the vfork. */ +static +#ifdef __cplusplus +sparc_address_test (int arg) +#else +sparc_address_test (arg) int arg; +#endif +{ + static pid_t child; + if (!child) { + child = vfork (); + if (child < 0) { + perror ("vfork"); + _exit(2); + } + if (!child) { + arg = getpid(); + write(-1, "", 0); + _exit (arg); + } + } +} +main() { + pid_t parent = getpid (); + pid_t child; + + sparc_address_test (); + + child = vfork (); + + if (child == 0) { + /* Here is another test for sparc vfork register problems. + This test uses lots of local variables, at least + as many local variables as main has allocated so far + including compiler temporaries. 4 locals are enough for + gcc 1.40.3 on a Solaris 4.1.3 sparc, but we use 8 to be safe. + A buggy compiler should reuse the register of parent + for one of the local variables, since it will think that + parent can't possibly be used any more in this routine. + Assigning to the local variable will thus munge parent + in the parent process. */ + pid_t + p = getpid(), p1 = getpid(), p2 = getpid(), p3 = getpid(), + p4 = getpid(), p5 = getpid(), p6 = getpid(), p7 = getpid(); + /* Convince the compiler that p..p7 are live; otherwise, it might + use the same hardware register for all 8 local variables. */ + if (p != p1 || p != p2 || p != p3 || p != p4 + || p != p5 || p != p6 || p != p7) + _exit(1); + + /* On some systems (e.g. IRIX 3.3), + vfork doesn't separate parent from child file descriptors. + If the child closes a descriptor before it execs or exits, + this munges the parent's descriptor as well. + Test for this by closing stdout in the child. */ + _exit(close(fileno(stdout)) != 0); + } else { + int status; + struct stat st; + + while (wait(&status) != child) + ; + exit( + /* Was there some problem with vforking? */ + child < 0 + + /* Did the child fail? (This shouldn't happen.) */ + || status + + /* Did the vfork/compiler bug occur? */ + || parent != getpid() + + /* Did the file descriptor bug occur? */ + || fstat(fileno(stdout), &st) != 0 + ); + } +} +EOF +if { (eval echo configure:3485: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + ac_cv_func_vfork_works=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + ac_cv_func_vfork_works=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$ac_cv_func_vfork_works" 1>&6 +if test $ac_cv_func_vfork_works = no; then + cat >> confdefs.h <<\EOF +#define vfork fork +EOF + +fi + +for ac_func in setpgrp strchr strrchr memcmp memset memmove memcpy index rindex bcmp bcopy bzero select inet_ntoa inet_aton inet_addr inet_netof getrusage times strerror strtoken strtok sigaction sigset truncate poll vsyslog +do +echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 +echo "configure:3510: checking for $ac_func" >&5 +if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 3515 "configure" +#include "confdefs.h" +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func(); below. */ +#include <assert.h> +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func(); + +int main() { + +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +$ac_func(); +#endif + +; return 0; } +EOF +if { (eval echo configure:3538: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_func_$ac_func=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_func_$ac_func=no" +fi +rm -f conftest* +fi + +if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'` + cat >> confdefs.h <<EOF +#define $ac_tr_func 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + +echo $ac_n "checking for 8-bit clean memcmp""... $ac_c" 1>&6 +echo "configure:3563: checking for 8-bit clean memcmp" >&5 +if eval "test \"`echo '$''{'irc_cv_func_memcmp_clean'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + irc_cv_func_memcmp_clean=no +else + cat > conftest.$ac_ext <<EOF +#line 3571 "configure" +#include "confdefs.h" + +main() +{ + char c0 = 0x40, c1 = 0x80, c2 = 0x81; + exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1); +} + +EOF +if { (eval echo configure:3581: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + irc_cv_func_memcmp_clean=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + irc_cv_func_memcmp_clean=no +fi +rm -fr conftest* +fi + +fi + +echo "$ac_t""$irc_cv_func_memcmp_clean" 1>&6 +if test $irc_cv_func_memcmp_clean = no; then + cat >> confdefs.h <<\EOF +#define MEMCMP_BROKEN 1 +EOF + +fi + +echo $ac_n "checking whether select or poll system call will be used""... $ac_c" 1>&6 +echo "configure:3604: checking whether select or poll system call will be used" >&5 +if eval "test \"`echo '$''{'irc_cv_select_poll'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$irc_cv_sun" != "no" && test "x$irc_cv_solaris_2" = "xno"; then + # we don't like SunOS' poll() function + irc_cv_select_poll=select +else + if test "$ac_cv_func_poll" = "yes"; then + irc_cv_select_poll=poll + else + irc_cv_select_poll=select + fi +fi +fi + + +if test "$irc_cv_select_poll" = "poll"; then + echo "$ac_t""poll" 1>&6 + cat >> confdefs.h <<\EOF +#define USE_POLL 1 +EOF + + if test ! "$irc_cv_linux" = "no"; then + echo "configure: warning: Aiiie.. This is linux. poll() is known to be broken for some releases (2.0.x with libc6?). You may want to edit setup.h to undefine USE_POLL" 1>&2 + fi +else + echo "$ac_t""select" 1>&6 +fi + + +echo $ac_n "checking for signal implementation""... $ac_c" 1>&6 +echo "configure:3636: checking for signal implementation" >&5 +if eval "test \"`echo '$''{'irc_cv_signal_implementation'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test x$ac_cv_func_sigaction = xyes; then + irc_cv_signal_implementation=posix_sigaction +elif test x$ac_cv_func_sigset = xyes; then + irc_cv_signal_implementation=bsd_sigset +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3649 "configure" +#include "confdefs.h" + +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#ifndef SIGCHLD +#define SIGCHLD SIGCLD +#endif + +int got = 0; + +RETSIGTYPE hand() +{ + got++; +} + +main() +{ + (void)signal(SIGCHLD, hand); + kill(getpid(), SIGCHLD); + kill(getpid(), SIGCHLD); + if (got < 2) + exit(1); + exit(0); +} + +EOF +if { (eval echo configure:3680: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + irc_cv_signal_implementation=bsd_signal +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + irc_cv_signal_implementation=sysv_signal +fi +rm -fr conftest* +fi + +fi + +fi + +if test $irc_cv_signal_implementation = posix_sigaction; then + echo "$ac_t""using POSIX sigaction" 1>&6 + cat >> confdefs.h <<\EOF +#define POSIX_SIGNALS 1 +EOF + +elif test $irc_cv_signal_implementation = bsd_sigset; then + echo "$ac_t""using BSD sigset" 1>&6 + cat >> confdefs.h <<\EOF +#define BSD_RELIABLE_SIGNALS 1 +EOF + + cat >> confdefs.h <<\EOF +#define signal sigset +EOF + +elif test $irc_cv_signal_implementation = bsd_signal; then + echo "$ac_t""using reliable BSD signal" 1>&6 + cat >> confdefs.h <<\EOF +#define BSD_RELIABLE_SIGNALS 1 +EOF + +else + echo "$ac_t""using unreliable SystemV signal" 1>&6 + cat >> confdefs.h <<\EOF +#define SYSV_UNRELIABLE_SIGNALS 1 +EOF + +fi + +echo $ac_n "checking for a working non-blocking system""... $ac_c" 1>&6 +echo "configure:3727: checking for a working non-blocking system" >&5 +if eval "test \"`echo '$''{'irc_cv_non_blocking_system'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + +irc_precode='#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +RETSIGTYPE alarmed() +{ + exit(1); +} + +main() +{ + char b[12]; + struct sockaddr_in x; + int f, l = sizeof(x); + f = socket(AF_INET, SOCK_DGRAM, 0); + if (f >= 0 && !(fcntl(f, F_SETFL, ' +irc_postcode='))) + { + signal(SIGALRM, alarmed); + alarm(3); + recvfrom(f, b, 12, 0, &x, &l); + alarm(0); + exit(0); + } + exit(1); +}' +irc_code_posix="${irc_precode}O_NONBLOCK${irc_postcode}" +irc_code_bsd="${irc_precode}O_NDELAY${irc_postcode}" +irc_code_sysv="${irc_precode}FIONBIO${irc_postcode}" +if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3783 "configure" +#include "confdefs.h" +$irc_code_posix +EOF +if { (eval echo configure:3787: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + irc_cv_non_blocking_system=posix +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3798 "configure" +#include "confdefs.h" +$irc_code_bsd +EOF +if { (eval echo configure:3802: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + irc_cv_non_blocking_system=bsd +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3813 "configure" +#include "confdefs.h" +$irc_code_sysv +EOF +if { (eval echo configure:3817: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + irc_cv_non_blocking_system=sysv +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + irc_cv_non_blocking_system=none +fi +rm -fr conftest* +fi + +fi +rm -fr conftest* +fi + +fi +rm -fr conftest* +fi + + +fi + +if test $irc_cv_non_blocking_system = posix; then + echo "$ac_t""using POSIX O_NONBLOCK" 1>&6 + cat >> confdefs.h <<\EOF +#define NBLOCK_POSIX 1 +EOF + +elif test $irc_cv_non_blocking_system = bsd; then + echo "$ac_t""using BSD O_NDELAY" 1>&6 + cat >> confdefs.h <<\EOF +#define NBLOCK_BSD 1 +EOF + +elif test $irc_cv_non_blocking_system = sysv; then + echo "$ac_t""using SystemV FIONBIO" 1>&6 + cat >> confdefs.h <<\EOF +#define NBLOCK_SYSV 1 +EOF + +else + echo "$ac_t""using none" 1>&6 + echo "configure: warning: I can't find a working non-blocking system." 1>&2 +fi + +echo $ac_n "checking for working stdarg""... $ac_c" 1>&6 +echo "configure:3864: checking for working stdarg" >&5 +if eval "test \"`echo '$''{'irc_cv_stdarg'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test "$cross_compiling" = yes; then + { echo "configure: error: can not run test program while cross compiling" 1>&2; exit 1; } +else + cat > conftest.$ac_ext <<EOF +#line 3872 "configure" +#include "confdefs.h" + +#if HAVE_STDIO_H +#include <stdio.h> +#endif +#if HAVE_STDARG_H +#include <stdarg.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#endif + +char buf1[256]; + +int level1(char *data, char *format, va_list ap) +{ + return vsprintf(data, format, ap); +} + +int level2(char *data, int rounds, char *format, va_list ap) +{ + if(!--rounds) + return level1(data, format, ap); + else { + if(rounds == 2) { + va_list ap2 = ap; + char *arg = va_arg(ap2, char *); + strcpy(buf1, arg); + } + return level2(data, rounds, format, ap); + } +} + +int level3(char *data, char *format, va_list ap) +{ + return level2(data, 5, format, ap); +} + +int dotest(int size, char *val, char *data) +{ + if(size != strlen(val)) + return 0; + if(strcmp(data, val)) + return 0; + if(strcmp(buf1, "was")) + return 0; + return 1; +} + +int base(char *val, char *format, ...) +{ + int res = 1; + char data[256]; + + { + va_list ap; + data[0]=0; + va_start(ap, format); + res = dotest(level3(data, format, ap), val, data); + va_end(ap); + } + + { + va_list ap; + data[0]=0; + va_start(ap, format); + res = res && dotest(level3(data, format, ap), val, data); + va_end(ap); + } + + return res; +} + +int main(void) +{ + int res = base("toto was here ! 42", "toto %s here ! %d", "was", 42); + + exit(res ? 0 : 1); +} + +EOF +if { (eval echo configure:3954: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +then + irc_cv_stdarg=yes +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -fr conftest* + irc_cv_stdarg=no +fi +rm -fr conftest* +fi + + +fi + +if test $irc_cv_stdarg = yes; then + echo "$ac_t""yes" 1>&6 + cat >> confdefs.h <<\EOF +#define USE_STDARG 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi + +echo $ac_n "checking for resolver configuration file""... $ac_c" 1>&6 +echo "configure:3980: checking for resolver configuration file" >&5 +if eval "test \"`echo '$''{'irc_cv_path_resconf'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + if test -z "$irc_resconf"; then + irc_cv_path_resconf="/etc/resolv.conf"; + else + irc_cv_path_resconf="$irc_resconf"; + fi + +fi + +echo "$ac_t""$irc_cv_path_resconf" 1>&6 +cat >> confdefs.h <<EOF +#define IRC_RESCONF "$irc_cv_path_resconf" +EOF + +if test ! -r "$irc_cv_path_resconf"; then + echo "configure: warning: Unable to read \"$irc_cv_path_resconf\"! Without resolver configuration file, the server won't work." 1>&2 +fi + +# Check whether --enable-ip6 or --disable-ip6 was given. +if test "${enable_ip6+set}" = set; then + enableval="$enable_ip6" + : +fi + +if test "x$enable_ip6" != x; then + cat >> confdefs.h <<\EOF +#define INET6 1 +EOF + + echo $ac_n "checking IPv6 system type""... $ac_c" 1>&6 +echo "configure:4013: checking IPv6 system type" >&5 + if eval "test \"`echo '$''{'irc_cv_v6type'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + + if test -d /usr/inet6; then + irc_cv_v6type=linux + else + cat > conftest.$ac_ext <<EOF +#line 4022 "configure" +#include "confdefs.h" +dnl +#include <netinet/in.h> +#ifdef IPV6_INRIA_VERSION +yes +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + irc_cv_v6type=inria +else + rm -rf conftest* + cat > conftest.$ac_ext <<EOF +#line 4037 "configure" +#include "confdefs.h" +#include <netinet/in.h> +#ifdef __KAME__ +yes +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + irc_cv_v6type=kame +else + rm -rf conftest* + cat > conftest.$ac_ext <<EOF +#line 4051 "configure" +#include "confdefs.h" +#include <sys/param.h> +#ifdef _TOSHIBA_INET6 +yes +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + irc_cv_v6type=toshiba +else + rm -rf conftest* + cat > conftest.$ac_ext <<EOF +#line 4065 "configure" +#include "confdefs.h" +#include </usr/local/v6/include/sys/types.h> +#ifdef __V6D__ +yes +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + irc_cv_v6type=v6d +else + rm -rf conftest* + cat > conftest.$ac_ext <<EOF +#line 4079 "configure" +#include "confdefs.h" +#include <sys/param.h> +#ifdef _ZETA_MINAMI_INET6 +yes +#endif +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "yes" >/dev/null 2>&1; then + rm -rf conftest* + irc_cv_v6type=zeta +fi +rm -f conftest* + +fi +rm -f conftest* + +fi +rm -f conftest* + +fi +rm -f conftest* + +fi +rm -f conftest* + + fi +fi + + echo "$ac_t""$irc_cv_v6type" 1>&6 + + case $irc_cv_v6type in + kame) + LIBS="-L/usr/local/v6/lib -linet6 $LIBS" + CFLAGS="$CFLAGS -I/usr/local/v6/include" + ;; + linux) + LIBS="-L/usr/inet6/lib -linet6 $LIBS" + CFLAGS="$CFLAGS -I/usr/inet6/include" + ;; + toshiba) + LIBS="-L/usr/local/v6/lib -linet6 $LIBS" + CFLAGS="$CFLAGS -I/usr/local/v6/include" + ;; + v6d) + LIBS="-L/usr/local/v6/lib -lv6 $LIBS" + CFLAGS="$CFLAGS -I/usr/local/v6/include" + ;; + zeta) + LIBS="-L/usr/local/v6/lib -linet6 $LIBS" + CFLAGS="$CFLAGS -I/usr/local/v6/include" + ;; + esac + + echo $ac_n "checking for IPv6 name server addresses in resolv.conf ($irc_cv_path_resconf)""... $ac_c" 1>&6 +echo "configure:4134: checking for IPv6 name server addresses in resolv.conf ($irc_cv_path_resconf)" >&5 + if grep nameserver $irc_cv_path_resconf | grep ':' >/dev/null 2>&1; then + echo "$ac_t""yes" 1>&6 + echo "configure: warning: $irc_cv_path_resconf is not setup correctly." 1>&2 + else + echo "$ac_t""no" 1>&6 + fi +fi + +# Check whether --enable-dsm or --disable-dsm was given. +if test "${enable_dsm+set}" = set; then + enableval="$enable_dsm" + : +fi + +if test "x$enable_dsm" != x; then + cat >> confdefs.h <<\EOF +#define USE_DSM 1 +EOF + + for ac_hdr in dlfcn.h +do +ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` +echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 +echo "configure:4158: checking for $ac_hdr" >&5 +if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 4163 "configure" +#include "confdefs.h" +#include <$ac_hdr> +EOF +ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" +{ (eval echo configure:4168: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` +if test -z "$ac_err"; then + rm -rf conftest* + eval "ac_cv_header_$ac_safe=yes" +else + echo "$ac_err" >&5 + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_header_$ac_safe=no" +fi +rm -f conftest* +fi +if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then + echo "$ac_t""yes" 1>&6 + ac_tr_hdr=HAVE_`echo $ac_hdr | sed 'y%abcdefghijklmnopqrstuvwxyz./-%ABCDEFGHIJKLMNOPQRSTUVWXYZ___%'` + cat >> confdefs.h <<EOF +#define $ac_tr_hdr 1 +EOF + +else + echo "$ac_t""no" 1>&6 +fi +done + + echo $ac_n "checking for dlclose in -ldl""... $ac_c" 1>&6 +echo "configure:4195: checking for dlclose in -ldl" >&5 +ac_lib_var=`echo dl'_'dlclose | sed 'y%./+-%__p_%'` +if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + ac_save_LIBS="$LIBS" +LIBS="-ldl $LIBS" +cat > conftest.$ac_ext <<EOF +#line 4203 "configure" +#include "confdefs.h" +/* Override any gcc2 internal prototype to avoid an error. */ +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char dlclose(); + +int main() { +dlclose() +; return 0; } +EOF +if { (eval echo configure:4214: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=yes" +else + echo "configure: failed program was:" >&5 + cat conftest.$ac_ext >&5 + rm -rf conftest* + eval "ac_cv_lib_$ac_lib_var=no" +fi +rm -f conftest* +LIBS="$ac_save_LIBS" + +fi +if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then + echo "$ac_t""yes" 1>&6 + IRC_DLIB="-ldl" +else + echo "$ac_t""no" 1>&6 +fi + + +fi + +echo $ac_n "checking whether this is an alpha/beta release""... $ac_c" 1>&6 +echo "configure:4238: checking whether this is an alpha/beta release" >&5 +if eval "test \"`echo '$''{'irc_cv_alpha_beta'+set}'`\" = set"; then + echo $ac_n "(cached) $ac_c" 1>&6 +else + cat > conftest.$ac_ext <<EOF +#line 4243 "configure" +#include "confdefs.h" +#include "../common/patchlevel.h" +#ifdef PATCHLEVEL +PATCHLEVEL +#else +"0000000000" +#endif + +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + egrep "^\"......00" >/dev/null 2>&1; then + rm -rf conftest* + irc_cv_alpha_beta= +else + rm -rf conftest* + irc_cv_alpha_beta=yes +fi +rm -f conftest* + + +fi + +if test x$irc_cv_alpha_beta = xyes; then + echo "$ac_t""yes" 1>&6 + echo "configure: warning: + +This is a development version of the package, +it is not intended to be used in a production environment. +" 1>&2 +# if test ! "$ac_test_CFLAGS" = set; then +# if test x$ac_cv_prog_cc_g = xyes -o x$GCC = x; then +# CFLAGS="$CFLAGS -g" +# fi +# fi +else + echo "$ac_t""no" 1>&6 +# if test ! "${LDFLAGS+set}" = set; then +# LDFLAGS="-s" +# fi +fi + +if test ! "$ac_test_CFLAGS" = set; then + if test x$ac_cv_prog_cc_g = xyes -o x$GCC = x; then + CFLAGS="$CFLAGS -g" + fi +fi + + +trap '' 1 2 15 +cat > confcache <<\EOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs. It is not useful on other systems. +# If it contains results you don't want to keep, you may remove or edit it. +# +# By default, configure uses ./config.cache as the cache file, +# creating it if it does not exist already. You can give configure +# the --cache-file=FILE option to use a different cache file; that is +# what configure does when it calls configure scripts in +# subdirectories, so they share the cache. +# Giving --cache-file=/dev/null disables caching, for debugging configure. +# config.status only pays attention to the cache file if you give it the +# --recheck option to rerun configure. +# +EOF +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, don't put newlines in cache variables' values. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +(set) 2>&1 | + case `(ac_space=' '; set | grep ac_space) 2>&1` in + *ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote substitution + # turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + -e "s/'/'\\\\''/g" \ + -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p" + ;; + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p' + ;; + esac >> confcache +if cmp -s $cache_file confcache; then + : +else + if test -w $cache_file; then + echo "updating cache $cache_file" + cat confcache > $cache_file + else + echo "not updating unwritable cache $cache_file" + fi +fi +rm -f confcache + +trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15 + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Any assignment to VPATH causes Sun make to only execute +# the first set of double-colon rules, so remove it if not needed. +# If there is a colon in the path, we need to keep it. +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d' +fi + +trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15 + +DEFS=-DHAVE_CONFIG_H + +# Without the "./", some shells look in PATH for config.status. +: ${CONFIG_STATUS=./config.status} + +echo creating $CONFIG_STATUS +rm -f $CONFIG_STATUS +cat > $CONFIG_STATUS <<EOF +#! /bin/sh +# Generated automatically by configure. +# Run this file to recreate the current configuration. +# This directory was configured as follows, +# on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# +# $0 $ac_configure_args +# +# Compiler output produced by configure, useful for debugging +# configure, is in ./config.log if it exists. + +ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]" +for ac_option +do + case "\$ac_option" in + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion" + exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;; + -version | --version | --versio | --versi | --vers | --ver | --ve | --v) + echo "$CONFIG_STATUS generated by autoconf version 2.13" + exit 0 ;; + -help | --help | --hel | --he | --h) + echo "\$ac_cs_usage"; exit 0 ;; + *) echo "\$ac_cs_usage"; exit 1 ;; + esac +done + +ac_given_srcdir=$srcdir +ac_given_INSTALL="$INSTALL" + +trap 'rm -fr `echo "Makefile:../support/Makefile.in version.c.SH:../ircd/version.c.SH.in sums:../support/sums.in tkconf.h:../support/tkconf.h.dist setup.h:../support/setup.h.in" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15 +EOF +cat >> $CONFIG_STATUS <<EOF + +# Protect against being on the right side of a sed subst in config.status. +sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g; + s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF +$ac_vpsub +$extrasub +s%@logdir@%$logdir%g +s%@SHELL@%$SHELL%g +s%@CFLAGS@%$CFLAGS%g +s%@CPPFLAGS@%$CPPFLAGS%g +s%@CXXFLAGS@%$CXXFLAGS%g +s%@FFLAGS@%$FFLAGS%g +s%@DEFS@%$DEFS%g +s%@LDFLAGS@%$LDFLAGS%g +s%@LIBS@%$LIBS%g +s%@exec_prefix@%$exec_prefix%g +s%@prefix@%$prefix%g +s%@program_transform_name@%$program_transform_name%g +s%@bindir@%$bindir%g +s%@sbindir@%$sbindir%g +s%@libexecdir@%$libexecdir%g +s%@datadir@%$datadir%g +s%@sysconfdir@%$sysconfdir%g +s%@sharedstatedir@%$sharedstatedir%g +s%@localstatedir@%$localstatedir%g +s%@libdir@%$libdir%g +s%@includedir@%$includedir%g +s%@oldincludedir@%$oldincludedir%g +s%@infodir@%$infodir%g +s%@mandir@%$mandir%g +s%@host@%$host%g +s%@host_alias@%$host_alias%g +s%@host_cpu@%$host_cpu%g +s%@host_vendor@%$host_vendor%g +s%@host_os@%$host_os%g +s%@target@%$target%g +s%@target_alias@%$target_alias%g +s%@target_cpu@%$target_cpu%g +s%@target_vendor@%$target_vendor%g +s%@target_os@%$target_os%g +s%@build@%$build%g +s%@build_alias@%$build_alias%g +s%@build_cpu@%$build_cpu%g +s%@build_vendor@%$build_vendor%g +s%@build_os@%$build_os%g +s%@CC@%$CC%g +s%@CPP@%$CPP%g +s%@AWK@%$AWK%g +s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g +s%@INSTALL_DATA@%$INSTALL_DATA%g +s%@SUM@%$SUM%g +s%@IRC_ZLIB_INCLUDE@%$IRC_ZLIB_INCLUDE%g +s%@IRC_ZLIB_LIBRARY@%$IRC_ZLIB_LIBRARY%g +s%@IRC_CURSES_TERMCAP_LIBRARY@%$IRC_CURSES_TERMCAP_LIBRARY%g +s%@IRC_DLIB@%$IRC_DLIB%g + +CEOF +EOF + +cat >> $CONFIG_STATUS <<\EOF + +# Split the substitutions into bite-sized pieces for seds with +# small command number limits, like on Digital OSF/1 and HP-UX. +ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script. +ac_file=1 # Number of current file. +ac_beg=1 # First line for current file. +ac_end=$ac_max_sed_cmds # Line after last line for current file. +ac_more_lines=: +ac_sed_cmds="" +while $ac_more_lines; do + if test $ac_beg -gt 1; then + sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file + else + sed "${ac_end}q" conftest.subs > conftest.s$ac_file + fi + if test ! -s conftest.s$ac_file; then + ac_more_lines=false + rm -f conftest.s$ac_file + else + if test -z "$ac_sed_cmds"; then + ac_sed_cmds="sed -f conftest.s$ac_file" + else + ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file" + fi + ac_file=`expr $ac_file + 1` + ac_beg=$ac_end + ac_end=`expr $ac_end + $ac_max_sed_cmds` + fi +done +if test -z "$ac_sed_cmds"; then + ac_sed_cmds=cat +fi +EOF + +cat >> $CONFIG_STATUS <<EOF + +CONFIG_FILES=\${CONFIG_FILES-"Makefile:../support/Makefile.in version.c.SH:../ircd/version.c.SH.in sums:../support/sums.in tkconf.h:../support/tkconf.h.dist"} +EOF +cat >> $CONFIG_STATUS <<\EOF +for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories. + + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`" + # A "../" for each directory in $ac_dir_suffix. + ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'` + else + ac_dir_suffix= ac_dots= + fi + + case "$ac_given_srcdir" in + .) srcdir=. + if test -z "$ac_dots"; then top_srcdir=. + else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;; + /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;; + *) # Relative path. + srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix" + top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + + case "$ac_given_INSTALL" in + [/$]*) INSTALL="$ac_given_INSTALL" ;; + *) INSTALL="$ac_dots$ac_given_INSTALL" ;; + esac + + echo creating "$ac_file" + rm -f "$ac_file" + configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure." + case "$ac_file" in + *Makefile*) ac_comsub="1i\\ +# $configure_input" ;; + *) ac_comsub= ;; + esac + + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + sed -e "$ac_comsub +s%@configure_input@%$configure_input%g +s%@srcdir@%$srcdir%g +s%@top_srcdir@%$top_srcdir%g +s%@INSTALL@%$INSTALL%g +" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file +fi; done +rm -f conftest.s* + +# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where +# NAME is the cpp macro being defined and VALUE is the value it is being given. +# +# ac_d sets the value in "#define NAME VALUE" lines. +ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)' +ac_dB='\([ ][ ]*\)[^ ]*%\1#\2' +ac_dC='\3' +ac_dD='%g' +# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE". +ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_uB='\([ ]\)%\1#\2define\3' +ac_uC=' ' +ac_uD='\4%g' +# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE". +ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)' +ac_eB='$%\1#\2define\3' +ac_eC=' ' +ac_eD='%g' + +if test "${CONFIG_HEADERS+set}" != set; then +EOF +cat >> $CONFIG_STATUS <<EOF + CONFIG_HEADERS="setup.h:../support/setup.h.in" +EOF +cat >> $CONFIG_STATUS <<\EOF +fi +for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then + # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in". + case "$ac_file" in + *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'` + ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + *) ac_file_in="${ac_file}.in" ;; + esac + + echo creating $ac_file + + rm -f conftest.frag conftest.in conftest.out + ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"` + cat $ac_file_inputs > conftest.in + +EOF + +# Transform confdefs.h into a sed script conftest.vals that substitutes +# the proper values into config.h.in to produce config.h. And first: +# Protect against being on the right side of a sed subst in config.status. +# Protect against being in an unquoted here document in config.status. +rm -f conftest.vals +cat > conftest.hdr <<\EOF +s/[\\&%]/\\&/g +s%[\\$`]%\\&%g +s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp +s%ac_d%ac_u%gp +s%ac_u%ac_e%gp +EOF +sed -n -f conftest.hdr confdefs.h > conftest.vals +rm -f conftest.hdr + +# This sed command replaces #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +cat >> conftest.vals <<\EOF +s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */% +EOF + +# Break up conftest.vals because some shells have a limit on +# the size of here documents, and old seds have small limits too. + +rm -f conftest.tail +while : +do + ac_lines=`grep -c . conftest.vals` + # grep -c gives empty output for an empty file on some AIX systems. + if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi + # Write a limited-size here document to conftest.frag. + echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS + sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS + echo 'CEOF + sed -f conftest.frag conftest.in > conftest.out + rm -f conftest.in + mv conftest.out conftest.in +' >> $CONFIG_STATUS + sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail + rm -f conftest.vals + mv conftest.tail conftest.vals +done +rm -f conftest.vals + +cat >> $CONFIG_STATUS <<\EOF + rm -f conftest.frag conftest.h + echo "/* $ac_file. Generated automatically by configure. */" > conftest.h + cat conftest.in >> conftest.h + rm -f conftest.in + if cmp -s $ac_file conftest.h 2>/dev/null; then + echo "$ac_file is unchanged" + rm -f conftest.h + else + # Remove last slash and all that follows it. Not all systems have dirname. + ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'` + if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then + # The file is in a subdirectory. + test ! -d "$ac_dir" && mkdir "$ac_dir" + fi + rm -f $ac_file + mv conftest.h $ac_file + fi +fi; done + +EOF +cat >> $CONFIG_STATUS <<EOF + +EOF +cat >> $CONFIG_STATUS <<\EOF + +exit 0 +EOF +chmod +x $CONFIG_STATUS +rm -fr confdefs* $ac_clean_files +test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1 + + +chmod a+x version.c.SH + diff --git a/support/configure.in b/support/configure.in new file mode 100644 index 0000000..3d425e5 --- /dev/null +++ b/support/configure.in @@ -0,0 +1,1519 @@ +dnl configure.in for irc-2.10.1 +dnl Matthew Green (mrg@mame.mu.oz.au), Alain Nissen (Alain.Nissen@ulg.ac.be) +dnl using portions of Avalon's Config and GNU Autoconf 1.12. + +dnl --------- +dnl new tests +dnl --------- + +AC_DEFUN(IRC_PATH_ZLIB, +[AC_MSG_CHECKING(for zlib package) +AC_ARG_WITH(zlib, [ --with-zlib checks for zlib; if found, enables compressed links]) +AC_ARG_WITH(zlib, [ --without-zlib does not check for zlib; disables compressed links]) +if test "x$with_zlib" = xno; then + no_zlib=yes +else +AC_CACHE_VAL(irc_cv_path_zlib, +[no_zlib=yes +no_zlib_include=yes +no_zlib_library=yes +AC_TRY_CPP([#include <zlib.h>], +[no_zlib_include= +irc_zlib_include=], +[for irc_dir in "$irc_zlib_include" \ + `test -z "$irc_zlib_prefix" || echo "$irc_zlib_prefix/include"` \ + `echo "$irc_zlib_library" | sed s/lib/include/` \ + /usr/include /usr/local/include /usr/unsupported/include \ + /usr/share/include /usr/local/share/include /include \ + /usr/zlib/include /usr/local/zlib/include \ + /usr/include/zlib /usr/local/include/zlib \ + /usr/unsupported/include/zlib /usr/share/include/zlib \ + /usr/local/share/include/zlib /include/zlib \ + /usr/zlib/include/zlib /usr/local/zlib/include/zlib; \ + do + if test -r "$irc_dir/zlib.h"; then + no_zlib_include= + irc_zlib_include=$irc_dir + break + fi + done +]) +irc_save_LIBS="$LIBS" +LIBS="-lz $LIBS" +AC_TRY_LINK(, +[inflate()], +[no_zlib_library= +irc_zlib_library= +LIBS="$irc_save_LIBS"], +[LIBS="$irc_save_LIBS" +for irc_dir in "$irc_zlib_library" \ + `test -z "$irc_zlib_prefix" || echo "$irc_zlib_prefix/lib"` \ + `echo "$irc_zlib_include" | sed s/include/lib/` \ + /usr/lib /usr/local/lib /usr/unsupported/lib \ + /usr/share/lib /usr/local/share/lib /lib /usr/zlib/lib \ + /usr/local/zlib/lib /usr/lib/zlib /usr/local/lib/zlib \ + /usr/unsupported/lib/zlib /usr/share/lib/zlib \ + /usr/local/share/lib/zlib /lib/zlib \ + /usr/zlib/lib/zlib /usr/local/zlib/lib/zlib; \ +do + for irc_extension in a so sl; do + if test -r $irc_dir/libz.$irc_extension; then + no_zlib_library= + irc_zlib_library=$irc_dir + break 2 + fi + done +done +]) +if test "x$no_zlib_include" = x && test "x$no_zlib_library" = x; then + no_zlib= +fi +if test "$no_zlib" = yes; then + irc_cv_path_zlib="no_zlib=yes" +else + irc_cv_path_zlib="no_zlib= irc_zlib_include=$irc_zlib_include irc_zlib_library=$irc_zlib_library" +fi]) + eval "$irc_cv_path_zlib" +fi +if test "$no_zlib" = yes; then + IRC_ZLIB_LIBRARY= + IRC_ZLIB_INCLUDE= + AC_MSG_RESULT(no) +else + AC_DEFINE(USE_ZLIB) + if test "x$irc_zlib_library" = x; then + irc_zlib_library_message="found by the linker" + IRC_ZLIB_LIBRARY=-lz + else + irc_zlib_library_message="in $irc_zlib_library" + IRC_ZLIB_LIBRARY=-L$irc_zlib_library + if test ! "$irc_cv_solaris_2" = no; then + IRC_ZLIB_LIBRARY="$IRC_ZLIB_LIBRARY -R$irc_zlib_library" + fi + IRC_ZLIB_LIBRARY="$IRC_ZLIB_LIBRARY -lz" + fi + if test "x$irc_zlib_include" = x; then + irc_zlib_include_message="found by the compiler" + IRC_ZLIB_INCLUDE= + else + irc_zlib_include_message="in $irc_zlib_include" + IRC_ZLIB_INCLUDE=-I$irc_zlib_include + fi + AC_MSG_RESULT([]) + AC_MSG_RESULT([ library $irc_zlib_library_message]) + AC_MSG_RESULT([ header $irc_zlib_include_message]) +fi +AC_SUBST(IRC_ZLIB_INCLUDE) +AC_SUBST(IRC_ZLIB_LIBRARY) +]) + + +AC_DEFUN(IRC_CURSES_TERMCAP, +[AC_MSG_CHECKING([which curses or termcap library will be used]) +AC_ARG_WITH(ncurses, [ --without-ncurses does not look for ncurses library, will not use it]) +AC_ARG_WITH(cursesX, [ --without-cursesX does not look for cursesX library, will not use it]) +AC_ARG_WITH(curses, [ --without-curses does not look for curses library, will not use it]) +AC_ARG_WITH(termcap, [ --without-termcap does not look for termcap library, will not use it]) +AC_CACHE_VAL(irc_cv_curses_termcap, +[irc_save_LIBS="$LIBS" +LIBS="-lncurses $irc_save_LIBS" +AC_TRY_LINK(, +[initscr()], +irc_ncurses=yes, +irc_ncurses=no) +LIBS="-lcursesX $irc_save_LIBS" +AC_TRY_LINK(, +[initscr()], +irc_cursesX=yes, +irc_cursesX=no) +LIBS="-lcurses $irc_save_LIBS" +AC_TRY_LINK(, +[initscr()], +irc_curses=yes, +irc_curses=no) +LIBS="-lcurses -ltermcap $irc_save_LIBS" +AC_TRY_LINK(, +[initscr()], +irc_curses_termcap=yes, +irc_curses_termcap=no) +LIBS="-ltermcap $irc_save_LIBS" +AC_TRY_LINK(, +[tgetent()], +irc_termcap=yes, +irc_termcap=no) +LIBS="$irc_save_LIBS" +irc_cv_curses_termcap="irc_ncurses=$irc_ncurses irc_curses=$irc_curses irc_cursesX=$irc_cursesX irc_curses_termcap=$irc_curses_termcap irc_termcap=$irc_termcap" +]) +eval $irc_cv_curses_termcap +if test "x$with_ncurses" = xno; then + irc_ncurses=no +fi +if test "x$with_cursesX" = xno; then + irc_cursesX=no +fi +if test "x$with_curses" = xno; then + irc_curses=no + irc_curses_termcap=no +fi +if test "x$with_termcap" = xno; then + irc_termcap=no +fi +if test $irc_ncurses = yes; then + AC_MSG_RESULT(ncurses) + AC_DEFINE(USE_NCURSES) + IRC_CURSES_TERMCAP_LIBRARY="-lncurses" +elif test $irc_cursesX = yes; then + AC_MSG_RESULT(cursesX) + AC_DEFINE(USE_CURSESX) + IRC_CURSES_TERMCAP_LIBRARY="-lcursesX" +elif test $irc_curses = yes; then + AC_MSG_RESULT(curses) + AC_DEFINE(USE_CURSES) + IRC_CURSES_TERMCAP_LIBRARY="-lcurses" +elif test $irc_curses_termcap = yes; then + AC_MSG_RESULT(curses over termcap) + AC_DEFINE(USE_CURSES) + IRC_CURSES_TERMCAP_LIBRARY="-lcurses -ltermcap" +elif test $irc_termcap = yes; then + AC_MSG_RESULT(termcap) + AC_DEFINE(USE_TERMCAP) + IRC_CURSES_TERMCAP_LIBRARY="-ltermcap" +else + AC_MSG_RESULT(none) + AC_MSG_WARN([I can't find either ncurses, cursesX, curses or termcap library.]) + IRC_CURSES_TERMCAP_LIBRARY= +fi +AC_SUBST(IRC_CURSES_TERMCAP_LIBRARY) +]) + + +AC_DEFUN(IRC_UNION_WAIT, +[AC_MSG_CHECKING(whether an union wait * is mandatory in waitpid) +AC_CACHE_VAL(irc_cv_type_union_wait, +AC_TRY_COMPILE([ +#if HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif], +[ +int status; +waitpid(-1, &status, 0); +], +irc_cv_type_union_wait=no, +AC_TRY_COMPILE([ +#if HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif], +[ +union wait status; +waitpid(-1, &status, 0); +], +irc_cv_type_union_wait=yes, +irc_cv_type_union_wait=no))) +if test $irc_cv_type_union_wait = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(USE_UNION_WAIT) +else + AC_MSG_RESULT(no) +fi +]) + + +AC_DEFUN(IRC_SUN, +[AC_MSG_CHECKING([for SunOS]) +AC_CACHE_VAL(irc_cv_sun, +[if test "x`(uname) 2>/dev/null`" = "xSunOS"; then + irc_cv_sun="`uname -r`" +else + irc_cv_sun=no +fi +]) +irc_cv_solaris_2=no +if test "$irc_sun" = no; then + AC_MSG_RESULT(no) +else + if uname -r 2>/dev/null | grep "^5" >/dev/null; then + irc_cv_solaris_2="`uname -r | sed -e \"s/^5/2/g\"`" + AC_MSG_RESULT([yes, Solaris $irc_cv_solaris_2]) + AC_DEFINE(SOLARIS_2) + if echo "$irc_cv_solaris_2" | egrep "^2\.(0|1|2)" >/dev/null; then + AC_DEFINE(SOLARIS_2_0_2_1_2_2) + elif echo "$irc_cv_solaris_2" | grep "^2\.3" >/dev/null; then + AC_DEFINE(SOLARIS_2_3) + fi + else + AC_MSG_RESULT([yes, SunOS $irc_cv_sun]) + fi +fi +]) + + +AC_DEFUN(IRC_DECL_SYS_ERRLIST, +[AC_CACHE_CHECK([for sys_errlist declaration in stdio.h, errno.h or sys/errno.h], + irc_cv_decl_sys_errlist, +[AC_TRY_COMPILE([ +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_STDIO_H +#include <stdio.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif], +[char *msg = sys_errlist[0];], + irc_cv_decl_sys_errlist=yes, irc_cv_decl_sys_errlist=no)]) +if test $irc_cv_decl_sys_errlist = yes; then + AC_DEFINE(SYS_ERRLIST_DECLARED) +fi +]) + + +AC_DEFUN(IRC_DECL_SYS_NERR, +[AC_CACHE_CHECK([for sys_nerr declaration in stdio.h, errno.h or sys/errno.h], + irc_cv_decl_sys_nerr, +[AC_TRY_COMPILE([ +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_STDIO_H +#include <stdio.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif], +[int num = sys_nerr;], + irc_cv_decl_sys_nerr=yes, irc_cv_decl_sys_nerr=no)]) +if test $irc_cv_decl_sys_nerr = yes; then + AC_DEFINE(SYS_NERR_DECLARED) +fi +]) + + +AC_DEFUN(IRC_DECL_ERRNO, +[AC_CACHE_CHECK([for errno declaration in errno.h or sys/errno.h], + irc_cv_decl_errno, +[AC_TRY_COMPILE([ +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif], +[int num = errno;], + irc_cv_decl_errno=yes, irc_cv_decl_errno=no)]) +if test $irc_cv_decl_errno = yes; then + AC_DEFINE(ERRNO_DECLARED) +fi +]) + + +AC_DEFUN(IRC_DECL_H_ERRNO, +[AC_CACHE_CHECK([for h_errno declaration in errno.h, sys/errno.h or netdb.h], + irc_cv_decl_h_errno, +[AC_TRY_COMPILE([ +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_SYS_ERRNO_H +#include <sys/errno.h> +#endif +#if HAVE_NETDB_H +#include <netdb.h> +#endif], +[int num = h_errno;], + irc_cv_decl_h_errno=yes, irc_cv_decl_h_errno=no)]) +if test $irc_cv_decl_h_errno = yes; then + AC_DEFINE(H_ERRNO_DECLARED) +fi +]) + + +AC_DEFUN(IRC_SGI_CC, +[AC_MSG_CHECKING([for SGI's cc]) +AC_EGREP_CPP(yes, +[#ifdef sgi +yes +#endif], +if test x$CC = xcc; then + AC_MSG_RESULT(yes) + CC="$CC -cckr" +else + AC_MSG_RESULT(no) +fi, +AC_MSG_RESULT(no)) +]) + + +AC_DEFUN(IRC_HPUX_CC, +[AC_MSG_CHECKING([for HPUX's cc]) +AC_EGREP_CPP(yes, +[#ifdef hpux +yes +#endif], +if test x$CC = xcc; then + AC_MSG_RESULT(yes) + CC="$CC -Ae" +else + AC_MSG_RESULT(no) +fi, +AC_MSG_RESULT(no)) +]) + + +AC_DEFUN(IRC_ALPHA_BETA, +[AC_MSG_CHECKING(whether this is an alpha/beta release) +AC_CACHE_VAL(irc_cv_alpha_beta, +[AC_EGREP_CPP(^\"......00, +[#include "../common/patchlevel.h" +#ifdef PATCHLEVEL +PATCHLEVEL +#else +"0000000000" +#endif +],irc_cv_alpha_beta=, +irc_cv_alpha_beta=yes) +]) +if test x$irc_cv_alpha_beta = xyes; then + AC_MSG_RESULT(yes) + AC_MSG_WARN([ + +This is a development version of the package, +it is not intended to be used in a production environment. +]) +# if test ! "$ac_test_CFLAGS" = set; then +# if test x$ac_cv_prog_cc_g = xyes -o x$GCC = x; then +# CFLAGS="$CFLAGS -g" +# fi +# fi +else + AC_MSG_RESULT(no) +# if test ! "${LDFLAGS+set}" = set; then +# LDFLAGS="-s" +# fi +fi + +if test ! "$ac_test_CFLAGS" = set; then + if test x$ac_cv_prog_cc_g = xyes -o x$GCC = x; then + CFLAGS="$CFLAGS -g" + fi +fi +]) + + +AC_DEFUN(IRC_SELECT_POLL, +[AC_MSG_CHECKING([whether select or poll system call will be used]) +AC_CACHE_VAL(irc_cv_select_poll, +[if test "$irc_cv_sun" != "no" && test "x$irc_cv_solaris_2" = "xno"; then + # we don't like SunOS' poll() function + irc_cv_select_poll=select +else + if test "$ac_cv_func_poll" = "yes"; then + irc_cv_select_poll=poll + else + irc_cv_select_poll=select + fi +fi]) + +if test "$irc_cv_select_poll" = "poll"; then + AC_MSG_RESULT(poll) + AC_DEFINE(USE_POLL) + if test ! "$irc_cv_linux" = "no"; then + AC_MSG_WARN([Aiiie.. This is linux. poll() is known to be broken for some releases (2.0.x with libc6?). You may want to edit setup.h to undefine USE_POLL]) + fi +else + AC_MSG_RESULT(select) +fi +]) + + +AC_DEFUN(IRC_SIGNAL_IMPLEMENTATION, +[AC_MSG_CHECKING([for signal implementation]) +AC_CACHE_VAL(irc_cv_signal_implementation, +[if test x$ac_cv_func_sigaction = xyes; then + irc_cv_signal_implementation=posix_sigaction +elif test x$ac_cv_func_sigset = xyes; then + irc_cv_signal_implementation=bsd_sigset +else + AC_TRY_RUN([ +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#ifndef SIGCHLD +#define SIGCHLD SIGCLD +#endif + +int got = 0; + +RETSIGTYPE hand() +{ + got++; +} + +main() +{ + (void)signal(SIGCHLD, hand); + kill(getpid(), SIGCHLD); + kill(getpid(), SIGCHLD); + if (got < 2) + exit(1); + exit(0); +} +], + irc_cv_signal_implementation=bsd_signal, + irc_cv_signal_implementation=sysv_signal) +fi +]) +if test $irc_cv_signal_implementation = posix_sigaction; then + AC_MSG_RESULT([using POSIX sigaction]) + AC_DEFINE(POSIX_SIGNALS) +elif test $irc_cv_signal_implementation = bsd_sigset; then + AC_MSG_RESULT([using BSD sigset]) + AC_DEFINE(BSD_RELIABLE_SIGNALS) + AC_DEFINE(signal, sigset) +elif test $irc_cv_signal_implementation = bsd_signal; then + AC_MSG_RESULT([using reliable BSD signal]) + AC_DEFINE(BSD_RELIABLE_SIGNALS) +else + AC_MSG_RESULT([using unreliable SystemV signal]) + AC_DEFINE(SYSV_UNRELIABLE_SIGNALS) +fi +]) + + +AC_DEFUN(IRC_NON_BLOCKING_SYSTEM, +[AC_MSG_CHECKING([for a working non-blocking system]) +AC_CACHE_VAL(irc_cv_non_blocking_system, +[ +changequote(<<, >>)dnl +irc_precode='#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif +#if HAVE_SIGNAL_H +#include <signal.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +RETSIGTYPE alarmed() +{ + exit(1); +} + +main() +{ + char b[12]; + struct sockaddr_in x; + int f, l = sizeof(x); + f = socket(AF_INET, SOCK_DGRAM, 0); + if (f >= 0 && !(fcntl(f, F_SETFL, ' +irc_postcode='))) + { + signal(SIGALRM, alarmed); + alarm(3); + recvfrom(f, b, 12, 0, &x, &l); + alarm(0); + exit(0); + } + exit(1); +}' +changequote([, ])dnl +irc_code_posix="${irc_precode}O_NONBLOCK${irc_postcode}" +irc_code_bsd="${irc_precode}O_NDELAY${irc_postcode}" +irc_code_sysv="${irc_precode}FIONBIO${irc_postcode}" +AC_TRY_RUN($irc_code_posix, + irc_cv_non_blocking_system=posix, + AC_TRY_RUN($irc_code_bsd, + irc_cv_non_blocking_system=bsd, + AC_TRY_RUN($irc_code_sysv, + irc_cv_non_blocking_system=sysv, + irc_cv_non_blocking_system=none))) +]) +if test $irc_cv_non_blocking_system = posix; then + AC_MSG_RESULT([using POSIX O_NONBLOCK]) + AC_DEFINE(NBLOCK_POSIX) +elif test $irc_cv_non_blocking_system = bsd; then + AC_MSG_RESULT([using BSD O_NDELAY]) + AC_DEFINE(NBLOCK_BSD) +elif test $irc_cv_non_blocking_system = sysv; then + AC_MSG_RESULT([using SystemV FIONBIO]) + AC_DEFINE(NBLOCK_SYSV) +else + AC_MSG_RESULT([using none]) + AC_MSG_WARN([I can't find a working non-blocking system.]) +fi +]) + + +AC_DEFUN(IRC_STDARG, +[AC_MSG_CHECKING([for working stdarg]) +AC_CACHE_VAL(irc_cv_stdarg, +AC_TRY_RUN( +[ +changequote(<<, >>)dnl +#if HAVE_STDIO_H +#include <stdio.h> +#endif +#if HAVE_STDARG_H +#include <stdarg.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#endif + +char buf1[256]; + +int level1(char *data, char *format, va_list ap) +{ + return vsprintf(data, format, ap); +} + +int level2(char *data, int rounds, char *format, va_list ap) +{ + if(!--rounds) + return level1(data, format, ap); + else { + if(rounds == 2) { + va_list ap2 = ap; + char *arg = va_arg(ap2, char *); + strcpy(buf1, arg); + } + return level2(data, rounds, format, ap); + } +} + +int level3(char *data, char *format, va_list ap) +{ + return level2(data, 5, format, ap); +} + +int dotest(int size, char *val, char *data) +{ + if(size != strlen(val)) + return 0; + if(strcmp(data, val)) + return 0; + if(strcmp(buf1, "was")) + return 0; + return 1; +} + +int base(char *val, char *format, ...) +{ + int res = 1; + char data[256]; + + { + va_list ap; + data[0]=0; + va_start(ap, format); + res = dotest(level3(data, format, ap), val, data); + va_end(ap); + } + + { + va_list ap; + data[0]=0; + va_start(ap, format); + res = res && dotest(level3(data, format, ap), val, data); + va_end(ap); + } + + return res; +} + +int main(void) +{ + int res = base("toto was here ! 42", "toto %s here ! %d", "was", 42); + + exit(res ? 0 : 1); +} +changequote([, ])dnl +], +irc_cv_stdarg=yes, +irc_cv_stdarg=no) +) +if test $irc_cv_stdarg = yes; then + AC_MSG_RESULT(yes) + AC_DEFINE(USE_STDARG) +else + AC_MSG_RESULT(no) +fi +]) + + +AC_DEFUN(IRC_PATH_RESCONF, +[AC_MSG_CHECKING([for resolver configuration file]) +AC_CACHE_VAL(irc_cv_path_resconf, +[if test -z "$irc_resconf"; then + irc_cv_path_resconf="/etc/resolv.conf"; + else + irc_cv_path_resconf="$irc_resconf"; + fi +]) +AC_MSG_RESULT($irc_cv_path_resconf) +AC_DEFINE_UNQUOTED(IRC_RESCONF, "$irc_cv_path_resconf") +if test ! -r "$irc_cv_path_resconf"; then + AC_MSG_WARN([Unable to read \"$irc_cv_path_resconf\"! Without resolver configuration file, the server won't work.]) +fi +]) + + +AC_DEFUN(IRC_EGREP_RMLF_CPP, +[cat > conftest.$ac_ext <<EOF +[#]line __oline__ "configure" +#include "confdefs.h" +[$2] +EOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&AC_FD_CC | + $AWK "{if (NR > 1) printf(\" \"); printf(\[$]0)}" | +changequote(, )dnl + egrep "$1" >/dev/null 2>&1; then +changequote([, ])dnl + ifelse([$3], , :, [rm -rf conftest* + $3]) +ifelse([$4], , , [else + rm -rf conftest* + $4 +])dnl +fi +rm -f conftest* +]) + + +AC_DEFUN(IRC_LINUX, +[AC_MSG_CHECKING(for Linux) +AC_CACHE_VAL(irc_cv_linux, +[if test "x`(uname) 2>/dev/null`" = "xLinux"; then + IRC_EGREP_RMLF_CPP( + [struct( | )+hostent( | )+\{.*const.*h_name], + [#include <netdb.h>], + irc_cv_linux=bad, + irc_cv_linux=good) +else + irc_cv_linux=no +fi +]) +if test "$irc_cv_linux" = no; then + AC_MSG_RESULT(no) +elif test "$irc_cv_linux" = good; then + AC_MSG_RESULT([yes, with a good <netdb.h> file]) +else + AC_MSG_RESULT([yes, with a bad <netdb.h> file]) + AC_DEFINE(BAD___CONST_NETDB_H) +fi +]) + + +AC_DEFUN(IRC_IP6, +[AC_ARG_ENABLE(ip6, [ --enable-ip6 enables IPv6]) +if test "x$enable_ip6" != x; then + AC_DEFINE(INET6) + dnl be smart about it + AC_MSG_CHECKING([IPv6 system type]) + AC_CACHE_VAL(irc_cv_v6type, [ + if test -d /usr/inet6; then + irc_cv_v6type=linux + else + AC_EGREP_CPP(yes, [dnl +#include <netinet/in.h> +#ifdef IPV6_INRIA_VERSION +yes +#endif], irc_cv_v6type=inria, + AC_EGREP_CPP(yes, [dnl +#include <netinet/in.h> +#ifdef __KAME__ +yes +#endif], irc_cv_v6type=kame, + AC_EGREP_CPP(yes, [dnl +#include <sys/param.h> +#ifdef _TOSHIBA_INET6 +yes +#endif], irc_cv_v6type=toshiba, + AC_EGREP_CPP(yes, [dnl +#include </usr/local/v6/include/sys/types.h> +#ifdef __V6D__ +yes +#endif], irc_cv_v6type=v6d, + AC_EGREP_CPP(yes, [dnl +#include <sys/param.h> +#ifdef _ZETA_MINAMI_INET6 +yes +#endif], irc_cv_v6type=zeta))))) + fi]) + AC_MSG_RESULT($irc_cv_v6type) + + dnl eventually update LIBS + case $irc_cv_v6type in + kame) + LIBS="-L/usr/local/v6/lib -linet6 $LIBS" + CFLAGS="$CFLAGS -I/usr/local/v6/include" + ;; + linux) + LIBS="-L/usr/inet6/lib -linet6 $LIBS" + CFLAGS="$CFLAGS -I/usr/inet6/include" + ;; + toshiba) + LIBS="-L/usr/local/v6/lib -linet6 $LIBS" + CFLAGS="$CFLAGS -I/usr/local/v6/include" + ;; + v6d) + LIBS="-L/usr/local/v6/lib -lv6 $LIBS" + CFLAGS="$CFLAGS -I/usr/local/v6/include" + ;; + zeta) + LIBS="-L/usr/local/v6/lib -linet6 $LIBS" + CFLAGS="$CFLAGS -I/usr/local/v6/include" + ;; + esac + + dnl /etc/resolv.conf check + AC_MSG_CHECKING(for IPv6 name server addresses in resolv.conf ($irc_cv_path_resconf)) + if grep nameserver $irc_cv_path_resconf | grep ':' >/dev/null 2>&1; then + AC_MSG_RESULT(yes) + AC_MSG_WARN([$irc_cv_path_resconf is not setup correctly.]) + else + AC_MSG_RESULT(no) + fi +fi +]) + + +AC_DEFUN(IRC_SHAREDMODULES, +[AC_ARG_ENABLE(dsm, [ --enable-dsm enables dynamically shared modules for iauth]) +if test "x$enable_dsm" != x; then + AC_DEFINE(USE_DSM) +dnl AC_CONFIG_HEADER(dl.h) + AC_CHECK_HEADERS(dlfcn.h) + AC_CHECK_LIB(dl, dlclose, IRC_DLIB="-ldl") + AC_SUBST(IRC_DLIB) +fi +]) + + +dnl ------------------------------------------------------------------- +dnl modified Autoconf tests; their names begin with IRC_ instead of AC_ +dnl ------------------------------------------------------------------- + +AC_DEFUN(IRC_INIT_PARSE_ARGS, +[ +# Initialize some variables set by options. +# The variables have the same names as the options, with +# dashes changed to underlines. +build=NONE +cache_file=./config.cache +exec_prefix=NONE +host=NONE +no_create= +nonopt=NONE +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +target=NONE +verbose= +zlib_include=NONE +zlib_library=NONE +dnl Installation directory options. +dnl These are left unexpanded so users can "make install exec_prefix=/foo" +dnl and all the variables that are supposed to be based on exec_prefix +dnl by default will actually change. +dnl Use braces instead of parens because sh, perl, etc. also accept them. +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datadir='${prefix}/share' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var/run' +includedir='${prefix}/include' +oldincludedir='/usr/include' +infodir='${prefix}/info' +mandir='${prefix}/man' +logdir='${prefix}/var/log/ircd' + +# Initialize some other variables. +subdirs= +MFLAGS= MAKEFLAGS= +# Maximum number of lines to put in a shell here document. +ac_max_here_lines=12 + +ac_prev= +for ac_option +do + + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval "$ac_prev=\$ac_option" + ac_prev= + continue + fi + + case "$ac_option" in +changequote(, )dnl + -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;; +changequote([, ])dnl + *) ac_optarg= ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case "$ac_option" in + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir="$ac_optarg" ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build="$ac_optarg" ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file="$ac_optarg" ;; + + -datadir | --datadir | --datadi | --datad | --data | --dat | --da) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \ + | --da=*) + datadir="$ac_optarg" ;; + + -disable-* | --disable-*) + ac_feature=`echo $ac_option|sed -e 's/-*disable-//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_feature: invalid feature name) + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + eval "enable_${ac_feature}=no" ;; + + -enable-* | --enable-*) + ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_feature: invalid feature name) + fi + ac_feature=`echo $ac_feature| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "enable_${ac_feature}='$ac_optarg'" ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix="$ac_optarg" ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he) + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat << EOF +changequote(, )dnl +Usage: configure [options] [host] +Options: [defaults in brackets after descriptions] +Configuration: + --cache-file=FILE cache test results in FILE + --help print this message + --no-create do not create output files + --quiet, --silent do not print \`checking...' messages + --version print the version of autoconf that created configure +Directory and file names: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [same as prefix] + --bindir=DIR user executables in DIR [EPREFIX/bin] + --sbindir=DIR system admin executables in DIR [EPREFIX/sbin] + --libexecdir=DIR program executables in DIR [EPREFIX/libexec] + --datadir=DIR read-only architecture-independent data in DIR + [PREFIX/share] + --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data in DIR + [PREFIX/com] + --localstatedir=DIR modifiable single-machine data in DIR[PREFIX/var/run] + --includedir=DIR C header files in DIR [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include] + --logdir=DIR log files in DIR [PREFIX/var/log/ircd] + --infodir=DIR info documentation in DIR [PREFIX/info] + --mandir=DIR man documentation in DIR [PREFIX/man] + --srcdir=DIR find the sources in DIR [configure dir or ..] + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM + run sed PROGRAM on installed program names +EOF + cat << EOF +Host type: + --build=BUILD configure for building on BUILD [BUILD=HOST] + --host=HOST configure for HOST [guessed] + --target=TARGET configure for TARGET [TARGET=HOST] +Features and packages: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --resconf=FILE use FILE as resolver config file [/etc/resolv.conf] + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --zlib-prefix=ZDIR zlib installation prefix is ZDIR + --zlib-include=ZIDIR zlib include files are in ZIDIR [ZDIR/include] + --zlib-library=ZLDIR zlib library files are in ZLDIR [ZDIR/lib] +changequote([, ])dnl +EOF + if test -n "$ac_help"; then + echo "--enable and --with options recognized:$ac_help" + fi + exit 0 ;; + + -host | --host | --hos | --ho) + ac_prev=host ;; + -host=* | --host=* | --hos=* | --ho=*) + host="$ac_optarg" ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir="$ac_optarg" ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir="$ac_optarg" ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir="$ac_optarg" ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir="$ac_optarg" ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst \ + | --locals | --local | --loca | --loc | --lo) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* \ + | --locals=* | --local=* | --loca=* | --loc=* | --lo=*) + localstatedir="$ac_optarg" ;; + + -logdir | --logdir | --logdi | --logd) + ac_prev=logdir ;; + -logdir=* | --logdir=* | --logdi=* | --logd=*) + logdir="$ac_optarg/" ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir="$ac_optarg" ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir="$ac_optarg" ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix="$ac_optarg" ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix="$ac_optarg" ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix="$ac_optarg" ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name="$ac_optarg" ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -resconf | --resconf | --rescon | --resco | --resc | --res \ + | --re | --r) + ac_prev=irc_resconf ;; + -resconf=* | --resconf=* | --rescon=* | --resco=* | --resc=* \ + | --res=* | --re=* | --r=*) + irc_resconf="$ac_optarg" ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir="$ac_optarg" ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir="$ac_optarg" ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site="$ac_optarg" ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir="$ac_optarg" ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir="$ac_optarg" ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target="$ac_optarg" ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers) + echo "configure generated by autoconf version AC_ACVERSION" + exit 0 ;; + + -with-* | --with-*) + ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_package: invalid package name) + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + case "$ac_option" in + *=*) ;; + *) ac_optarg=yes ;; + esac + eval "with_${ac_package}='$ac_optarg'" ;; + + -without-* | --without-*) + ac_package=`echo $ac_option|sed -e 's/-*without-//'` + # Reject names that are not valid shell variable names. +changequote(, )dnl + if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then +changequote([, ])dnl + AC_MSG_ERROR($ac_package: invalid package name) + fi + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval "with_${ac_package}=no" ;; + + -zlib-prefix | --zlib-prefix | --zlib-prefi | --zlib-pref \ + | --zlib-pre | --zlib-pr | --zlib-p) + ac_prev=irc_zlib_prefix ;; + -zlib-prefix=* | --zlib-prefix=* | --zlib-prefi=* | --zlib-pref=* \ + | --zlib-pre=* | --zlib-pr=* | --zlib-p=*) + irc_zlib_prefix="$ac_optarg" ;; + + -zlib-include | --zlib-include | --zlib-includ | --zlib-inclu \ + | --zlib-incl | --zlib-inc | --zlib-in | --zlib-i) + ac_prev=irc_zlib_include ;; + -zlib-include=* | --zlib-include=* | --zlib-includ=* | --zlib-inclu=* \ + | --zlib-incl=* | --zlib-inc=* | --zlib-in=* | --zlib-i=*) + irc_zlib_include="$ac_optarg" ;; + + -zlib-library | --zlib-library | --zlib-librar | --zlib-libra | --zlib-libr \ + | --zlib-lib | --zlib-li | --zlib-l) + ac_prev=irc_zlib_library ;; + -zlib-library=* | --zlib-library=* | --zlib-librar=* | --zlib-libra=* \ + | --zlib-libr=* | --zlib-lib=* | --zlib-li=* | --zlib-l=*) + irc_zlib_library="$ac_optarg" ;; + + -*) AC_MSG_ERROR([$ac_option: invalid option; use --help to show usage]) + ;; + + *) +changequote(, )dnl + if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then +changequote([, ])dnl + AC_MSG_WARN($ac_option: invalid host type) + fi + if test "x$nonopt" != xNONE; then + AC_MSG_ERROR(can only configure for one host and one target at a time) + fi + nonopt="$ac_option" + ;; + + esac +done + +if test -n "$ac_prev"; then + AC_MSG_ERROR(missing argument to --`echo $ac_prev | sed 's/_/-/g'`) +fi + +AC_SUBST(logdir) +]) + + +AC_DEFUN(IRC_INIT, +[sinclude(acsite.m4)dnl +sinclude(./aclocal.m4)dnl +AC_REQUIRE([AC_INIT_BINSH])dnl +AC_INIT_NOTICE +AC_DIVERT_POP()dnl to NORMAL +AC_DIVERT_PUSH(AC_DIVERSION_INIT)dnl +IRC_INIT_PARSE_ARGS +AC_INIT_PREPARE($1)dnl +AC_DIVERT_POP()dnl to NORMAL +]) + + +AC_DEFUN(IRC_PROG_INSTALL, +[define(AC_PROVIDE_AC_PROG_INSTALL) +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AIX v4 /usr/bin/installbsd, which does not work if the user is not root +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# ./install, which can be erroneously created by make from ./install.sh. +AC_MSG_CHECKING(for a BSD compatible install) +if test -z "$INSTALL"; then +AC_CACHE_VAL(ac_cv_path_install, +[ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:" + for ac_dir in $PATH; do + # Account for people who put trailing slashes in PATH elements. + case "$ac_dir/" in + /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + for ac_prog in ginstall installbsd scoinst install; do + if test -f $ac_dir/$ac_prog; then + if test $ac_prog = install && + grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + # OSF/1 installbsd also uses dspmsg, but is usable. + : + elif test $ac_prog = installbsd -a "x`(uname -sv) 2>/dev/null`" = "xAIX 4"; then + # AIX v4 installbsd. Does not work if the user is not root. + : + else + ac_cv_path_install="$ac_dir/$ac_prog -c" + break 2 + fi + fi + done + ;; + esac + done + IFS="$ac_save_IFS" +])dnl + if test "${ac_cv_path_install+set}" = set; then + INSTALL="$ac_cv_path_install" + else + # As a last resort, use the slow shell script. We don't cache a + # path for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the path is relative. + INSTALL="$ac_install_sh" + fi +fi +dnl We do special magic for INSTALL instead of AC_SUBST, to get +dnl relative paths right. +AC_MSG_RESULT($INSTALL) + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' +AC_SUBST(INSTALL_PROGRAM)dnl + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' +AC_SUBST(INSTALL_DATA)dnl +]) + +AC_DEFUN(IRC_CYGWIN, +[AC_CYGWIN +if test ! -z "$CYGWIN"; then + if test ! -x /bin/mv || test ! -x /bin/rm || test ! -x /bin/sh; then + AC_MSG_ERROR([mv, rm and/or sh is missing from /bin]) + fi + AC_MSG_WARN([The IRC client and the iauth program do not work under the CYGWIN environment.]) +fi +]) + +AC_DEFUN(IRC_PROG_CC, +[define(AC_PROVIDE_AC_PROG_CC) +AC_BEFORE([$0], [AC_PROG_CPP])dnl +AC_CHECK_PROG(CC, gcc, gcc) +if test -z "$CC"; then + AC_CHECK_PROG(CC, cc, cc, , , /usr/ucb/cc) + test -z "$CC" && AC_MSG_ERROR([no acceptable cc found in \$PATH]) +fi +AC_PROG_CC_WORKS +AC_PROG_CC_GNU +ac_test_CFLAGS="${CFLAGS+set}" +if test $ac_cv_prog_gcc = yes; then + GCC=yes + ac_save_CFLAGS="$CFLAGS" + CFLAGS= + AC_PROG_CC_G + if test "$ac_test_CFLAGS" = set; then + CFLAGS="$ac_save_CFLAGS" + else + CFLAGS="-O2" + fi +else + GCC= +fi +]) + + +AC_DEFUN(IRC_AIX, +[AC_MSG_CHECKING(for AIX) +AC_CACHE_VAL(irc_cv_aix, +[if test "x`(uname) 2>/dev/null`" = "xAIX"; then + irc_cv_aix="`uname -rv`" +else + irc_cv_aix=no +fi +]) +if test "$irc_cv_aix" = no; then + AC_MSG_RESULT(no) +else + AC_MSG_RESULT(yes) + AC_DEFINE(_ALL_SOURCE) + if test "x$irc_cv_aix" = "x2 3"; then + AC_DEFINE(AIX_3_2) + fi + if test x$CC = xcc; then + CFLAGS="$CFLAGS -O3 -qstrict" + fi +fi +]) + + +AC_DEFUN(IRC_CHECK_TYPE, +[AC_REQUIRE([AC_HEADER_STDC])dnl +AC_MSG_CHECKING(for $1) +AC_CACHE_VAL(ac_cv_type_$1, +[AC_EGREP_CPP(dnl +changequote(<<,>>)dnl +<<$1[^a-zA-Z_0-9]>>dnl +changequote([,]), [ +#if HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif +#if HAVE_SYS_BITYPES_H +#include <sys/bitypes.h> +#endif], ac_cv_type_$1=yes, ac_cv_type_$1=no)])dnl +AC_MSG_RESULT($ac_cv_type_$1) +if test $ac_cv_type_$1 = no; then + AC_DEFINE($1, $2) +fi +]) + + +AC_DEFUN(IRC_FUNC_MEMCMP, +[AC_CACHE_CHECK(for 8-bit clean memcmp, irc_cv_func_memcmp_clean, +[AC_TRY_RUN([ +main() +{ + char c0 = 0x40, c1 = 0x80, c2 = 0x81; + exit(memcmp(&c0, &c2, 1) < 0 && memcmp(&c1, &c2, 1) < 0 ? 0 : 1); +} +], irc_cv_func_memcmp_clean=yes, irc_cv_func_memcmp_clean=no, +irc_cv_func_memcmp_clean=no)]) +if test $irc_cv_func_memcmp_clean = no; then + AC_DEFINE(MEMCMP_BROKEN) +fi +]) + + +dnl ---- +dnl main +dnl ---- + +AC_REVISION([$Id: configure.in,v 1.46 1999/08/13 17:18:23 kalt Exp $]) +AC_PREREQ(2.13) +IRC_INIT(../ircd/ircd.c) +AC_CONFIG_HEADER(setup.h:../support/setup.h.in) +AC_CONFIG_AUX_DIR(../support) +AC_VALIDATE_CACHED_SYSTEM_TUPLE() + +IRC_PROG_CC +AC_PROG_CPP +AC_PROG_AWK +IRC_PROG_INSTALL +AC_PATH_PROGS(SUM, md5sum sum cksum, true) +AC_PROG_GCC_TRADITIONAL + +IRC_AIX +AC_ISC_POSIX +AC_MINIX +IRC_SGI_CC +IRC_HPUX_CC +IRC_SUN +IRC_LINUX +IRC_CYGWIN + +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(stdio.h stdlib.h sys/types.h sys/bitypes.h stddef.h stdarg.h unistd.h ctype.h memory.h ncurses.h curses.h cursesX.h term.h sgtty.h errno.h sys/errno.h sys/syscall.h pwd.h math.h utmp.h fcntl.h signal.h sys/ioctl.h sys/file.h sys/filio.h sys/socket.h sys/stat.h sys/resource.h sys/select.h sys/poll.h stropts.h netdb.h netinet/in.h sys/un.h arpa/inet.h sys/param.h syslog.h sys/syslog.h string.h strings.h sys/time.h time.h sys/times.h netinet/in_systm.h netinfo/ni.h resolv.h arpa/nameser.h) +IRC_DECL_SYS_ERRLIST +IRC_DECL_SYS_NERR +IRC_DECL_ERRNO +IRC_DECL_H_ERRNO +AC_HEADER_STAT +AC_HEADER_TIME +AC_STRUCT_TM +AC_TYPE_MODE_T +AC_TYPE_OFF_T +AC_TYPE_PID_T +AC_TYPE_SIGNAL +AC_TYPE_SIZE_T +AC_TYPE_UID_T +IRC_UNION_WAIT +IRC_CHECK_TYPE(int8_t, char) +IRC_CHECK_TYPE(u_int8_t, unsigned char) +IRC_CHECK_TYPE(int16_t, short) +IRC_CHECK_TYPE(u_int16_t, unsigned short) +IRC_CHECK_TYPE(int32_t, int) +IRC_CHECK_TYPE(u_int32_t, unsigned int) +IRC_CHECK_TYPE(u_char, unsigned char) +IRC_CHECK_TYPE(u_short, unsigned short) +IRC_CHECK_TYPE(u_int, unsigned int) +IRC_CHECK_TYPE(u_long, unsigned long) + +AC_C_BIGENDIAN +AC_C_CONST + +AC_CHECK_LIB(crypt, crypt) +AC_CHECK_LIB(socket, socket) +AC_CHECK_LIB(nsl, socket) + +IRC_PATH_ZLIB +IRC_CURSES_TERMCAP + +AC_FUNC_SETPGRP +AC_FUNC_SETVBUF_REVERSED +AC_FUNC_VFORK +AC_CHECK_FUNCS(setpgrp strchr strrchr memcmp memset memmove memcpy index rindex bcmp bcopy bzero select inet_ntoa inet_aton inet_addr inet_netof getrusage times strerror strtoken strtok sigaction sigset truncate poll vsyslog) +dnl --- +dnl Note: additional tests should be performed and used inside the source code +dnl for the following functions: +dnl gethostname gettimeofday lrand48 mkdir socket +dnl --- +IRC_FUNC_MEMCMP +IRC_SELECT_POLL + +IRC_SIGNAL_IMPLEMENTATION +IRC_NON_BLOCKING_SYSTEM +IRC_STDARG +IRC_PATH_RESCONF +IRC_IP6 +IRC_SHAREDMODULES +IRC_ALPHA_BETA + +AC_OUTPUT(Makefile:../support/Makefile.in version.c.SH:../ircd/version.c.SH.in sums:../support/sums.in tkconf.h:../support/tkconf.h.dist) +AC_OUTPUT_COMMANDS(chmod a+x version.c.SH) diff --git a/support/iauth.conf b/support/iauth.conf new file mode 100644 index 0000000..c86c379 --- /dev/null +++ b/support/iauth.conf @@ -0,0 +1,18 @@ +# +# Default iauth configuration file +# +# $Id: iauth.conf,v 1.2 1999/07/04 22:15:43 kalt Exp $ +# + +# If iauth timeouts, then reject user +notimeout +# This makes the IRC server require that iauth performs the authentication +# in order for a new user connection to be accepted +required + +# Perform ident lookups +module rfc931 + +# Check and reject open SOCKS proxies +#module socks +# option = reject,paranoid diff --git a/support/install-sh b/support/install-sh new file mode 100755 index 0000000..5ad826e --- /dev/null +++ b/support/install-sh @@ -0,0 +1,253 @@ +#! /bin/sh +# +# $Id: install-sh,v 1.3 1999/01/18 00:24:17 kalt Exp $ +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/support/mkdirhier b/support/mkdirhier new file mode 100755 index 0000000..244462a --- /dev/null +++ b/support/mkdirhier @@ -0,0 +1,70 @@ +#!/bin/sh +# $XConsortium: mkdirhier.sh,v 1.7 94/03/24 15:46:34 gildea Exp $ +# Courtesy of Paul Eggert +# +# $Id: mkdirhier,v 1.2 1997/07/22 12:40:10 kalt Exp $ +# + +newline=' +' +IFS=$newline + +case ${1--} in +-*) echo >&2 "mkdirhier: usage: mkdirhier directory ..."; exit 1 +esac + +status= + +for directory +do + case $directory in + '') + echo >&2 "mkdirhier: empty directory name" + status=1 + continue;; + *"$newline"*) + echo >&2 "mkdirhier: directory name contains a newline: \`\`$directory''" + status=1 + continue;; + ///*) prefix=/;; # See Posix 2.3 "path". + //*) prefix=//;; + /*) prefix=/;; + -*) prefix=./;; + *) prefix= + esac + + IFS=/ + set x $directory + case $2 in + */*) # IFS parsing is broken + IFS=' ' + set x `echo $directory | tr / ' '` + ;; + esac + IFS=$newline + shift + + for filename + do + path=$prefix$filename + prefix=$path/ + shift + + test -d "$path" || { + paths=$path + for filename + do + if [ "$filename" != "." ]; then + path=$path/$filename + paths=$paths$newline$path + fi + done + + mkdir $paths || status=$? + + break + } + done + done + +exit $status diff --git a/support/setup.h.in b/support/setup.h.in new file mode 100644 index 0000000..a01bbc0 --- /dev/null +++ b/support/setup.h.in @@ -0,0 +1,413 @@ +/* ../support/setup.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +#undef _ALL_SOURCE +#endif + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef gid_t + +/* Define if system calls automatically restart after interruption + by a signal. */ +#undef HAVE_RESTARTABLE_SYSCALLS + +/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define if you have <vfork.h>. */ +#undef HAVE_VFORK_H + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef mode_t + +/* Define to `long' if <sys/types.h> doesn't define. */ +#undef off_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef pid_t + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +#undef _POSIX_1_SOURCE + +/* Define if you need to in order for stat and other things to work. */ +#undef _POSIX_SOURCE + +/* Define as the return type of signal handlers (int or void). */ +#undef RETSIGTYPE + +/* Define if the `setpgrp' function takes no argument. */ +#undef SETPGRP_VOID + +/* Define if the setvbuf function takes the buffering type as its second + argument and the buffer pointer as the third, as on System V + before release 3. */ +#undef SETVBUF_REVERSED + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +#undef size_t + +/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +#undef STAT_MACROS_BROKEN + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define if you can safely include both <sys/time.h> and <time.h>. */ +#undef TIME_WITH_SYS_TIME + +/* Define if your <sys/time.h> declares struct tm. */ +#undef TM_IN_SYS_TIME + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef uid_t + +/* Define vfork as fork if vfork does not work. */ +#undef vfork + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +#undef WORDS_BIGENDIAN + +/* Define if zlib package must be used for compilation/linking. */ +#undef USE_ZLIB + +/* Define if ncurses library must be used for compilation/linking. */ +#undef USE_NCURSES + +/* Define if cursesX library must be used for compilation/linking. */ +#undef USE_CURSESX + +/* Define if curses library must be used for compilation/linking. */ +#undef USE_CURSES + +/* Define if termcap library must be used for compilation/linking. */ +#undef USE_TERMCAP + +/* Define if the second argument of waitpid must be an "union wait *" instead + of an "int *". */ +#undef USE_UNION_WAIT + +/* Define if int8_t, u_int8_t, int16_t, u_int16_t, int32_t, u_int32_t, u_char, + * u_short, u_int, u_long are not known types. */ +#undef int8_t +#undef u_int8_t +#undef int16_t +#undef u_int16_t +#undef int32_t +#undef u_int32_t +#undef u_char +#undef u_short +#undef u_int +#undef u_long + +/* Define if memcmp is not 8-bit clean. */ +#undef MEMCMP_BROKEN + +/* Define if the operating system is AIX 3.2. */ +#undef AIX_3_2 + +/* Define if the operating system is Solaris 2.x (SunOS 5.x). */ +#undef SOLARIS_2 + +/* Define if the operating system is Solaris 2.3 (SunOS 5.3). */ +#undef SOLARIS_2_3 + +/* Define if the operating system is Solaris 2.[0-2] (SunOS 5.[0-2]). */ +#undef SOLARIS_2_0_2_1_2_2 + +/* Define if <netdb.h> contains bad __const usages (Linux). */ +#undef BAD___CONST_NETDB_H + +/* Define if sys_errlist is declared in stdio.h or errno.h. */ +#undef SYS_ERRLIST_DECLARED + +/* Define if sys_nerr is declared in stdio.h or errno.h. */ +#undef SYS_NERR_DECLARED + +/* Define if errno is declared in errno.h. */ +#undef ERRNO_DECLARED + +/* Define if h_errno is declared in errno.h or netdb.h. */ +#undef H_ERRNO_DECLARED + +/* Define if poll(2) must be used instead of select(2). */ +/* Note: some systems (e.g. linux 2.0.x) have a non-working poll() */ +#undef USE_POLL + +/* Define if the system provides POSIX sigaction. */ +#undef POSIX_SIGNALS + +/* Define if the system provides reliable BSD signals through sigset instead + of signal. */ +/* #define signal sigset */ + +/* Define if the system provides reliable BSD signals. */ +#undef BSD_RELIABLE_SIGNALS + +/* Define if the system provides unreliable SystemV signals. */ +#undef SYSV_UNRELIABLE_SIGNALS + +/* Define if the system provides POSIX non-blocking system. */ +#undef NBLOCK_POSIX + +/* Define if the system provides BSD non-blocking system. */ +#undef NBLOCK_BSD + +/* Define if the system provides SystemV non-blocking system. */ +#undef NBLOCK_SYSV + +/* Define is the system can use variable arguments. */ +#undef USE_STDARG + +/* Define as the resolver configuration file. */ +#undef IRC_RESCONF + +/* Define to enable IPv6 support */ +#undef INET6 + +/* Define to enable dynamically shared iauth module support */ +#undef USE_DSM + +/* Define if you have the bcmp function. */ +#undef HAVE_BCMP + +/* Define if you have the bcopy function. */ +#undef HAVE_BCOPY + +/* Define if you have the bzero function. */ +#undef HAVE_BZERO + +/* Define if you have the getrusage function. */ +#undef HAVE_GETRUSAGE + +/* Define if you have the index function. */ +#undef HAVE_INDEX + +/* Define if you have the inet_addr function. */ +#undef HAVE_INET_ADDR + +/* Define if you have the inet_aton function. */ +#undef HAVE_INET_ATON + +/* Define if you have the inet_netof function. */ +#undef HAVE_INET_NETOF + +/* Define if you have the inet_ntoa function. */ +#undef HAVE_INET_NTOA + +/* Define if you have the memcmp function. */ +#undef HAVE_MEMCMP + +/* Define if you have the memcpy function. */ +#undef HAVE_MEMCPY + +/* Define if you have the memmove function. */ +#undef HAVE_MEMMOVE + +/* Define if you have the memset function. */ +#undef HAVE_MEMSET + +/* Define if you have the poll function. */ +#undef HAVE_POLL + +/* Define if you have the rindex function. */ +#undef HAVE_RINDEX + +/* Define if you have the select function. */ +#undef HAVE_SELECT + +/* Define if you have the setpgrp function. */ +#undef HAVE_SETPGRP + +/* Define if you have the sigaction function. */ +#undef HAVE_SIGACTION + +/* Define if you have the sigset function. */ +#undef HAVE_SIGSET + +/* Define if you have the strchr function. */ +#undef HAVE_STRCHR + +/* Define if you have the strerror function. */ +#undef HAVE_STRERROR + +/* Define if you have the strrchr function. */ +#undef HAVE_STRRCHR + +/* Define if you have the strtok function. */ +#undef HAVE_STRTOK + +/* Define if you have the strtoken function. */ +#undef HAVE_STRTOKEN + +/* Define if you have the times function. */ +#undef HAVE_TIMES + +/* Define if you have the truncate function. */ +#undef HAVE_TRUNCATE + +/* Define if you have the vsyslog function. */ +#undef HAVE_VSYSLOG + +/* Define if you have the <arpa/inet.h> header file. */ +#undef HAVE_ARPA_INET_H + +/* Define if you have the <arpa/nameser.h> header file. */ +#undef HAVE_ARPA_NAMESER_H + +/* Define if you have the <ctype.h> header file. */ +#undef HAVE_CTYPE_H + +/* Define if you have the <curses.h> header file. */ +#undef HAVE_CURSES_H + +/* Define if you have the <cursesX.h> header file. */ +#undef HAVE_CURSESX_H + +/* Define if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define if you have the <errno.h> header file. */ +#undef HAVE_ERRNO_H + +/* Define if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the <math.h> header file. */ +#undef HAVE_MATH_H + +/* Define if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have the <ncurses.h> header file. */ +#undef HAVE_NCURSES_H + +/* Define if you have the <netdb.h> header file. */ +#undef HAVE_NETDB_H + +/* Define if you have the <netinet/in.h> header file. */ +#undef HAVE_NETINET_IN_H + +/* Define if you have the <netinet/in_systm.h> header file. */ +#undef HAVE_NETINET_IN_SYSTM_H + +/* Define if you have the <netinfo/ni.h> header file. */ +#undef HAVE_NETINFO_NI_H + +/* Define if you have the <pwd.h> header file. */ +#undef HAVE_PWD_H + +/* Define if you have the <resolv.h> header file. */ +#undef HAVE_RESOLV_H + +/* Define if you have the <sgtty.h> header file. */ +#undef HAVE_SGTTY_H + +/* Define if you have the <signal.h> header file. */ +#undef HAVE_SIGNAL_H + +/* Define if you have the <stdarg.h> header file. */ +#undef HAVE_STDARG_H + +/* Define if you have the <stddef.h> header file. */ +#undef HAVE_STDDEF_H + +/* Define if you have the <stdio.h> header file. */ +#undef HAVE_STDIO_H + +/* Define if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define if you have the <stropts.h> header file. */ +#undef HAVE_STROPTS_H + +/* Define if you have the <sys/bitypes.h> header file. */ +#undef HAVE_SYS_BITYPES_H + +/* Define if you have the <sys/errno.h> header file. */ +#undef HAVE_SYS_ERRNO_H + +/* Define if you have the <sys/file.h> header file. */ +#undef HAVE_SYS_FILE_H + +/* Define if you have the <sys/filio.h> header file. */ +#undef HAVE_SYS_FILIO_H + +/* Define if you have the <sys/ioctl.h> header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the <sys/poll.h> header file. */ +#undef HAVE_SYS_POLL_H + +/* Define if you have the <sys/resource.h> header file. */ +#undef HAVE_SYS_RESOURCE_H + +/* Define if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the <sys/socket.h> header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define if you have the <sys/syscall.h> header file. */ +#undef HAVE_SYS_SYSCALL_H + +/* Define if you have the <sys/syslog.h> header file. */ +#undef HAVE_SYS_SYSLOG_H + +/* Define if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define if you have the <sys/times.h> header file. */ +#undef HAVE_SYS_TIMES_H + +/* Define if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define if you have the <sys/un.h> header file. */ +#undef HAVE_SYS_UN_H + +/* Define if you have the <syslog.h> header file. */ +#undef HAVE_SYSLOG_H + +/* Define if you have the <term.h> header file. */ +#undef HAVE_TERM_H + +/* Define if you have the <time.h> header file. */ +#undef HAVE_TIME_H + +/* Define if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the <utmp.h> header file. */ +#undef HAVE_UTMP_H + +/* Define if you have the crypt library (-lcrypt). */ +#undef HAVE_LIBCRYPT + +/* Define if you have the nsl library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define if you have the socket library (-lsocket). */ +#undef HAVE_LIBSOCKET diff --git a/support/sums.in b/support/sums.in new file mode 100644 index 0000000..ff7dffc --- /dev/null +++ b/support/sums.in @@ -0,0 +1,39 @@ +#!/bin/sh +# trap "" 1 2 3 13 14 15 21 22 +# $Id: sums.in,v 1.1 1998/04/07 20:44:48 kalt Exp $ +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=`(cd ../ircd; @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=`(cd ../ircd; @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=`(cd ../ircd; @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=`(cd ../ircd; @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=`(cd ../ircd; @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=`(cd ../ircd; @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=`(cd ../ircd; @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 + diff --git a/support/tkconf.h.dist b/support/tkconf.h.dist new file mode 100644 index 0000000..3467564 --- /dev/null +++ b/support/tkconf.h.dist @@ -0,0 +1,35 @@ +/* + * TkServ configuration definitions + * + * Make sure the ircd conf files are located in the server_bin_dir + * (see Makefile) and that USE_SERVICES is #define'd if you intend + * to use this service. + * + */ + +/* This will be shown on ADMIN requests */ +#define TKSERV_ADMIN_NAME "Admin: Someone Somewhere" +#define TKSERV_ADMIN_CONTACT "Mail: i.didnt@edit.my.ADMIN.info" +#define TKSERV_ADMIN_OTHER "SomeAdmin@IRCNet" + +/* This is the name of the service which appears on /servlist */ +#define TKSERV_NAME "TkServ" + +/* The description of the service (appears on /SERVLIST) */ +#define TKSERV_DESC "Temporary K-line Service" + +/* The distribution of the server */ +#define TKSERV_DIST "*" + +/* The password for the service (must match the one in the S: line) */ +#define TKSERV_PASSWORD "blah" + +/* Debugging (displays service<->server traffic to standard output) */ +#undef TKSERV_DEBUG + +/* The name of the ircd config file backup (suffix after CPATH) */ +#define TKSERV_IRCD_CONFIG_BAK CPATH".tkserv" + +/* The name of the ircd temp config file (suffix after CPATH) */ +#define TKSERV_IRCD_CONFIG_TMP CPATH".tmp" + |