--- /dev/null
+CFLAGS=-O0 -g -Wall -Wshadow -Werror
+
+all:
+ gcc -o iauth -O0 -g -Wall iauth.c iauth_io.c iauth_query.c iauth_cmd.c -Wshadow -Werror
+
+library:
+ gcc -o libiauth.so
+
+binary:
--- /dev/null
+/*
+ * Written by David Herrmann.
+ * Dedicated to the Public Domain.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "iauth.h"
+
+static unsigned int running = 1;
+
+static void iauth_signal(int sig) {
+ iauth_flog(IAUTH_INFO, "Caught signal %d, ignoring...", sig);
+}
+
+/* Parses one single input line. */
+void iauth_parse(char *line) {
+ unsigned int i, found;
+ signed int id;
+
+ /* The line has to look like:
+ * <id> X <several> <arguments>
+ */
+
+ found = 0;
+ for(i = 0; line[i]; ++i) {
+ if(line[i] == ' ') {
+ found = 1;
+ break;
+ }
+ }
+
+ /* Ignore invalid lines. */
+ if(!found) {
+ iauth_flog(IAUTH_WARNING, "Received invalid line; no subcommand specified.");
+ return;
+ }
+
+ /* Get the id. */
+ id = atoi(line);
+
+ /* Ignore invalid subcommands. */
+ if(!line[++i] || line[i] == ' ' || (line[i + 1] != ' ' && line[i + 1])) {
+ iauth_flog(IAUTH_WARNING, "Received invalid line; invalid subcommand.");
+ return;
+ }
+
+ /* Call the subcommand handler. */
+ switch(line[i]) {
+ case 'C':
+ /* Client Introduction: <id> C <remoteip> <remoteport> <localip> <localport> */
+ if(id >= 0 && id < iauth_clients_size && line[++i]) iauth_cmd_C(id, &line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid C line.");
+ break;
+ case 'D':
+ /* Client Disconnect: <id> D */
+ if(id >= 0 && id < iauth_clients_size) {
+ if(iauth_clients[id].id == id) iauth_cmd_D(&iauth_clients[id]);
+ else /* Ignore all other disconnects. */ ;
+ }
+ else iauth_flog(IAUTH_WARNING, "Received invalid D line.");
+ break;
+ case 'L':
+ /* Login On Connect: <id> L <account>[:<accountstamp>][ <fakehost>] */
+ if(id >= 0 && id < iauth_clients_size && line[++i] && iauth_clients[id].id == id) iauth_cmd_L(&iauth_clients[id], &line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid L line.");
+ break;
+ case 'H':
+ /* Hurry Up: <id> H <class> */
+ if(id >= 0 && id < iauth_clients_size && line[++i] && iauth_clients[id].id == id) iauth_cmd_H(&iauth_clients[id], &line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid H line.");
+ break;
+ case 'M':
+ /* Server Name and Capacity: <id> M <servername> <capacity> */
+ if(id == -1 && line[++i]) iauth_cmd_M(&line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid M line.");
+ break;
+ case 'N':
+ /* Hostname Received: <id> N <hostname> */
+ if(id >= 0 && id < iauth_clients_size && line[++i] && iauth_clients[id].id == id) iauth_cmd_N(&iauth_clients[id], &line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid N line.");
+ break;
+ case 'd':
+ /* Hostname Timeout: <id> d */
+ if(id >= 0 && id < iauth_clients_size && iauth_clients[id].id == id) iauth_cmd_d(&iauth_clients[id]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid d line.");
+ break;
+ case 'P':
+ /* Client Password: <id> P :<password ...> */
+ if(id >= 0 && id < iauth_clients_size && line[++i] && iauth_clients[id].id == id) iauth_cmd_P(&iauth_clients[id], &line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid P line.");
+ break;
+ case 'U':
+ /* Client Username: <id> U <username> <hostname> <servername> :<userinfo ...> */
+ if(id >= 0 && id < iauth_clients_size && line[++i] && iauth_clients[id].id == id) iauth_cmd_U(&iauth_clients[id], &line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid U line.");
+ break;
+ case 'u':
+ /* Client Username: <id> u <username> */
+ if(id >= 0 && id < iauth_clients_size && line[++i] && iauth_clients[id].id == id) iauth_cmd_u(&iauth_clients[id], &line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid u line.");
+ break;
+ case 'n':
+ /* Client Nickname: <id> n <nickname> */
+ if(id >= 0 && id < iauth_clients_size && line[++i] && iauth_clients[id].id == id) iauth_cmd_n(&iauth_clients[id], &line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid n line.");
+ break;
+ case 'T':
+ /* Client Registered: <id> T */
+ if(id >= 0 && id < iauth_clients_size && iauth_clients[id].id == id) iauth_cmd_T(&iauth_clients[id]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid T line.");
+ break;
+ case 'E':
+ /* Error: <id> E <type> :<additional text> */
+ if(line[++i]) iauth_cmd_E(id, &line[++i]);
+ else iauth_flog(IAUTH_WARNING, "Received invalid E line.");
+ break;
+ default:
+ /* Invalid subcommand; ignore. */
+ iauth_flog(IAUTH_WARNING, "Received invalid subcommand.");
+ return;
+ }
+
+ /* Subcommand called, nothing to do; return and await next line. */
+ return;
+}
+
+signed int main(signed int argc, char *argv[]) {
+ char *line;
+
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGINT, iauth_signal);
+ signal(SIGQUIT, iauth_signal);
+ signal(SIGTERM, iauth_signal);
+
+ if(argc > 1) iauth_logfile = argv[1];
+ if(argc > 2) iauth_scriptfile = argv[2];
+ if(argc > 3) iauth_debug = 1;
+
+ iauth_flog(IAUTH_INFO, "Starting IAuth");
+
+ iauth_query_version("OGN iauth");
+ iauth_query_policy("ARTU");
+ iauth_stats_report();
+
+ while(running && (line = iauth_read())) {
+ iauth_parse(line);
+ }
+
+ iauth_flog(IAUTH_INFO, "Stopping IAuth");
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+/*
+ * Written by David Herrmann.
+ * Dedicated to the Public Domain.
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+/* Global configuration.
+ * It is not recommended to change these values. They are set to
+ * an especially high value to support even the weirdest environments.
+ */
+/* Maximal length of a line. */
+#define IAUTH_LINE 4096
+/* Maximal capacity. */
+#define IAUTH_CAPMAX 1000000
+/* Maximum length of accounts/classes/fakehosts etc.. */
+#define IAUTH_DATALEN 256
+
+/* 1 if debug mode is enabled, otherwise 0. */
+extern unsigned int iauth_debug;
+
+/* Log functions.
+ * These functions write status data into a log file.
+ * They all do the same but take either a formatted argument
+ * or a va_list buffer.
+ * Error functions log the message and terminate the application,
+ * log functions only log the message.
+ */
+#define IAUTH_FATAL 0
+#define IAUTH_WARNING 1
+#define IAUTH_INFO 2
+#define IAUTH_DEBUG 3
+extern const char *iauth_logfile;
+extern void iauth_ferror(const char *format, ...);
+extern void iauth_verror(const char *format, va_list list);
+extern void iauth_flog(unsigned int type, const char *format, ...);
+extern void iauth_vlog(unsigned int type, const char *format, va_list list);
+extern void iauth_eflog(const char *format, ...);
+extern void iauth_evlog(const char *format, va_list list);
+
+/* IO functions.
+ * These functions either write a line to the IAuth or read a
+ * single line from the IAuth.
+ */
+extern char *iauth_read();
+extern void iauth_fsend(const char *format, ...);
+extern void iauth_vsend(const char *format, va_list list);
+
+/* Allocates/frees memory.
+ * Aborts with an appropriate message if the allocation fails.
+ */
+static inline void *iauth_malloc(size_t size) {
+ void *mem;
+ if(!(mem = malloc(size))) iauth_eflog("Memory allocation failed.");
+ memset(mem, 0, size);
+ return mem;
+}
+static inline char *iauth_strdup(const char *str) {
+ char *mem;
+ if(!(mem = strdup(str))) iauth_eflog("strdup() failed.");
+ return mem;
+}
+#define iauth_free(x) ((void)((x)?free(x):0))
+
+/* User management.
+ * Adds or removes a user.
+ */
+struct iauth_client {
+ signed int id;
+ char *ip;
+ unsigned short port;
+ char *lo_ip;
+ unsigned short lo_port;
+ char *host;
+ char *c_host;
+ char *c_serv;
+ char *nick;
+ char *username;
+ char *realname;
+ char *account;
+ char *fakehost;
+ char *cclass;
+ char *password;
+ char *ident;
+ unsigned int state_r : 1; /* Is in "registering" state. */
+ unsigned int state_h : 1; /* Is in "hurry" state. */
+};
+#define iauth_set(x, y) (iauth_free(x), (x = y))
+extern struct iauth_client *iauth_clients;
+extern unsigned int iauth_clients_size;
+extern void iauth_setcap(unsigned int cap);
+extern void iauth_addid(signed int id);
+extern void iauth_delid(signed int id);
+
+/* Request handler.
+ * The real requests are outsourced to a scriptfile.
+ * The iauth process spawns the scriptfile, passes the
+ * data as arguments and exspects the process to return
+ * the result on stdout.
+ * The scriptfile is spawned for every request.
+ */
+extern char *iauth_scriptfile;
+struct iauth_result {
+ char cclass[IAUTH_DATALEN + 1];
+ char ident[IAUTH_DATALEN + 1];
+ char host[IAUTH_DATALEN + 1];
+ char ip[IAUTH_DATALEN + 1];
+ char modes[IAUTH_DATALEN + 1];
+};
+extern const struct iauth_result *iauth_query(struct iauth_client *cli);
+extern char iauth_servname[IAUTH_DATALEN + 1];
+
+/* Sends a specific request to the ircd.
+ * This is a less generic but easier to use interface
+ * for the iauth_[vf]send() commands. This interface also
+ * correctly sends statistics.
+ */
+
+/* Operator Notification: > :<message text> */
+extern void iauth_query_fnotify(const char *format, ...);
+extern void iauth_query_vnotify(const char *format, va_list list);
+/* Set Debug Level: G <level> */
+extern void iauth_query_debug(unsigned int debuglevel);
+/* Set Policy Options: O <options> */
+extern void iauth_query_policy(const char *policy);
+/* iauth Program Version: V :<version string> */
+extern void iauth_query_version(const char *version);
+/* Start of new configuration: a */
+extern void iauth_query_newconf();
+/* Configuration Information: A <hosts?> <module> :<options> */
+extern void iauth_query_config(const char *hosts, const char *module, const char *value);
+/* Start of new statistics: s */
+extern void iauth_query_newstats();
+/* Statistics Information: S <module> :<module information> */
+extern void iauth_query_stats(const char *module, const char *value);
+/* Forced Username: o <id> <remoteip> <remoteport> <username> */
+extern void iauth_query_set_username(signed int id, const char *username);
+/* Trusted Username: U <id> <remoteip> <remoteport> <username> */
+extern void iauth_query_trust_username(signed int id, const char *username);
+/* Untrusted Username: u <id> <remoteip> <remoteport> <username> */
+extern void iauth_query_distrust_username(signed int id, const char *username);
+/* Client Hostname: N <id> <remoteip> <remoteport> <hostname> */
+extern void iauth_query_sethost(signed int id, const char *hostname);
+/* Client IP Address: I <id> <currentip> <remoteport> <newip> */
+extern void iauth_query_setip(signed int id, const char *ip);
+/* Adjust User Mode: M <id> <remoteip> <remoteport> +<mode changes> */
+extern void iauth_query_setmodes(signed int id, const char *modes);
+/* Challenge User: C <id> <remoteip> <remoteport> :<challenge string> */
+extern void iauth_query_challenge(signed int id, const char *challenge);
+/* Quietly Kill Client: k <id> <remoteip> <remoteport> :<reason> */
+extern void iauth_query_reject(signed int id, const char *reason);
+/* Kill Client: K <id> <remoteip> <remoteport> :<reason> */
+extern void iauth_query_kill(signed int id, const char *reason);
+/* Done Checking: D <id> <remoteip> <remoteport> [class] */
+extern void iauth_query_assign(signed int id, const char *cclass);
+/* Registered User: R <id> <remoteip> <remoteport> <account> [class] */
+extern void iauth_query_register(signed int id, const char *account, const char *cclass);
+
+/* Subcommand handlers. */
+extern void iauth_cmd_C(signed int id, char *arg);
+extern void iauth_cmd_D(struct iauth_client *client);
+extern void iauth_cmd_L(struct iauth_client *client, char *arg);
+extern void iauth_cmd_H(struct iauth_client *client, char *arg);
+extern void iauth_cmd_M(char *arg);
+extern void iauth_cmd_N(struct iauth_client *client, char *arg);
+extern void iauth_cmd_d(struct iauth_client *client);
+extern void iauth_cmd_P(struct iauth_client *client, char *arg);
+extern void iauth_cmd_U(struct iauth_client *client, char *arg);
+extern void iauth_cmd_u(struct iauth_client *client, char *arg);
+extern void iauth_cmd_n(struct iauth_client *client, char *arg);
+extern void iauth_cmd_T(struct iauth_client *client);
+extern void iauth_cmd_E(signed int id, char *arg);
+
+/* Statistics */
+extern void iauth_stats_report();
+extern void iauth_stats_loc_allow();
+extern void iauth_stats_loc_deny();
+extern void iauth_stats_def_allow();
+extern void iauth_stats_def_deny();
+
--- /dev/null
+#!/usr/bin/php
+<?php
+/* Written by David Herrmann.
+ * Dedicated to the Public Domain.
+ */
+/* PHP IAuth verifier.
+ * The IAuth collects all information from the ircd and when it thinks it has a complete
+ * set of information, it starts this script with all information as parameters. This
+ * script has to check the database for a dataset and return the values it wants to change
+ * or return nothing if it wants to reject the client.
+ *
+ * The data from the IAuth is passed in the array $argv. If a value is not available, it is
+ * an empty string. If a value is available it must be a string between 1 and IAUTH_DATALEN
+ * characters, whereas IAUTH_DATALEN is defined in iauth.h.
+ * - Name of the script:
+ * $argv[0] = ./iauth.php
+ * - The IP of the remote socket endpoint:
+ * $argv[1] = 85.214.49.253
+ * - The port of the remote socket endpoint:
+ * $argv[2] = 17655
+ * - The ip of the local socket endpoint:
+ * $argv[3] = 127.0.0.1
+ * - The port of the local socket endpoint:
+ * $argv[4] = 6667
+ * - The resolved hostname of the remote socket:
+ * $argv[5] = p3EE37393.dip.t-dialin.net
+ * - The hostname the user passed to USER:
+ * $argv[6] = localhost
+ * - The servername the user passed to USER:
+ * $argv[7] = irc.ogn.net
+ * - The nick which the user passed:
+ * $argv[8] = some_weird_nick
+ * - The username the user passed to USER:
+ * $argv[9] = username
+ * - The realname the user passed to USER:
+ * $argv[10] = realname
+ * - The account[:timestamp] which was proofed by LOC: (The :timestamp is optional)
+ * $argv[11] = some_account:124206424
+ * - The fakehost which was set by LOC:
+ * $argv[12] = cool.1337.fakehost
+ * - The class that the server would assign to the user if iauth would not be there:
+ * $argv[13] = some_server_class
+ * - The last PASS line the user sent:
+ * $argv[14] = some_password
+ * - The ident we got from the user's ident server:
+ * $argv[15] = ident
+ * - The name of the server we are connected to:
+ * $argv[16] = devnull.xy.net
+ *
+ * The response of the script is sent to STDOUT. If the script wants to reject the request, it can
+ * simply exit without sending anything.
+ * If you want to accept the client, you have to pass several parameters to STDOUT. Each parameter
+ * is separated by a space. If you want to skip a parameter, simply put "$" in there.
+ * Every value which is not "$" is forced on the user before he gets assigned to a class.
+ * Each value is limited again to IAUTH_DATALEN, however, the ircd itself may limit the data again,
+ * therefore, it is recommended to use short values. '\0' characters are not allowed in a reply and
+ * the IAuth parser will reject the query.
+ * The values are:
+ * - The class which is assigned to the user:
+ * echo "some_class ";
+ * - The ident which should be forced on the user:
+ * echo "FORCEIDENT ";
+ * - The host which should be forced on the user:
+ * echo "forced.host.on.user ";
+ * - The ip which should be forced on the user:
+ * echo "127.244.12.110 ";
+ * - A mode striing which is set on the user. This can include fakehosts/accounts/operators/etc.
+ * echo "+wogsfr 131071 fake.host.net account:124653295"
+ * The last parameter "mode" can have as many spaces as you want.
+ */
+
+/* These constants are defined to access $argv more easily. */
+define("ARG_REMOTEIP", $argv[1]);
+define("ARG_REMOTEPORT", $argv[2]);
+define("ARG_LOCALIP", $argv[3]);
+define("ARG_LOCALPORT", $argv[4]);
+define("ARG_HOSTNAME", $argv[5]);
+define("ARG_USER_HOST", $argv[6]);
+define("ARG_USER_SERV", $argv[7]);
+define("ARG_NICK", $argv[8]);
+define("ARG_USERNAME", $argv[9]);
+define("ARG_REALNAME", $argv[10]);
+define("ARG_TS_ACCOUNT", $argv[11]);
+define("ARG_ACCOUNT", preg_replace('/^(.*?)(:\d+)?$/', '$1', $argv[11]));
+define("ARG_FAKEHOST", $argv[12]);
+define("ARG_CLASS", $argv[13]);
+define("ARG_PASS", $argv[14]);
+define("ARG_IDENT", $argv[15]);
+define("ARG_SERVER", $argv[16]);
+
+/* This function can be used to return a result. */
+function iauth_return($class = NULL, $ident = NULL, $host = NULL, $ip = NULL, $mode = NULL) {
+ $class = trim($class);
+ $ident = trim($ident);
+ $host = trim($host);
+ $ip = trim((substr($ip, 0, 1) == ":") ? "0".$ip : $ip);
+ $mode = trim($mode);
+ if($class === NULL || strlen($class) == 0) $class = "$";
+ if($ident === NULL || strlen($ident) == 0) $ident = "$";
+ if($host === NULL || strlen($host) == 0) $host = "$";
+ if($ip === NULL || strlen($ip) == 0) $ip = "$";
+ if($mode === NULL || strlen($mode) == 0) $mode = "$";
+ echo "$class $ident $host $ip $mode";
+ exit(0);
+}
+
+/* This rejects the client. */
+function iauth_reject() {
+ exit(0);
+}
+
+/* Validate the input now and return the right result.
+ * REMEMBER: SOME VALUES MIGHT BE AN EMPTY STRING AND NOT SET!
+ */
+
+
+/****************************************************/
+/****************************************************/
+/* Following three example ways to handle a client. */
+/****************************************************/
+/****************************************************/
+
+/* Simply allow the client to connect the normal way. */
+/* iauth_return(); */
+
+/* Or as an example return only a class and a mode change. */
+/* iauth_return("class", NULL, NULL, NULL, "+rf account:14314789 fake.host.net"); */
+
+/* Or reject the client. */
+/* iauth_reject(); */
+
+/* our real implementation */
+iauth_return();
+
+?>
--- /dev/null
+/*
+ * Written by David Herrmann.
+ * Dedicated to the Public Domain.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "iauth.h"
+
+char iauth_servname[IAUTH_DATALEN + 1];
+
+static char *iauth_next_data(char **arg) {
+ char *sep, *ret;
+ unsigned int len;
+
+ while(**arg == ' ') ++*arg;
+ if(!**arg) return NULL;
+ if(**arg == ':' || !(sep = strchr(*arg, ' '))) {
+ if(**arg == ':') ++*arg;
+ len = strlen(*arg);
+ ret = iauth_malloc(len + 1);
+ strcpy(ret, *arg);
+ *arg += len;
+ if(len > IAUTH_DATALEN) ret[IAUTH_DATALEN] = 0;
+ else ret[len] = 0;
+ return ret;
+ }
+ else {
+ *sep = 0;
+ len = strlen(*arg);
+ ret = iauth_malloc(len + 1);
+ strcpy(ret, *arg);
+ if(len > IAUTH_DATALEN) ret[IAUTH_DATALEN] = 0;
+ else ret[len] = 0;
+ *sep = ' ';
+ *arg = sep + 1;
+ return ret;
+ }
+}
+
+/* Client Introduction: <id> C <remoteip> <remoteport> <localip> <localport> */
+void iauth_cmd_C(signed int id, char *arg) {
+ char *str;
+ struct iauth_client *cli;
+
+ iauth_delid(id);
+ iauth_addid(id);
+ cli = &iauth_clients[id];
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(cli->ip, str);
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ cli->port = atoi(str);
+ iauth_free(str);
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(cli->lo_ip, str);
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ cli->lo_port = atoi(str);
+ iauth_free(str);
+
+ iauth_flog(IAUTH_INFO, "New client (%d) from '%s':%hu to '%s':%hu.", id, cli->ip, cli->port, cli->lo_ip, cli->lo_port);
+
+ return;
+ parse_error:
+ iauth_flog(IAUTH_WARNING, "Parse error: Invalid C line.");
+ iauth_delid(id);
+ return;
+}
+
+/* Client Disconnect: <id> D */
+void iauth_cmd_D(struct iauth_client *client) {
+ iauth_delid(client->id);
+}
+
+/* Login On Connect: <id> L <account>[:<accountstamp>][ <fakehost>] */
+void iauth_cmd_L(struct iauth_client *client, char *arg) {
+ char *str;
+ const struct iauth_result *res;
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->account, str);
+
+ str = iauth_next_data(&arg);
+ if(str) iauth_set(client->fakehost, str);
+
+ /* Query database for account query. */
+ res = iauth_query(client);
+ if(!res) {
+ iauth_query_reject(client->id, "Access denied.");
+ iauth_stats_loc_deny();
+ }
+ else {
+ if(*res->ident) iauth_query_set_username(client->id, res->ident);
+ if(*res->host) iauth_query_sethost(client->id, res->host);
+ if(*res->ip) iauth_query_setip(client->id, res->ip);
+ if(*res->modes) iauth_query_setmodes(client->id, res->modes);
+ iauth_query_assign(client->id, (*res->cclass)?res->cclass:NULL);
+ iauth_stats_loc_allow();
+ }
+
+ iauth_delid(client->id);
+
+ return;
+ parse_error:
+ iauth_flog(IAUTH_WARNING, "Parse error: Invalid L line.");
+ return;
+}
+
+/* Hurry Up: <id> H <class> */
+void iauth_cmd_H(struct iauth_client *client, char *arg) {
+ char *str;
+ const struct iauth_result *res;
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->cclass, str);
+ client->state_h = 1;
+
+ /* Query database for account query. */
+ res = iauth_query(client);
+ if(!res) {
+ iauth_query_reject(client->id, "Access denied.");
+ iauth_stats_def_deny();
+ }
+ else {
+ if(*res->ident) iauth_query_set_username(client->id, res->ident);
+ if(*res->host) iauth_query_sethost(client->id, res->host);
+ if(*res->ip) iauth_query_setip(client->id, res->ip);
+ if(*res->modes) iauth_query_setmodes(client->id, res->modes);
+ iauth_query_assign(client->id, (*res->cclass)?res->cclass:NULL);
+ iauth_stats_def_allow();
+ }
+ iauth_delid(client->id);
+
+ return;
+ parse_error:
+ iauth_flog(IAUTH_WARNING, "Parse error: Invalid H line.");
+ return;
+}
+
+/* Server Name and Capacity: <id> M <servername> <capacity> */
+void iauth_cmd_M(char *arg) {
+ char *server = NULL, *str = NULL;
+ unsigned int cap;
+
+ server = iauth_next_data(&arg);
+ if(!server) goto parse_error;
+
+ str = iauth_next_data(&arg);
+ if(!str || !*str || (cap = atoi(str)) == 0) goto parse_error;
+ iauth_setcap(cap);
+ iauth_flog(IAUTH_INFO, "Setting server (%s) capacity to: %u.", server, cap);
+ strcpy(iauth_servname, server);
+ iauth_free(str);
+ iauth_free(server);
+
+ return;
+ parse_error:
+ iauth_flog(IAUTH_WARNING, "Parse error: Invalid M line.");
+ iauth_free(server);
+ iauth_free(str);
+ return;
+}
+
+/* Hostname Received: <id> N <hostname> */
+void iauth_cmd_N(struct iauth_client *client, char *arg) {
+ char *str;
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->host, str);
+
+ return;
+ parse_error:
+ iauth_flog(IAUTH_WARNING, "Parse error: Invalid N line.");
+ return;
+}
+
+/* Hostname Timeout: <id> d */
+void iauth_cmd_d(struct iauth_client *client) {
+ char *str;
+
+ str = iauth_malloc(1);
+ iauth_set(client->host, str);
+
+ return;
+}
+
+/* Client Password: <id> P :<password ...> */
+void iauth_cmd_P(struct iauth_client *client, char *arg) {
+ char *str;
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->password, str);
+
+ return;
+ parse_error:
+ iauth_flog(IAUTH_WARNING, "Parse error: Invalid P line.");
+ return;
+}
+
+/* Client Username: <id> U <username> <hostname> <servername> :<userinfo ...> */
+void iauth_cmd_U(struct iauth_client *client, char *arg) {
+ char *str;
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->username, str);
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->c_host, str);
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->c_serv, str);
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->realname, str);
+
+ return;
+ parse_error:
+ iauth_flog(IAUTH_WARNING, "Parse error: Invalid U line.");
+ return;
+}
+
+/* Client Username: <id> u <username> */
+void iauth_cmd_u(struct iauth_client *client, char *arg) {
+ char *str;
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->ident, str);
+
+ return;
+ parse_error:
+ iauth_flog(IAUTH_WARNING, "Parse error: Invalid u line.");
+ return;
+}
+
+/* Client Nickname: <id> n <nickname> */
+void iauth_cmd_n(struct iauth_client *client, char *arg) {
+ char *str;
+
+ str = iauth_next_data(&arg);
+ if(!str) goto parse_error;
+ iauth_set(client->nick, str);
+
+ return;
+ parse_error:
+ iauth_flog(IAUTH_WARNING, "Parse error: Invalid n line.");
+ return;
+}
+
+/* Client Registered: <id> T */
+void iauth_cmd_T(struct iauth_client *client) {
+ iauth_flog(IAUTH_INFO, "Client %d was registered without IAuth answer.", client->id);
+ iauth_delid(client->id);
+}
+
+/* Error: <id> E <type> :<additional text> */
+void iauth_cmd_E(signed int id, char *arg) {
+ iauth_flog(IAUTH_WARNING, "Received IRCd error: %s", arg);
+}
+
--- /dev/null
+/*
+ * Written by David Herrmann.
+ * Dedicated to the Public Domain.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#include <unistd.h>
+
+#include "iauth.h"
+
+/* /path/to/logfile.log or NULL. */
+const char *iauth_logfile = NULL;
+/* Current logfile or NULL. */
+FILE *logfile = NULL;
+/* 1 if debug mode is enabled, otherwise 0. */
+unsigned int iauth_debug = 0;
+
+static void iauth_error(const char *msg, size_t len) {
+ fwrite(msg, 1, len, stderr);
+ fwrite("\n", 1, 1, stderr);
+ /*abort();*/
+ exit(1);
+}
+
+void iauth_ferror(const char *format, ...) {
+ va_list arg;
+
+ va_start(arg, format);
+ iauth_verror(format, arg);
+ va_end(arg);
+}
+
+void iauth_verror(const char *format, va_list list) {
+ char buffer[IAUTH_LINE + 1];
+ size_t len;
+
+ memset(buffer, 0, IAUTH_LINE + 1);
+ len = vsnprintf(buffer, IAUTH_LINE, format, list);
+ if(!len) len = snprintf(buffer, IAUTH_LINE, "<no error message specified>");
+ iauth_error(buffer, len);
+}
+
+/* Checks whether we need to reopen the logfile.
+ * Aborts the application if the logfile cannot be
+ * opened.
+ */
+static void iauth_log_reopen() {
+ if(iauth_logfile) {
+ if(logfile) fclose(logfile);
+ logfile = fopen(iauth_logfile, "a");
+ if(!logfile) iauth_ferror("Logfile '%s' could not be opened in mode 'a'; errno = '%d'.", iauth_logfile, errno);
+ iauth_logfile = NULL;
+ }
+ else if(!logfile) iauth_ferror("No logfile specified.");
+}
+
+static void iauth_log(unsigned int type, const char *msg, size_t len) {
+ struct tm *tstamp;
+ time_t curtime;
+ char buffer[IAUTH_LINE + 1];
+ size_t len2;
+
+ iauth_log_reopen();
+
+ curtime = time(NULL);
+ tstamp = localtime(&curtime);
+ memset(buffer, 0, IAUTH_LINE + 1);
+ len2 = snprintf(buffer, IAUTH_LINE + 1, "[%02d.%02d.%d %02d:%02d:%02d]", tstamp->tm_mday, tstamp->tm_mon + 1, tstamp->tm_year + 1900,
+ tstamp->tm_hour, tstamp->tm_min, tstamp->tm_sec);
+ len2 += snprintf(&buffer[len2], IAUTH_LINE + 1 - len2, " (%s): ", (type == IAUTH_FATAL)?"FATAL":(type == IAUTH_WARNING)?"WARNING":
+ (type == IAUTH_INFO)?"INFO":(type == IAUTH_DEBUG)?"DEBUG":"UNKNOWN");
+
+ if(fwrite(buffer, 1, len2, logfile) != len2) iauth_ferror("Write operation on logfile failed; errno = '%d'.", errno);
+ if(fwrite(msg, 1, len, logfile) != len) iauth_ferror("Write operation on logfile failed; errno = '%d'.", errno);
+ fwrite("\n", 1, 1, logfile);
+ fflush(logfile);
+}
+
+void iauth_flog(unsigned int type, const char *format, ...) {
+ va_list arg;
+
+ va_start(arg, format);
+ iauth_vlog(type, format, arg);
+ va_end(arg);
+}
+
+void iauth_vlog(unsigned int type, const char *format, va_list list) {
+ char buffer[IAUTH_LINE + 1];
+ size_t len;
+
+ memset(buffer, 0, IAUTH_LINE + 1);
+ len = vsnprintf(buffer, IAUTH_LINE, format, list);
+ if(!len) len = snprintf(buffer, IAUTH_LINE, "<no message specified>");
+ iauth_log(type, buffer, len);
+}
+
+void iauth_eflog(const char *format, ...) {
+ va_list arg;
+
+ va_start(arg, format);
+ iauth_evlog(format, arg);
+ va_end(arg);
+}
+
+void iauth_evlog(const char *format, va_list list) {
+ char buffer[IAUTH_LINE + 1];
+ size_t len;
+
+ memset(buffer, 0, IAUTH_LINE + 1);
+ len = vsnprintf(buffer, IAUTH_LINE, format, list);
+ if(!len) len = snprintf(buffer, IAUTH_LINE, "<no message specified>");
+ iauth_log(IAUTH_FATAL, buffer, len);
+ iauth_error(buffer, len);
+}
+
+char *iauth_read() {
+ static char buffer[IAUTH_LINE + 1];
+ unsigned int i, ignore = 0;
+
+ next_line:
+
+ if(!fgets(buffer, IAUTH_LINE, stdin)) {
+ if(feof(stdin)) return NULL;
+ iauth_eflog("Reading on stdin failed; errno = '%d'.", errno);
+ }
+ buffer[IAUTH_LINE] = 0;
+
+ for(i = 0; i < IAUTH_LINE; ++i) {
+ if(buffer[i] == '\n') {
+ if(ignore) {
+ ignore = 0;
+ goto next_line;
+ }
+ if(i == 0) goto next_line;
+ if(buffer[i - 1] == '\r') {
+ if(i == 1) goto next_line;
+ buffer[i - 1] = 0;
+ }
+ else buffer[i] = 0;
+ if(iauth_debug) {
+ iauth_flog(IAUTH_DEBUG, "IN -> %s", buffer);
+ }
+ return buffer;
+ }
+ }
+
+ /* Too long message. Discard it! */
+ iauth_flog(IAUTH_WARNING, "Message exceeded maximum length of '%d' bytes.", IAUTH_LINE);
+ ignore = 1;
+ goto next_line;
+}
+
+void iauth_fsend(const char *format, ...) {
+ va_list arg;
+
+ va_start(arg, format);
+ iauth_vsend(format, arg);
+ va_end(arg);
+}
+
+void iauth_vsend(const char *format, va_list list) {
+ char buffer[IAUTH_LINE + 1];
+ size_t len, len2;
+
+ memset(buffer, 0, IAUTH_LINE + 1);
+ if(iauth_debug) {
+ len2 = snprintf(buffer, IAUTH_LINE, "OUT <- ");
+ len = vsnprintf(&buffer[len2], IAUTH_LINE, format, list);
+ if(!len) return;
+ iauth_log(IAUTH_DEBUG, buffer, len + len2);
+ if(write(0, &buffer[len2], len) != len) iauth_eflog("IAuth write operation failed; errno = '%d'", errno);
+ write(0, "\r\n", 2);
+ }
+ else {
+ len = vsnprintf(buffer, IAUTH_LINE, format, list);
+ if(!len) return;
+ if(write(0, buffer, len) != len) iauth_eflog("IAuth write operation failed; errno = '%d'", errno);
+ write(0, "\r\n", 2);
+ }
+}
--- /dev/null
+/*
+ * Written by David Herrmann.
+ * Dedicated to the Public Domain.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include "iauth.h"
+
+/* File which is spawned on a query. */
+char *iauth_scriptfile = NULL;
+
+const struct iauth_result *iauth_query(struct iauth_client *cli) {
+ static struct iauth_result res;
+ static char buffer[IAUTH_DATALEN * 5 + 5];
+ pid_t cpid;
+ signed int fds[2], ret;
+ char ** parv;
+ char portbuf[6], portbuf2[6];
+ char c = 0;
+ char *arg, *tread;
+
+ memset(&res, 0, sizeof(res));
+ memset(portbuf, 0, 6);
+ memset(portbuf2, 0, 6);
+ if(!iauth_scriptfile) return &res;
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) {
+ iauth_flog(IAUTH_WARNING, "socketpair() failed; errno = '%d'.", errno);
+ return NULL;
+ }
+
+ cpid = fork();
+ if(cpid < 0) {
+ close(fds[0]);
+ close(fds[1]);
+ iauth_flog(IAUTH_WARNING, "fork() failed; errno = '%d'.", errno);
+ return NULL;
+ }
+
+ if(cpid == 0) {
+ /* This is the child.
+ * Close the parents socket. Spawn the DB process with the socket
+ * set as stdout.
+ * When done, close the socket and exit the child.
+ * We directly fork() again to prevent zombies.
+ */
+ close(fds[0]);
+ cpid = fork();
+ if(cpid < 0) exit(EXIT_FAILURE);
+ if(cpid != 0) exit(EXIT_SUCCESS);
+
+ #define ISIZE 18
+ parv = iauth_malloc(sizeof(char*) * ISIZE);
+ parv[0] = iauth_scriptfile;
+ parv[1] = cli->ip?cli->ip:&c;
+ snprintf(portbuf, 5, "%hu", cli->port);
+ parv[2] = portbuf;
+ parv[3] = cli->lo_ip?cli->lo_ip:&c;
+ snprintf(portbuf2, 5, "%hu", cli->lo_port);
+ parv[4] = portbuf2;
+ parv[5] = cli->host?cli->host:&c;
+ parv[6] = cli->c_host?cli->c_host:&c;
+ parv[7] = cli->c_serv?cli->c_serv:&c;
+ parv[8] = cli->nick?cli->nick:&c;
+ parv[9] = cli->username?cli->username:&c;
+ parv[10] = cli->realname?cli->realname:&c;
+ parv[11] = cli->account?cli->account:&c;
+ parv[12] = cli->fakehost?cli->fakehost:&c;
+ parv[13] = cli->cclass?cli->cclass:&c;
+ parv[14] = cli->password?cli->password:&c;
+ parv[15] = cli->ident?cli->ident:&c;
+ parv[16] = iauth_servname;
+ parv[ISIZE - 1] = NULL;
+ #undef ISIZE
+
+ if(dup2(fds[1], 1) != -1) {
+ execvp(iauth_scriptfile, parv);
+ iauth_flog(IAUTH_WARNING, "execvp() failed; errno = '%d'.", errno);
+ }
+ else iauth_flog(IAUTH_WARNING, "dup2() failed; errno = '%d'.", errno);
+ iauth_free(parv);
+ close(fds[1]);
+ exit(EXIT_FAILURE);
+ }
+
+ /* We are the parent. Read on the file descriptor until it is closed. */
+ close(fds[1]);
+
+ /* Wait for client. The client directly forked again, so this should
+ * not *really* block.
+ * This whole mechanism prevents zombies.
+ */
+ wait(NULL);
+
+ tread = buffer;
+ if((ret = read(fds[0], buffer, sizeof(buffer))) < 1) {
+ close(fds[0]);
+ return NULL;
+ }
+ buffer[sizeof(buffer) - 1] = 0;
+
+ /* Read class. */
+ if(!(arg = strchr(tread, ' '))) {
+ close(fds[0]);
+ return NULL;
+ }
+ *arg++ = 0;
+ if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.cclass[0] = 0;
+ else strcpy(res.cclass, tread);
+
+ /* Read ident. */
+ tread = arg;
+ if(!(arg = strchr(tread, ' '))) {
+ close(fds[0]);
+ return NULL;
+ }
+ *arg++ = 0;
+ if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.ident[0] = 0;
+ else strcpy(res.ident, tread);
+
+ /* Read host. */
+ tread = arg;
+ if(!(arg = strchr(tread, ' '))) {
+ close(fds[0]);
+ return NULL;
+ }
+ *arg++ = 0;
+ if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.host[0] = 0;
+ else strcpy(res.host, tread);
+
+ /* Read ip. */
+ tread = arg;
+ if(!(arg = strchr(tread, ' '))) {
+ close(fds[0]);
+ return NULL;
+ }
+ *arg++ = 0;
+ if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.ip[0] = 0;
+ else strcpy(res.ip, tread);
+
+ /* Read modes string. */
+ tread = arg;
+ if(!*tread) {
+ close(fds[0]);
+ return NULL;
+ }
+ if(strcmp(tread, "$") == 0 || strlen(tread) > IAUTH_DATALEN) res.modes[0] = 0;
+ else strcpy(res.modes, tread);
+
+ close(fds[0]);
+ return &res;
+}
+
+/* User management.
+ * Adds or removes a user.
+ */
+struct iauth_client *iauth_clients = NULL;
+unsigned int iauth_clients_size = 0;
+
+void iauth_setcap(unsigned int cap) {
+ if(iauth_clients_size) return;
+ iauth_clients = iauth_malloc(sizeof(struct iauth_client) * cap);
+ iauth_clients_size = cap;
+}
+
+void iauth_addid(signed int id) {
+ if(id < 0) return;
+ if(!iauth_clients_size || id >= iauth_clients_size) return;
+ memset(&iauth_clients[id], 0, sizeof(struct iauth_client));
+ iauth_clients[id].state_r = 1;
+ iauth_clients[id].id = id;
+}
+
+void iauth_delid(signed int id) {
+ if(id < 0) return;
+ if(!iauth_clients_size || id >= iauth_clients_size) return;
+ iauth_free(iauth_clients[id].ip);
+ iauth_free(iauth_clients[id].lo_ip);
+ iauth_free(iauth_clients[id].host);
+ iauth_free(iauth_clients[id].c_host);
+ iauth_free(iauth_clients[id].c_serv);
+ iauth_free(iauth_clients[id].nick);
+ iauth_free(iauth_clients[id].username);
+ iauth_free(iauth_clients[id].realname);
+ iauth_free(iauth_clients[id].account);
+ iauth_free(iauth_clients[id].fakehost);
+ iauth_free(iauth_clients[id].cclass);
+ iauth_free(iauth_clients[id].password);
+ iauth_free(iauth_clients[id].ident);
+ memset(&iauth_clients[id], 0, sizeof(struct iauth_client));
+}
+
+static unsigned int loc_allow = 0;
+static unsigned int loc_deny = 0;
+static unsigned int def_allow = 0;
+static unsigned int def_deny = 0;
+
+void iauth_stats_report() {
+ static unsigned int stats = 0;
+ static char buffer[512];
+
+ ++stats;
+
+ if(stats == 1) {
+ iauth_query_newconf();
+ iauth_query_config("*", "loc", "Login-On-Connect handler");
+ iauth_query_config("*", "def", "Default handler");
+ }
+ if(stats < 10) goto report;
+ else if((stats % 10) == 0) goto report;
+ else return;
+
+ report:
+ iauth_query_newstats();
+ sprintf(buffer, "Count: %u Allowed: %u Denied: %u", loc_allow + loc_deny, loc_allow, loc_deny);
+ iauth_query_stats("loc", buffer);
+ sprintf(buffer, "Count: %u Allowed: %u Denied: %u", def_allow + def_deny, def_allow, def_deny);
+ iauth_query_stats("def", buffer);
+}
+
+void iauth_stats_loc_allow() {
+ ++loc_allow;
+ iauth_stats_report();
+}
+
+void iauth_stats_loc_deny() {
+ ++loc_deny;
+ iauth_stats_report();
+}
+
+void iauth_stats_def_allow() {
+ ++def_allow;
+ iauth_stats_report();
+}
+
+void iauth_stats_def_deny() {
+ ++def_deny;
+ iauth_stats_report();
+}
+
+/* Sends a specific request to the ircd.
+ * This is a less generic but easier to use interface
+ * for the iauth_[vf]send() commands. This interface also
+ * correctly sends statistics.
+ */
+
+/* Operator Notification: > :<message text> */
+extern void iauth_query_fnotify(const char *format, ...) {
+ va_list arg;
+
+ va_start(arg, format);
+ iauth_query_vnotify(format, arg);
+ va_end(arg);
+}
+extern void iauth_query_vnotify(const char *format, va_list list) {
+ char buffer[IAUTH_LINE + 1];
+
+ buffer[IAUTH_LINE] = 0;
+ sprintf(buffer, "> :");
+ vsnprintf(buffer, IAUTH_LINE - 4, format, list);
+ iauth_fsend(buffer);
+}
+
+/* Set Debug Level: G <level> */
+extern void iauth_query_debug(unsigned int debuglevel) {
+ iauth_fsend("G %u", debuglevel);
+}
+
+/* Set Policy Options: O <options> */
+extern void iauth_query_policy(const char *policy) {
+ iauth_fsend("O %s", policy);
+}
+
+/* iauth Program Version: V :<version string> */
+extern void iauth_query_version(const char *version) {
+ iauth_fsend("V :%s", version);
+}
+
+/* Start of new configuration: a */
+extern void iauth_query_newconf() {
+ iauth_fsend("a");
+}
+
+/* Configuration Information: A <hosts?> <module> :<options> */
+extern void iauth_query_config(const char *hosts, const char *module, const char *value) {
+ iauth_fsend("A %s %s :%s", hosts, module, value);
+}
+
+/* Start of new statistics: s */
+extern void iauth_query_newstats() {
+ iauth_fsend("s");
+}
+
+/* Statistics Information: S <module> :<module information> */
+extern void iauth_query_stats(const char *module, const char *value) {
+ iauth_fsend("S %s :%s", module, value);
+}
+
+/* Forced Username: o <id> <remoteip> <remoteport> <username> */
+extern void iauth_query_set_username(signed int id, const char *username) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ iauth_fsend("o %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, username);
+}
+
+/* Trusted Username: U <id> <remoteip> <remoteport> <username> */
+extern void iauth_query_trust_username(signed int id, const char *username) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ iauth_fsend("U %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, username);
+}
+
+/* Untrusted Username: u <id> <remoteip> <remoteport> <username> */
+extern void iauth_query_distrust_username(signed int id, const char *username) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ iauth_fsend("u %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, username);
+}
+
+/* Client Hostname: N <id> <remoteip> <remoteport> <hostname> */
+extern void iauth_query_sethost(signed int id, const char *hostname) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ iauth_fsend("N %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, hostname);
+}
+
+/* Client IP Address: I <id> <currentip> <remoteport> <newip> */
+extern void iauth_query_setip(signed int id, const char *ip) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ iauth_fsend("I %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, ip);
+ iauth_free(iauth_clients[id].ip);
+ iauth_clients[id].ip = iauth_strdup(ip);
+}
+
+/* Adjust User Mode: M <id> <remoteip> <remoteport> +<mode changes> */
+extern void iauth_query_setmodes(signed int id, const char *modes) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ iauth_fsend("M %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, modes);
+}
+
+/* Challenge User: C <id> <remoteip> <remoteport> :<challenge string> */
+extern void iauth_query_challenge(signed int id, const char *challenge) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ iauth_fsend("C %d %s %hu :%s", id, iauth_clients[id].ip, iauth_clients[id].port, challenge);
+}
+
+/* Quietly Kill Client: k <id> <remoteip> <remoteport> :<reason> */
+extern void iauth_query_reject(signed int id, const char *reason) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ iauth_fsend("k %d %s %hu :%s", id, iauth_clients[id].ip, iauth_clients[id].port, reason);
+ iauth_delid(id);
+}
+
+/* Kill Client: K <id> <remoteip> <remoteport> :<reason> */
+extern void iauth_query_kill(signed int id, const char *reason) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ iauth_fsend("K %d %s %hu :%s", id, iauth_clients[id].ip, iauth_clients[id].port, reason);
+ iauth_delid(id);
+}
+
+/* Done Checking: D <id> <remoteip> <remoteport> [class] */
+extern void iauth_query_assign(signed int id, const char *cclass) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ if(cclass)
+ iauth_fsend("D %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, cclass);
+ else
+ iauth_fsend("D %d %s %hu", id, iauth_clients[id].ip, iauth_clients[id].port);
+ iauth_delid(id);
+}
+
+/* Registered User: R <id> <remoteip> <remoteport> <account> [class] */
+extern void iauth_query_register(signed int id, const char *account, const char *cclass) {
+ if(id < 0 || id >= iauth_clients_size) return;
+ if(cclass)
+ iauth_fsend("D %d %s %hu %s %s", id, iauth_clients[id].ip, iauth_clients[id].port, account, cclass);
+ else
+ iauth_fsend("D %d %s %hu %s", id, iauth_clients[id].ip, iauth_clients[id].port, account);
+ iauth_delid(id);
+}
+