aboutsummaryrefslogtreecommitdiff
path: root/iauth/mod_rfc931.c
diff options
context:
space:
mode:
Diffstat (limited to 'iauth/mod_rfc931.c')
-rw-r--r--iauth/mod_rfc931.c368
1 files changed, 368 insertions, 0 deletions
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 };