aboutsummaryrefslogtreecommitdiff
path: root/iauth
diff options
context:
space:
mode:
authorGravatar Jonas Gunz <himself@jonasgunz.de> 2020-05-25 20:09:04 +0200
committerGravatar Jonas Gunz <himself@jonasgunz.de> 2020-05-25 20:09:04 +0200
commit4440a86cfa359b8e40a484a2cd46d33db5455d8a (patch)
treef5c0c59aebf0058ae97e7ef8b5fb8017f459a05a /iauth
downloadircd-4440a86cfa359b8e40a484a2cd46d33db5455d8a.tar.gz
Initial
Diffstat (limited to 'iauth')
-rw-r--r--iauth/a_conf.c548
-rw-r--r--iauth/a_conf_def.h56
-rw-r--r--iauth/a_conf_ext.h43
-rw-r--r--iauth/a_defines.h39
-rw-r--r--iauth/a_externs.h34
-rw-r--r--iauth/a_io.c831
-rw-r--r--iauth/a_io_ext.h50
-rw-r--r--iauth/a_log.c123
-rw-r--r--iauth/a_log_def.h41
-rw-r--r--iauth/a_log_ext.h46
-rw-r--r--iauth/a_struct_def.h72
-rw-r--r--iauth/iauth.c226
-rw-r--r--iauth/mod_lhex.c318
-rw-r--r--iauth/mod_lhex_ext.h28
-rw-r--r--iauth/mod_pipe.c217
-rw-r--r--iauth/mod_pipe_ext.h28
-rw-r--r--iauth/mod_rfc931.c368
-rw-r--r--iauth/mod_rfc931_ext.h45
-rw-r--r--iauth/mod_socks.c632
-rw-r--r--iauth/mod_socks_ext.h28
20 files changed, 3773 insertions, 0 deletions
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 */