From 4440a86cfa359b8e40a484a2cd46d33db5455d8a Mon Sep 17 00:00:00 2001 From: Jonas Gunz Date: Mon, 25 May 2020 20:09:04 +0200 Subject: Initial --- contrib/README | 21 + contrib/RULES | 24 + contrib/antispoof.README | 56 ++ contrib/antispoof.diff | 484 ++++++++++++++++ contrib/ircdwatch/README | 56 ++ contrib/ircdwatch/ircdwatch.8 | 50 ++ contrib/ircdwatch/ircdwatch.c | 499 +++++++++++++++++ contrib/mkpasswd/README | 64 +++ contrib/mkpasswd/crypter | 55 ++ contrib/mkpasswd/mkpasswd.c | 44 ++ contrib/mod_passwd/README | 30 + contrib/mod_passwd/mod_passwd.c | 171 ++++++ contrib/tkserv/CHANGES | 37 ++ contrib/tkserv/CREDITS | 60 ++ contrib/tkserv/INSTALL | 20 + contrib/tkserv/README | 290 ++++++++++ contrib/tkserv/proto.h | 24 + contrib/tkserv/tkserv.access.example | 10 + contrib/tkserv/tkserv.c | 1022 ++++++++++++++++++++++++++++++++++ 19 files changed, 3017 insertions(+) create mode 100644 contrib/README create mode 100644 contrib/RULES create mode 100644 contrib/antispoof.README create mode 100644 contrib/antispoof.diff create mode 100644 contrib/ircdwatch/README create mode 100644 contrib/ircdwatch/ircdwatch.8 create mode 100644 contrib/ircdwatch/ircdwatch.c create mode 100644 contrib/mkpasswd/README create mode 100755 contrib/mkpasswd/crypter create mode 100644 contrib/mkpasswd/mkpasswd.c create mode 100644 contrib/mod_passwd/README create mode 100644 contrib/mod_passwd/mod_passwd.c create mode 100644 contrib/tkserv/CHANGES create mode 100644 contrib/tkserv/CREDITS create mode 100644 contrib/tkserv/INSTALL create mode 100644 contrib/tkserv/README create mode 100644 contrib/tkserv/proto.h create mode 100644 contrib/tkserv/tkserv.access.example create mode 100644 contrib/tkserv/tkserv.c (limited to 'contrib') diff --git a/contrib/README b/contrib/README new file mode 100644 index 0000000..7d62989 --- /dev/null +++ b/contrib/README @@ -0,0 +1,21 @@ +$Id: README,v 1.6 1999/03/13 23:06:15 kalt Exp $ + +This directory contains ircd related contributions. Most of them fall + in one of the following categories: + * small side utility + * code sample + * service + +Each contribution lives in its own directory under contrib/ and has a +README file. For those which need to be compiled, this can be done in +the same directory as you compiled irc and/or ircd. + +If you want to submit a package for this directory, see the RULES file. + +--- + +mkpasswd utility to crypt a password. +ircdwatch utility to keep ircd running (eventually restarting it). +tkserv stupid toy to manage "temporary" klines. +mod_passwd example of DSM module for iauth +antispoof.diff diff file to add extra code to ircd to prevent TCP spoofing diff --git a/contrib/RULES b/contrib/RULES new file mode 100644 index 0000000..f3de2a1 --- /dev/null +++ b/contrib/RULES @@ -0,0 +1,24 @@ +$Id: RULES,v 1.2 1998/11/09 20:07:12 kalt Exp $ + +This file describes how to prepare a package for inclusion +in the contrib/ directory. The goal is to have a consistent +setup for all contributions, making it easy to install any +of them. + +* each package must have a README file (at least) explaining + what it is about. +* a man page would be nice ;-) + +* packages are stored in contrib/ + +* C programs: + * If possible, use the same coding style as in the + rest of the package. + * They need to be portable + * They should use "setup.h" or "os.h" + * If needed, they may have a *.h file generated by configure + * They are to be compiled from within the same + directory as irc/ircd, using the same Makefile + + +* questions, submissions should be sent to ircd-dev@irc.org diff --git a/contrib/antispoof.README b/contrib/antispoof.README new file mode 100644 index 0000000..fd1d5a7 --- /dev/null +++ b/contrib/antispoof.README @@ -0,0 +1,56 @@ +The nospoof patch was adapted from the nospoof5 patch in use on Undernet +servers. It should NOT be needed unless you're running ircd on a really +old OS which doesn't have a patch against TCP spoofing. Note that this +patch should be applied BEFORE running ./configure -- this is very +important, and the usual cause of any problems encountered. + +When a client connects to the server, they are sent a PING with a random +number (please do not confuse this with a CTCP PING -- they're very +different things). Until the client responds with a PONG and the correct +random number, it is not registered with the server and cannot do +anything. + +Please note that this does break the RFC. However, it has been tested +with most popular clients and is in common use on large IRC networks +currently. The only reported client to have problems is Homer (for +the Macintosh). + +To cater for possibly broken clients, a message is also sent to clients +on connect of the form: + +*** If your client freezes here, type /QUOTE PONG 12345678 or /PONG 12345678 + +Because of this, it is a good idea to increase the allowed timeout on +connections since the user might have to manually PONG the server with +the ugly number (although hopefully they only need to cut'n'paste). + +If the client PONGs with the wrong number, another message is sent to +the client directing the user what to type. In addition, if the +connection does end up timing out due to no PONG, a message is sent to +the user explaining the client may not be compatible, and lists where +compatible clients for all the major platforms can be found. + +The random number sequence is based on an md5 series. I didn't write it. +Someone else did. It's included because many have a dud random() in their +libc (this applies to more people than you think). It is seeded on a +#define value in config.h - YOU MUST CHANGE THIS FROM THE DEFAULT OR YOU +CAN STILL BE SPOOFED. If you still find that you get spoofed, try +changing this value again and recompiling. + +KNOWN BUGS: + + - There is a known bug whereby the host provided by the client's + USER sequence is not checked for validity until after the PONG + reply (and registration takes place). This allows a form of + "spoofing" to take place, with the client showing under /whois + lookups with a fake hostname. At this stage the client can't + actually issue commands to the server though, and the hostmask + is corrected to what it should be upon the PONG being received + (and the client properly registered). + + - The random number generator isn't 64-bit clean. On 64-bit + machines, a 64-bit random number is generated, but I'm not + convinced all 64-bits are random. At least 32 bits are + however, so this isn't a problem. + + - Andrew (earthpig@yoyo.cc.monash.edu.au) diff --git a/contrib/antispoof.diff b/contrib/antispoof.diff new file mode 100644 index 0000000..b02832f --- /dev/null +++ b/contrib/antispoof.diff @@ -0,0 +1,484 @@ +diff -urN irc-cvs/common/numeric_def.h irc-cvs-nospoof/common/numeric_def.h +--- irc-cvs/common/numeric_def.h Wed Jan 20 12:28:46 1999 ++++ irc-cvs-nospoof/common/numeric_def.h Tue Mar 16 12:45:56 1999 +@@ -198,6 +198,10 @@ + #define ERR_UMODEUNKNOWNFLAG 501 + #define ERR_USERSDONTMATCH 502 + ++#if defined(NOSPOOF) ++#define ERR_BADPING 513 ++#endif ++ + /* + * Numberic replies from server commands. + * These are currently in the range 200-399. +diff -urN irc-cvs/common/parse.c irc-cvs-nospoof/common/parse.c +--- irc-cvs/common/parse.c Tue Dec 29 02:44:57 1998 ++++ irc-cvs-nospoof/common/parse.c Tue Mar 16 12:45:56 1999 +@@ -56,7 +56,11 @@ + { MSG_INVITE, m_invite, MAXPARA, MSG_LAG|MSG_REGU, 0, 0, 0L}, + { MSG_WALLOPS, m_wallops, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L}, + { MSG_PING, m_ping, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, ++#if defined(NOSPOOF) ++ { MSG_PONG, m_pong, MAXPARA, MSG_LAG, 0, 0, 0L}, ++#else + { MSG_PONG, m_pong, MAXPARA, MSG_LAG|MSG_REG, 0, 0, 0L}, ++#endif + { MSG_ERROR, m_error, MAXPARA, MSG_LAG|MSG_REG|MSG_NOU, 0, 0, 0L}, + #ifdef OPER_KILL + { MSG_KILL, m_kill, MAXPARA, MSG_LAG|MSG_REG|MSG_OP|MSG_LOP, 0,0, 0L}, +diff -urN irc-cvs/common/send.c irc-cvs-nospoof/common/send.c +--- irc-cvs/common/send.c Fri Feb 5 10:26:35 1999 ++++ irc-cvs-nospoof/common/send.c Tue Mar 16 12:45:56 1999 +@@ -392,6 +392,9 @@ + NULL, + # endif + 0, {0, 0, NULL }, {0, 0, NULL }, ++#if defined(NOSPOOF) ++ -1, ++#endif + 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, NULL, 0 + # if defined(__STDC__) /* hack around union{} initialization -Vesa */ + ,{0}, NULL, "", "" +diff -urN irc-cvs/common/struct_def.h irc-cvs-nospoof/common/struct_def.h +--- irc-cvs/common/struct_def.h Sun Mar 14 11:59:54 1999 ++++ irc-cvs-nospoof/common/struct_def.h Tue Mar 16 12:45:56 1999 +@@ -432,6 +432,9 @@ + short lastsq; /* # of 2k blocks when sendqueued called last*/ + dbuf sendQ; /* Outgoing message queue--if socket full */ + dbuf recvQ; /* Hold for data incoming yet to be parsed */ ++#if defined(NOSPOOF) ++ u_long cookie; /* Random cookie local clients must PONG */ ++#endif + long sendM; /* Statistics: protocol messages send */ + long sendK; /* Statistics: total k-bytes send */ + long receiveM; /* Statistics: protocol messages received */ +diff -urN irc-cvs/ircd/ircd.c irc-cvs-nospoof/ircd/ircd.c +--- irc-cvs/ircd/ircd.c Sun Mar 14 11:59:58 1999 ++++ irc-cvs-nospoof/ircd/ircd.c Tue Mar 16 12:45:56 1999 +@@ -493,6 +493,22 @@ + else + { + cptr->exitc = EXITC_PING; ++#if defined(NOSPOOF) ++ if((!IsRegistered(cptr)) && (cptr->name) && ++ (cptr->username)) ++ { ++ sendto_one(cptr, ++ ":%s %d %s :Your client may not be compatible with this server.", ++ me.name, ERR_BADPING, cptr->name); ++ /* Someone suggest a better ++ * place? :) - Earthpig ++ */ ++ sendto_one(cptr, ++ ":%s %d %s :Compatible clients are available at " ++ "ftp://yoyo.cc.monash.edu.au/pub/irc/clients/", ++ me.name, ERR_BADPING, cptr->name); ++ } ++#endif + (void)exit_client(cptr, cptr, &me, + "Ping timeout"); + } +diff -urN irc-cvs/ircd/list.c irc-cvs-nospoof/ircd/list.c +--- irc-cvs/ircd/list.c Tue Dec 29 02:44:57 1998 ++++ irc-cvs-nospoof/ircd/list.c Tue Mar 16 12:45:56 1999 +@@ -146,6 +146,9 @@ + if (size == CLIENT_LOCAL_SIZE) + { + cptr->since = cptr->lasttime = cptr->firsttime = timeofday; ++#if defined(NOSPOOF) ++ cptr->cookie = 0; ++#endif + cptr->confs = NULL; + cptr->sockhost[0] = '\0'; + cptr->buffer[0] = '\0'; +diff -urN irc-cvs/ircd/random.c irc-cvs-nospoof/ircd/random.c +--- irc-cvs/ircd/random.c Thu Jan 1 10:00:00 1970 ++++ irc-cvs-nospoof/ircd/random.c Tue Mar 16 12:45:56 1999 +@@ -0,0 +1,162 @@ ++/************************************************************************ ++ * IRC - Internet Relay Chat, ircd/random.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 1, or (at your option) ++ * any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include ++#include ++#include ++#include ++#include "os.h" ++#include "s_defines.h" ++ ++#ifdef NOSPOOF ++ ++char localkey[8] = RANDOM_SEED; ++ ++/* ++ * MD5 transform algorithm, taken from code written by Colin Plumb, ++ * and put into the public domain ++ * ++ * Kev: Taken from Ted T'so's /dev/random random.c code and modified to ++ * be slightly simpler. That code is released under a BSD-style copyright ++ * OR under the terms of the GNU Public License, which should be included ++ * at the top of this source file. ++ * ++ * record: Cleaned up to work with ircd. RANDOM_TOKEN is defined in ++ * setup.h by the make script; if people start to "guess" your cookies, ++ * consider recompiling your server with a different random token. ++ */ ++ ++/* The four core functions - F1 is optimized somewhat */ ++ ++#define F1(x, y, z) (z ^ (x & (y ^ z))) ++#define F2(x, y, z) F1(z, x, y) ++#define F3(x, y, z) (x ^ y ^ z) ++#define F4(x, y, z) (y ^ (x | ~z)) ++ ++/* This is the central step in the MD5 algorithm. */ ++#define MD5STEP(f, w, x, y, z, data, s) \ ++ ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) ++ ++/* ++ * The core of the MD5 algorithm, this alters an existing MD5 hash to ++ * reflect the addition of 16 longwords of new data. MD5Update blocks ++ * the data and converts bytes into longwords for this routine. ++ * ++ * original comment left in; this used to be called MD5Transform and took ++ * two arguments; I've internalized those arguments, creating the character ++ * array "localkey," which should contain 8 bytes of data. The function also ++ * originally returned nothing; now it returns an unsigned long that is the ++ * random number. It appears to be reallyrandom, so... -Kev ++ * ++ * I don't really know what this does. I tried to figure it out and got ++ * a headache. If you know what's good for you, you'll leave this stuff ++ * for the smart people and do something else. -record ++ */ ++unsigned long ircrandom(void) ++{ ++ unsigned long a, b, c, d; ++ unsigned char in[16]; ++ struct timeval tv; ++ ++ (void)gettimeofday(&tv, NULL); ++ ++ (void)memcpy((void *)in, (void *)localkey, 8); ++ (void)memcpy((void *)(in+8), (void *)&tv.tv_sec, 4); ++ (void)memcpy((void *)(in+12), (void *)&tv.tv_usec, 4); ++ ++ a = 0x67452301; ++ b = 0xefcdab89; ++ c = 0x98badcfe; ++ d = 0x10325476; ++ ++ MD5STEP(F1, a, b, c, d, (long)in[ 0]+0xd76aa478, 7); ++ MD5STEP(F1, d, a, b, c, (long)in[ 1]+0xe8c7b756, 12); ++ MD5STEP(F1, c, d, a, b, (long)in[ 2]+0x242070db, 17); ++ MD5STEP(F1, b, c, d, a, (long)in[ 3]+0xc1bdceee, 22); ++ MD5STEP(F1, a, b, c, d, (long)in[ 4]+0xf57c0faf, 7); ++ MD5STEP(F1, d, a, b, c, (long)in[ 5]+0x4787c62a, 12); ++ MD5STEP(F1, c, d, a, b, (long)in[ 6]+0xa8304613, 17); ++ MD5STEP(F1, b, c, d, a, (long)in[ 7]+0xfd469501, 22); ++ MD5STEP(F1, a, b, c, d, (long)in[ 8]+0x698098d8, 7); ++ MD5STEP(F1, d, a, b, c, (long)in[ 9]+0x8b44f7af, 12); ++ MD5STEP(F1, c, d, a, b, (long)in[10]+0xffff5bb1, 17); ++ MD5STEP(F1, b, c, d, a, (long)in[11]+0x895cd7be, 22); ++ MD5STEP(F1, a, b, c, d, (long)in[12]+0x6b901122, 7); ++ MD5STEP(F1, d, a, b, c, (long)in[13]+0xfd987193, 12); ++ MD5STEP(F1, c, d, a, b, (long)in[14]+0xa679438e, 17); ++ MD5STEP(F1, b, c, d, a, (long)in[15]+0x49b40821, 22); ++ ++ MD5STEP(F2, a, b, c, d, (long)in[ 1]+0xf61e2562, 5); ++ MD5STEP(F2, d, a, b, c, (long)in[ 6]+0xc040b340, 9); ++ MD5STEP(F2, c, d, a, b, (long)in[11]+0x265e5a51, 14); ++ MD5STEP(F2, b, c, d, a, (long)in[ 0]+0xe9b6c7aa, 20); ++ MD5STEP(F2, a, b, c, d, (long)in[ 5]+0xd62f105d, 5); ++ MD5STEP(F2, d, a, b, c, (long)in[10]+0x02441453, 9); ++ MD5STEP(F2, c, d, a, b, (long)in[15]+0xd8a1e681, 14); ++ MD5STEP(F2, b, c, d, a, (long)in[ 4]+0xe7d3fbc8, 20); ++ MD5STEP(F2, a, b, c, d, (long)in[ 9]+0x21e1cde6, 5); ++ MD5STEP(F2, d, a, b, c, (long)in[14]+0xc33707d6, 9); ++ MD5STEP(F2, c, d, a, b, (long)in[ 3]+0xf4d50d87, 14); ++ MD5STEP(F2, b, c, d, a, (long)in[ 8]+0x455a14ed, 20); ++ MD5STEP(F2, a, b, c, d, (long)in[13]+0xa9e3e905, 5); ++ MD5STEP(F2, d, a, b, c, (long)in[ 2]+0xfcefa3f8, 9); ++ MD5STEP(F2, c, d, a, b, (long)in[ 7]+0x676f02d9, 14); ++ MD5STEP(F2, b, c, d, a, (long)in[12]+0x8d2a4c8a, 20); ++ ++ MD5STEP(F3, a, b, c, d, (long)in[ 5]+0xfffa3942, 4); ++ MD5STEP(F3, d, a, b, c, (long)in[ 8]+0x8771f681, 11); ++ MD5STEP(F3, c, d, a, b, (long)in[11]+0x6d9d6122, 16); ++ MD5STEP(F3, b, c, d, a, (long)in[14]+0xfde5380c, 23); ++ MD5STEP(F3, a, b, c, d, (long)in[ 1]+0xa4beea44, 4); ++ MD5STEP(F3, d, a, b, c, (long)in[ 4]+0x4bdecfa9, 11); ++ MD5STEP(F3, c, d, a, b, (long)in[ 7]+0xf6bb4b60, 16); ++ MD5STEP(F3, b, c, d, a, (long)in[10]+0xbebfbc70, 23); ++ MD5STEP(F3, a, b, c, d, (long)in[13]+0x289b7ec6, 4); ++ MD5STEP(F3, d, a, b, c, (long)in[ 0]+0xeaa127fa, 11); ++ MD5STEP(F3, c, d, a, b, (long)in[ 3]+0xd4ef3085, 16); ++ MD5STEP(F3, b, c, d, a, (long)in[ 6]+0x04881d05, 23); ++ MD5STEP(F3, a, b, c, d, (long)in[ 9]+0xd9d4d039, 4); ++ MD5STEP(F3, d, a, b, c, (long)in[12]+0xe6db99e5, 11); ++ MD5STEP(F3, c, d, a, b, (long)in[15]+0x1fa27cf8, 16); ++ MD5STEP(F3, b, c, d, a, (long)in[ 2]+0xc4ac5665, 23); ++ ++ MD5STEP(F4, a, b, c, d, (long)in[ 0]+0xf4292244, 6); ++ MD5STEP(F4, d, a, b, c, (long)in[ 7]+0x432aff97, 10); ++ MD5STEP(F4, c, d, a, b, (long)in[14]+0xab9423a7, 15); ++ MD5STEP(F4, b, c, d, a, (long)in[ 5]+0xfc93a039, 21); ++ MD5STEP(F4, a, b, c, d, (long)in[12]+0x655b59c3, 6); ++ MD5STEP(F4, d, a, b, c, (long)in[ 3]+0x8f0ccc92, 10); ++ MD5STEP(F4, c, d, a, b, (long)in[10]+0xffeff47d, 15); ++ MD5STEP(F4, b, c, d, a, (long)in[ 1]+0x85845dd1, 21); ++ MD5STEP(F4, a, b, c, d, (long)in[ 8]+0x6fa87e4f, 6); ++ MD5STEP(F4, d, a, b, c, (long)in[15]+0xfe2ce6e0, 10); ++ MD5STEP(F4, c, d, a, b, (long)in[ 6]+0xa3014314, 15); ++ MD5STEP(F4, b, c, d, a, (long)in[13]+0x4e0811a1, 21); ++ MD5STEP(F4, a, b, c, d, (long)in[ 4]+0xf7537e82, 6); ++ MD5STEP(F4, d, a, b, c, (long)in[11]+0xbd3af235, 10); ++ MD5STEP(F4, c, d, a, b, (long)in[ 2]+0x2ad7d2bb, 15); ++ MD5STEP(F4, b, c, d, a, (long)in[ 9]+0xeb86d391, 21); ++ ++ /* ++ * we have 4 unsigned longs generated by the above sequence; this scrambles ++ * them together so that if there is any pattern, it will be obscured. ++ */ ++ return (a ^ b ^ c ^ d); ++} ++ ++#endif +diff -urN irc-cvs/ircd/s_debug.c irc-cvs-nospoof/ircd/s_debug.c +--- irc-cvs/ircd/s_debug.c Fri Feb 5 10:44:16 1999 ++++ irc-cvs-nospoof/ircd/s_debug.c Tue Mar 16 12:45:56 1999 +@@ -148,6 +148,9 @@ + #ifdef INET6 + '6', + #endif ++#if defined(NOSPOOF) ++'*', ++#endif + '\0'}; + + #ifdef DEBUGMODE +@@ -344,7 +347,7 @@ + sendto_one(cptr, ":%s %d %s :BS:%d MXR:%d MXB:%d MXBL:%d PY:%d", + ME, RPL_STATSDEFINE, nick, BUFSIZE, MAXRECIPIENTS, MAXBANS, + MAXBANLENGTH, MAXPENALTY); +- sendto_one(cptr, ":%s %d %s :ZL:%d CM:%d CP:%d", ++ sendto_one(cptr, ":%s %d %s :ZL:%d CM:%d CP:%d NS:%s", + ME, RPL_STATSDEFINE, nick, + #ifdef ZIP_LINKS + ZIP_LEVEL, +@@ -352,9 +355,14 @@ + -1, + #endif + #ifdef CLONE_CHECK +- CLONE_MAX, CLONE_PERIOD ++ CLONE_MAX, CLONE_PERIOD, ++#else ++ -1, -1, ++#endif ++#if defined(NOSPOOF) ++ "yes" + #else +- -1, -1 ++ "no" + #endif + ); + } +diff -urN irc-cvs/ircd/s_err.c irc-cvs-nospoof/ircd/s_err.c +--- irc-cvs/ircd/s_err.c Sun Feb 28 02:45:29 1999 ++++ irc-cvs-nospoof/ircd/s_err.c Tue Mar 16 12:45:56 1999 +@@ -162,6 +162,19 @@ + { 0, (char *)NULL }, + /* 501 */ { ERR_UMODEUNKNOWNFLAG, ":Unknown MODE flag" }, + /* 502 */ { ERR_USERSDONTMATCH, ":Can't change mode for other users" }, ++#if defined(NOSPOOF) ++ { 0, (char *)NULL }, ++ { 0, (char *)NULL }, ++ { 0, (char *)NULL }, ++ { 0, (char *)NULL }, ++ { 0, (char *)NULL }, ++ { 0, (char *)NULL }, ++ { 0, (char *)NULL }, ++ { 0, (char *)NULL }, ++ { 0, (char *)NULL }, ++ { 0, (char *)NULL }, ++/* 513 */ { ERR_BADPING, (char *)NULL }, ++#endif + { 0, (char *)NULL } + }; + +diff -urN irc-cvs/ircd/s_user.c irc-cvs-nospoof/ircd/s_user.c +--- irc-cvs/ircd/s_user.c Tue Mar 16 12:32:51 1999 ++++ irc-cvs-nospoof/ircd/s_user.c Tue Mar 16 12:51:41 1999 +@@ -335,9 +335,9 @@ + + /* + ** register_user +-** This function is called when both NICK and USER messages +-** have been accepted for the client, in whatever order. Only +-** after this the USER message is propagated. ++** This function is called when both NICK and USER [and maybe PONG] ++** messages have been accepted for the client, in whatever order. ++** Only after this the USER message is propagated. + ** + ** NICK's must be propagated at once when received, although + ** it would be better to delay them too until full info is +@@ -1007,9 +1007,30 @@ + + /* This had to be copied here to avoid problems.. */ + (void)strcpy(sptr->name, nick); ++#if defined(NOSPOOF) ++ /* If the client hasn't gotten a cookie-ping yet, ++ choose a cookie and send it. -record!jegelhof@cloud9.net */ ++ ++ if (!sptr->cookie) ++ { ++ while((!sptr->cookie) || (sptr->cookie==-1)) ++ sptr->cookie=(ircrandom()); ++ sendto_one(cptr, "PING :%lu", sptr->cookie); ++ sendto_one(sptr, ++ ":%s %d %s :If your client freezes here, type /QUOTE PONG %lu " ++ "or /PONG %lu ", ++ me.name, ERR_BADPING, sptr->name, ++ sptr->cookie, sptr->cookie); ++ } ++ ++ if ((sptr->user) && (sptr->cookie==-1)) ++ { ++#else + if (sptr->user) ++#endif + /* +- ** USER already received, now we have NICK. ++ ** USER [and possibly PONG] already received, ++ ** now we have NICK. + ** *NOTE* For servers "NICK" *must* precede the + ** user message (giving USER before NICK is possible + ** only for local client connection!). register_user +@@ -1020,6 +1041,9 @@ + sptr->user->username) + == FLUSH_BUFFER) + return FLUSH_BUFFER; ++#if defined(NOSPOOF) ++ } ++#endif + } + /* + ** Finally set new nick name. +@@ -1849,7 +1873,12 @@ + if (strlen(realname) > REALLEN) + realname[REALLEN] = '\0'; + sptr->info = mystrdup(realname); +- if (sptr->name[0]) /* NICK already received, now we have USER... */ ++ if ((sptr->name[0]) ++#if defined(NOSPOOF) ++ && (!MyConnect(sptr) || (sptr->cookie==-1)) ++#endif ++ ) ++ /* NICK already received, now we have USER... */ + { + if ((parc == 6) && IsServer(cptr)) /* internal m_user() */ + { +@@ -2222,7 +2251,32 @@ + aClient *acptr; + char *origin, *destination; + +- if (parc < 2 || *parv[1] == '\0') ++#if defined(NOSPOOF) ++ /* Check to see if this is a PONG :cookie reply from an ++ unregistered user. If so, process it. -record */ ++ ++ if((!IsRegistered(sptr)) && (sptr->cookie!=0) && ++ (sptr->cookie!=-1) && (parc>1)) ++ { ++ if(strtoul(parv[parc-1],NULL,10)==sptr->cookie) ++ { ++ sptr->cookie=-1; ++ if((sptr->user) && (sptr->name[0])) ++ /* NICK and USER OK */ ++ return register_user(cptr, sptr, sptr->name, ++ sptr->user->username); ++ } ++ else ++ sendto_one(sptr, ++ ":%s %d %s :To connect, type /QUOTE PONG %lu or /PONG %lu", ++ me.name, ERR_BADPING, sptr->name, ++ sptr->cookie, sptr->cookie); ++ ++ return 1; ++ } ++#endif ++ ++ if (parc < 2 || *parv[1] == '\0') + { + sendto_one(sptr, err_str(ERR_NOORIGIN, parv[0])); + return 1; +diff -urN irc-cvs/support/Makefile.in irc-cvs-nospoof/support/Makefile.in +--- irc-cvs/support/Makefile.in Fri Mar 12 20:06:00 1999 ++++ irc-cvs-nospoof/support/Makefile.in Tue Mar 16 12:47:37 1999 +@@ -153,7 +153,7 @@ + SERVER_OBJS = channel.o class.o hash.o ircd.o list.o res.o s_auth.o \ + s_bsd.o s_conf.o s_debug.o s_err.o s_id.o s_misc.o s_numeric.o \ + s_serv.o s_service.o s_user.o s_zip.o whowas.o \ +- res_init.o res_comp.o res_mkquery.o ++ res_init.o res_comp.o res_mkquery.o random.o + + IAUTH_COMMON_OBJS = clsupport.o clmatch.o # This is a little evil + IAUTH_OBJS = iauth.o a_conf.o a_io.o a_log.o \ +@@ -431,6 +431,9 @@ + + res_mkquery.o: ../ircd/res_mkquery.c setup.h config.h + $(CC) $(S_CFLAGS) -c -o $@ ../ircd/res_mkquery.c ++ ++random.o: ../ircd/random.c setup.h config.h ++ $(CC) $(S_CFLAGS) -c -o $@ ../ircd/random.c + + iauth.o: ../iauth/iauth.c config.h setup.h + $(CC) $(A_CFLAGS) -c -o $@ ../iauth/iauth.c +diff -urN irc-cvs/support/config.h.dist irc-cvs-nospoof/support/config.h.dist +--- irc-cvs/support/config.h.dist Mon Feb 22 10:41:32 1999 ++++ irc-cvs-nospoof/support/config.h.dist Tue Mar 16 12:45:57 1999 +@@ -374,6 +374,30 @@ + */ + #undef CLONE_CHECK + ++/* Define this to turn on code that enables a PING/PONG cookies sequence ++ * whenever a client connects. The purpose of this is to prevent IP ++ * spoofing (normally based on predicting TCP/IP sequence numbers). ++ * This breaks the RFC slightly, but so far only one (old) client has ++ * been encountered that breaks. There's a small overhead if you define ++ * it, but it's essential for older BSD-based (or any other) TCP/IP ++ * stacks with predictable sequence numbers. ++ */ ++ ++#undef NOSPOOF ++ ++/* Random number generator seed -- used for cookies if NOSPOOF is ++ * defined. ++ * ++ * Set this to an 8 character random text string. ++ * Do _NOT_ use the default text. ++ * If people are able to defeat the IP-spoofing protection on your ++ * server, please consider changing this value and recompiling. ++ */ ++ ++#if defined(NOSPOOF) ++#define RANDOM_SEED "ChangeMe" ++#endif ++ + /* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */ + /* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */ + /* STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP STOP */ diff --git a/contrib/ircdwatch/README b/contrib/ircdwatch/README new file mode 100644 index 0000000..80653bd --- /dev/null +++ b/contrib/ircdwatch/README @@ -0,0 +1,56 @@ +$Id: README,v 1.5 1998/11/09 22:56:34 borud Exp $ + +DESCRIPTION +=========== + ircdwatch is a daemon that regularly checks to see if ircd is running. + if ircd should die or somehow stop running, ircdwatch will respawn the + ircd daemon. if desirable, ircdwatch can be configured to check if + the ircd configuration file is changed and send a SIGHUP to the ircd + daemon which then causes the daemon to reload the configuration + file. + + the ircdwatch program itself is also used as sort of a remote + control depending on what command line arguments you feed it. you + can use it to start ircd and stop ircd and ircdwatch. + +OPTIONS +======= + if you invoke ircdwatch without any command line arguments it will + either daemonize itself and become a daemon, or it will exit if it + detects that an ircdwatch daemon is already running. + + for using the ircdwatch program as a remote control the following + command line options are available: + + --kill + stop both ircdwatch and ircd + + --rest + stop ircdwatch but leave ircd running + + --help + list command line arguments + + +COMPILE TIME CONFIGURATION +========================== + you configure ircdwatch by editing config.h in the directory where + you build ircd. the configuration parameters available for + ircdwatch are those starting with the prefix "IRCDWATCH_". please + refer to the config.h file for more information on the parameter + settings. most of the defaults should be okay if you want to use + ircdwatch though. + + +ADMINISTRATIVIA +=============== + ircdwatch was written by Bjorn Borud and is + Copyright (C) 1998 Bjorn Borud + + the program is released under the GNU General Public License + + the current maintainer can be reached at: + + please report bugs to + improvements are welcome. + diff --git a/contrib/ircdwatch/ircdwatch.8 b/contrib/ircdwatch/ircdwatch.8 new file mode 100644 index 0000000..cc944b1 --- /dev/null +++ b/contrib/ircdwatch/ircdwatch.8 @@ -0,0 +1,50 @@ +.\" @(#)$Id: ircdwatch.8,v 1.1 1998/06/12 22:57:40 kalt Exp $ +.TH IRCDWATCH 8 "$Date: 1998/06/12 22:57:40 $" +.SH NAME +ircdwatch \- Daemon for monitoring ircd and ircd.conf +.SH SYNOPSIS +.hy 0 +.IP \fBircdwatch\fP +[ +.BI \-\-kill +] [ +.BI \-\-rest +] [ +.BI \-\-help +] +.SH DESCRIPTION +.LP +\fIircdwatch\fP is a daemon that periodically checks that the +\fIircd\fP daemon is running, restarting it of necessary. This +daemon can also be configured (at compile time) to check for +changes to the \fIircd\fP configuration file and make \fIircd\fP +reload its configuration file by sending it a SIGHUP signal. +.LP +Given command line arguments \fIircdwatch\fP will serve as a remote +control for stopping both \fIircdwatch\fP and \fIircd\fP or just +\fIircdwatch\fP. + +.SH OPTIONS +.TP +.B \-\-kill +Stop both \fIircd\fP and \fIircdwatch\fP +.TP +.B \-\-rest +Stop \fIircdwatch\fP but leave \fIircd\fP running +.TP +.B \-\-help +List command line arguments +.SH COPYRIGHT +Copyright (C) 1998 Bjorn Borud, +.LP +.RE +.SH FILES + "ircd.conf" + "ircd.pid" + "ircdwatch.pid" +.SH "SEE ALSO" +ircd(8) +.SH BUGS +There may be some portability issues. Report bugs to +.SH AUTHOR +Bjorn Borud, diff --git a/contrib/ircdwatch/ircdwatch.c b/contrib/ircdwatch/ircdwatch.c new file mode 100644 index 0000000..c384578 --- /dev/null +++ b/contrib/ircdwatch/ircdwatch.c @@ -0,0 +1,499 @@ +/* + * Copyright (C) 1998 Bjorn Borud + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: ircdwatch.c,v 1.3 1999/02/21 00:33:44 kalt Exp $"; +#endif + +#include +#include /* atol() */ +#include /* fork() exec() */ +#include +#include /* stat() */ +#include +#include +#include /* strncmp() */ +#include + +#include "os.h" +#include "config.h" + +/* + * Try and find the correct name to use with getrlimit() for setting + * the max. number of files allowed to be open by this process. + * (borrowed from ircd/s_bsd.c) + */ +#ifdef RLIMIT_FDMAX +# define RLIMIT_FD_MAX RLIMIT_FDMAX +#else +# ifdef RLIMIT_NOFILE +# define RLIMIT_FD_MAX RLIMIT_NOFILE +# else +# ifdef RLIMIT_OPEN_MAX +# define RLIMIT_FD_MAX RLIMIT_OPEN_MAX +# else +# undef RLIMIT_FD_MAX +# endif +# endif +#endif + +#define PID_LEN 7 /* overkill, but hey */ +#define MAX_OPEN_FILEDESCRIPTORS_WILD_GUESS 256 + +static int want_to_quit = 0; + +void finalize(int i) +{ +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_NOTICE, "ircdwatch daemon exiting"); + closelog(); +#endif + exit(i); +} + +int daemonize(void) +{ + pid_t pid; + int i; + int open_max; + +#ifdef RLIMIT_FD_MAX + struct rlimit rlim; + + if (getrlimit(RLIMIT_FD_MAX, &rlim) != 0) { + perror("getrlimit"); + finalize(1); + } + + /* if we get a lame answer we just take a wild guess */ + if (rlim.rlim_max == 0) { + open_max = MAX_OPEN_FILEDESCRIPTORS_WILD_GUESS; + } + + open_max = rlim.rlim_max; + +#else + + /* no RLIMIT_FD_MAX? take a wild guess */ + open_max = MAX_OPEN_FILEDESCRIPTORS_WILD_GUESS; + +#endif + + pid = fork(); + if (pid < 0) { + perror("fork"); + exit(1); + } + + /* parent process dies */ + if (pid != 0) { + exit(0); + } + + setsid(); + umask(0); + + /* close file descriptors */ + for (i=0; i < open_max; i++) { + close(i); + } + + return(0); +} + +static void sig_handler (int signo) +{ + if (signo == SIGHUP) { + want_to_quit = 1; + return; + } + + if (signo == SIGALRM) { + +#ifndef POSIX_SIGNALS + (void)signal(SIGALRM, &sig_handler); +#endif; + + return; + } +} + + +void set_up_signals(void) +{ +#ifdef POSIX_SIGNALS + struct sigaction act; + + act.sa_handler = sig_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = 0; + + if (sigaction(SIGHUP, &act, NULL) < 0) { + perror("sigaction"); + } + + if (sigaction(SIGALRM, &act, NULL) < 0) { + perror("sigaction"); + } +#else + (void)signal(SIGHUP, &sig_handler); + (void)signal(SIGALRM, &sig_handler); +#endif + + /* ignore it if child processes die */ + signal(SIGCHLD, SIG_IGN); +} + +int write_my_pid(void) +{ + FILE *f; + + f = fopen(IRCDWATCH_PID_FILENAME, "w"); + if (f == NULL) { + return(-1); + } + + fprintf(f, "%d\n", getpid()); + fclose(f); + + return(0); +} + + +int file_modified(char *s) +{ + struct stat st; + + if (stat(s, &st) < 0) { + return(-1); + } + return(st.st_ctime); +} + + +int spawn (char *cmd) +{ + pid_t pid; + + pid = fork(); + + if (pid == -1) { +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "spawn() unable to fork, errno=%d", errno); +#endif + return(-1); + } + + if (pid == 0) { + execl("/bin/sh", "sh", "-c", cmd, (char *) NULL); + _exit(127); + } + return(0); +} + +int read_pid(char *pid_filename) +{ + FILE *f; + char pidbuf[PID_LEN]; + pid_t pid; + + f = fopen(pid_filename, "r"); + if (f == NULL) { +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "unable to fopen() %s: %s", pid_filename, strerror(errno)); +#endif + return(-1); + } + + if (fgets(pidbuf, PID_LEN, f) != NULL) { + pid = atol(pidbuf); + } else { +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "fgets() %s: %s", pid_filename, strerror(errno)); +#endif + fclose(f); + return(-1); + } + + fclose(f); + return(pid); +} + +int file_exists (char *s) +{ + struct stat st; + if ((stat(s, &st) < 0) && (errno == ENOENT)) { + return(0); + } + return(1); +} + +/* yeah, I'll get around to these in some later version */ + +int file_readable (char *s) +{ + return(access(s, R_OK) == 0); +} + +int file_writable (char *s) +{ + return(access(s, W_OK) == 0); +} + +int file_executable (char *s) +{ + int rc; + rc = (access(IRCD_PATH, X_OK) == 0); + return rc; +} + +int verify_pid(int pid) +{ + int res; + + res = kill(pid, 0); + if (res < 0 && errno == EPERM) { + fprintf(stderr, "Not process owner\n"); + exit(1); + } + + return(res == 0); +} + +int ircdwatch_running () { + int pid; + + if (file_exists(IRCDWATCH_PID_FILENAME)) { + pid = read_pid(IRCDWATCH_PID_FILENAME); + if (pid > 0) { + return(verify_pid(pid) == 1); + } else { + return(-1); + } + } + return(0); +} + +int ircd_running () { + int pid; + + if (file_exists(IRCDPID_PATH)) { + pid = read_pid(IRCDPID_PATH); + if (pid > 0) { + return(verify_pid(pid) == 1); + } else { + return(-1); + } + } + return(0); +} + +void hup_ircd () +{ + int pid; + int res; + + if (file_exists(IRCDPID_PATH)) { + pid = read_pid(IRCDPID_PATH); + if (pid > 0) { + res = kill(pid, SIGHUP); + if (res < 0 && errno == EPERM) { +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "not allowed to send SIGHUP to ircd"); +#endif + finalize(1); + } + } + } +} + + +void daemon_run () +{ + int i; + int last_config_time = 0; + + /* is ircdwatch already running? */ + i = ircdwatch_running(); + if (i == -1) { + /* unable to open pid file. wrong user? */ + fprintf(stderr, "ircdwatch pid file exists but is unreadable\n"); + exit(1); + } else if (i) { + fprintf(stderr, "ircdwatch is already running\n"); + exit(0); + } + + /* is ircd running? */ + i = ircd_running(); + if (i == -1) { + /* unable to open pid file. wrong user? */ + fprintf(stderr, "ircdwatch pid file exists but is unreadable\n"); + exit(1); + } else if (!i) { + fprintf(stderr, "ircd not running. attempting to start ircd...\n"); + if (file_exists(IRCD_PATH)) { + if (file_executable(IRCD_PATH)) { + spawn(IRCD_PATH); + } else { + fprintf(stderr, "%s not executable\n", IRCD_PATH); + exit(1); + } + } else { + fprintf(stderr, "%s does not exist\n", IRCD_PATH); + exit(1); + } + } + + set_up_signals(); + closelog(); + /* daemonize(); */ + +#ifdef IRCDWATCH_USE_SYSLOG + openlog(IRCDWATCH_SYSLOG_IDENT, + IRCDWATCH_SYSLOG_OPTIONS, + IRCDWATCH_SYSLOG_FACILITY); + + syslog(LOG_NOTICE, "starting ircdwatch daemon"); +#endif + + alarm(IRCDWATCH_POLLING_INTERVAL); + pause(); + + while (!want_to_quit) { + if (! ircd_running() ) { + +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_ERR, "spawning %s", IRCD_PATH); +#endif + + spawn(IRCD_PATH); + } + +#ifdef IRCDWATCH_HUP_ON_CONFIG_CHANGE + i = file_modified(IRCDCONF_PATH); + if (i != -1) { + + if (last_config_time == 0) { + last_config_time = i; + } + + else if (i > last_config_time) { + last_config_time = i; + hup_ircd(); + +#ifdef IRCDWATCH_USE_SYSLOG + syslog(LOG_NOTICE, "config change, HUPing ircd"); +#endif + + } + } +#endif + + alarm(IRCDWATCH_POLLING_INTERVAL); + pause(); + } + return; +} + +void kill_ircd () +{ + int pid; + int res; + + if (file_exists(IRCDPID_PATH)) { + pid = read_pid(IRCDPID_PATH); + if (pid > 0) { + res = kill(pid, SIGTERM); + if (res < 0) { + perror("ircd kill"); + finalize(1); + } else { + fprintf(stderr, "killed ircd\n"); + } + } + } else { + fprintf(stderr, "File %s does not exist\n", IRCDPID_PATH); + } +} + +void kill_ircdwatch () +{ + int pid; + int res; + + if (file_exists(IRCDWATCH_PID_FILENAME)) { + pid = read_pid(IRCDWATCH_PID_FILENAME); + if (pid > 0) { + res = kill(pid, SIGHUP); + if (res < 0) { + perror("ircdwatch kill"); + finalize(1); + } else { + fprintf(stderr, "Sent HUP to ircdwatch. it will die soon...\n"); + } + } + } else { + fprintf(stderr, "File %s does not exist\n", IRCDWATCH_PID_FILENAME); + } +} + + +void usage (void) +{ + fprintf(stderr,"\n\ +Usage:\n\ + ircdwatch [--kill | --rest | --help]\n\ +\n\ + --kill, stop both ircdwatch and ircd\n\ + --rest, stop ircdwatch but let ircd alone\n\ + --help, display this text\n\ +\n\ +%s\n", rcsid); +} + +int +main (int argc, char **argv) { + int i; + +#ifdef IRCDWATCH_USE_SYSLOG + openlog(IRCDWATCH_SYSLOG_IDENT, + IRCDWATCH_SYSLOG_OPTIONS, + IRCDWATCH_SYSLOG_FACILITY); +#endif + + if (argc > 1) { + if (strncmp(argv[1], "--rest", 6) == 0) { + kill_ircdwatch(); + exit(0); + } + + if (strncmp(argv[1], "--kill", 6) == 0) { + kill_ircdwatch(); + kill_ircd(); + exit(0); + } + + usage(); + exit(0); + } + + daemon_run(); + finalize(0); +} diff --git a/contrib/mkpasswd/README b/contrib/mkpasswd/README new file mode 100644 index 0000000..a2bb420 --- /dev/null +++ b/contrib/mkpasswd/README @@ -0,0 +1,64 @@ +/************************************************************************ + * IRC - Internet Relay Chat, ircd/crypt/README + * Copyright (C) 1991 Nelson Minar + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * $Id: README,v 1.1 1998/04/07 21:20:59 kalt Exp $ + * + */ + +The change implemented here is that the operator password in irc.conf +is no longer stored in plaintext form, but is encrypted the same way +that user passwords are encrypted on normal UNIX systems. Ie, instead +of having + + O:*:goodboy:Nelson + +in your ircd.conf file, you have + + O:*:sCnvYRmbFJ7oI:Nelson + +You still type "/oper Nelson goodboy" to become operator. However, if +someone gets ahold of your irc.conf file, they can no longer figure +out what the password is from reading it. There are still other +security holes, namely server-server passwords, but this closes one +obvious problem. + +So how do you generate these icky looking strings for passwords? +There's a simple program called mkpasswd to do that for you. Just run +mkpasswd, and at the prompt type in your plaintext password. It will +spit out the encrypted password, which you should then just copy into +the irc.conf file. This should be done only when adding new passwords +to your irc.conf file. To change over your irc.conf file to use +encrypted passwords, define CRYPT_OPER_PASSWORD in config.h. You will +need to recompile your server if you already compiled it with this +feature disabled. Once compiled, edit the Makefile in this directory +and chang "IRCDCONF" to your irc.conf file. Then "make install" in this +directory to replace all the operator passwords in your irc.conf file +with the encrypted format. + +Choose your passwords carefully. Do not choose something in a +dictionary, make sure its at least 5 characters. Anything past 8 +characters is ignored. + +One thing to note about crypt() passwords - for every plaintext, there +are 4096 different passwords. Some valid encryptions of "goodboy" +include t1Ub2RhRQHd4g sCnvYRmbFJ7oI and Xr4Z.Kg5tcdy6. The first +two characters (the "salt") determine which of the 4096 passwords +you will get. mkpasswd chooses the salt randomly, or alternately +will let you specify one on the command line. + +see also - crypt(3) diff --git a/contrib/mkpasswd/crypter b/contrib/mkpasswd/crypter new file mode 100755 index 0000000..4851620 --- /dev/null +++ b/contrib/mkpasswd/crypter @@ -0,0 +1,55 @@ +#!/usr/local/bin/perl +#************************************************************************ +#* IRC - Internet Relay Chat, ircd/crypt/crypter +#* Copyright (C) 1991 Sean Batt +#* +#* This program is free software; you can redistribute it and/or modify +#* it under the terms of the GNU General Public License as published by +#* the Free Software Foundation; either version 1, or (at your option) +#* any later version. +#* +#* This program is distributed in the hope that it will be useful, +#* but WITHOUT ANY WARRANTY; without even the implied warranty of +#* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +#* GNU General Public License for more details. +#* +#* You should have received a copy of the GNU General Public License +#* along with this program; if not, write to the Free Software +#* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +#* +#* $Id: crypter,v 1.1 1998/04/07 21:21:00 kalt Exp $ +#* +#*/ + +#From Sean Batt sean@coombs.anu.edu.au +# +#Temporary output file +# +$tmpfile = "/tmp/ircd.conf.tmp"; + +# +#Original ircd.conf file +# +$ircdconf = @ARGV[0]; + +print "crypting ",$ircdconf,"\n"; +@saltset = ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '.', '/'); + +umask(0077); +open ($ircdout, ">/tmp/ircd.conf.tmp") || die "open $!"; + +while ($text = <>) { +#if its not an "O" line we can ignore it + $text =~ /^o/i || print ($ircdout $text) && next; + chop($text); + @oline = split(':', $text); + $salt = $saltset[rand(time)%64].$saltset[(rand(time)>>6)%64]; + $oline[2] = crypt(@oline[2], $salt); + print ($ircdout join(':',@oline)."\n"); +} +close ($ircdout); +close ($ircdin); +print "/bin/cp ",$tmpfile," ",$ircdconf,"\n"; +(fork()==0) ? exec("/bin/cp", $tmpfile, $ircdconf) : wait; + +#unlink($tmpfile); diff --git a/contrib/mkpasswd/mkpasswd.c b/contrib/mkpasswd/mkpasswd.c new file mode 100644 index 0000000..8ea8413 --- /dev/null +++ b/contrib/mkpasswd/mkpasswd.c @@ -0,0 +1,44 @@ +/* simple password generator by Nelson Minar (minar@reed.edu) + * copyright 1991, all rights reserved. + * You can use this code as long as my name stays with it. + */ + +#include +#include +#include + +#ifndef lint +static char rcsid[] = "@(#)$Id: mkpasswd.c,v 1.1 1998/04/07 21:21:00 kalt Exp $"; +#endif + +extern char *getpass(); + +int main(argc, argv) +int argc; +char *argv[]; +{ + static char saltChars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"; + char salt[3]; + char * plaintext; + int i; + + if (argc < 2) { + srandom(time(0)); /* may not be the BEST salt, but its close */ + salt[0] = saltChars[random() % 64]; + salt[1] = saltChars[random() % 64]; + salt[2] = 0; + } + else { + salt[0] = argv[1][0]; + salt[1] = argv[1][1]; + salt[2] = '\0'; + if ((strchr(saltChars, salt[0]) == NULL) || (strchr(saltChars, salt[1]) == NULL)) + fprintf(stderr, "illegal salt %s\n", salt), exit(1); + } + + plaintext = getpass("plaintext: "); + + printf("%s\n", crypt(plaintext, salt)); + return 0; +} + diff --git a/contrib/mod_passwd/README b/contrib/mod_passwd/README new file mode 100644 index 0000000..6aa2352 --- /dev/null +++ b/contrib/mod_passwd/README @@ -0,0 +1,30 @@ +$Id: README,v 1.1 1999/03/13 23:06:15 kalt Exp $ + +This is an example module for the authentication program (iauth) used by +the IRC server. + +* This module demonstrates how a module can access and use the PASS and + USER information provided by users. It is *NOT* a finished product. In + particular, the actual password validation is not implemented. + +* This module also demonstrates how a DSM module should be written. You'll + note that it is completely identical to ordinary modules, except for one + extra function: "passwd_load()" + +To be used, this module needs to be compiled from the normal compilation +directory. It should be linked as a dynamic library. Methods vary +depending on the compiler and platform. + +$ gcc -c -g -I../iauth -I../common -I. ../contrib/mod_passwd/mod_passwd.c +$ ld -Bshareable mod_passwd.o -o mod_passwd.so +$ ls -l mod_passwd.so +-rwxr--r-- 1 kalt staff 26932 Mar 13 17:59 mod_passwd.so +$ + +To be used by iauth, add the following lines to the iauth.conf file: + + extinfo + shared passwd /path/to/mod_passwd.so + module passwd + +See iauth.conf(5) for more information on configuring iauth. diff --git a/contrib/mod_passwd/mod_passwd.c b/contrib/mod_passwd/mod_passwd.c new file mode 100644 index 0000000..817a722 --- /dev/null +++ b/contrib/mod_passwd/mod_passwd.c @@ -0,0 +1,171 @@ +/************************************************************************ + * IRC - Internet Relay Chat, mod_passwd.c + * Copyright (C) 1999 Christophe Kalt + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 1, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef lint +static char rcsid[] = "@(#)$Id: mod_passwd.c,v 1.1 1999/03/13 23:06:15 kalt Exp $"; +#endif + +#include "os.h" +#include "a_defines.h" +#include "a_externs.h" + +/* + * passwd_init + * + * This procedure is called when a particular module is loaded. + * Returns NULL if everything went fine, + * an error message otherwise. + */ +char * +passwd_init(self) +AnInstance *self; +{ + return NULL; +} + +/* + * passwd_release + * + * This procedure is called when a particular module is unloaded. + */ +void +passwd_release(self) +AnInstance *self; +{ +} + +/* + * passwd_stats + * + * This procedure is called regularly to update statistics sent to ircd. + */ +void +passwd_stats(self) +AnInstance *self; +{ +} + +/* + * passwd_start + * + * This procedure is called to start an authentication. + * Returns 0 if everything went fine, + * +1 if still waiting for some data (username, password).. + * -1 otherwise (nothing to be done, or failure) + * + * It is responsible for sending error messages where appropriate. + * In case of failure, it's responsible for cleaning up (e.g. passwd_clean + * will NOT be called) + */ +int +passwd_start(cl) +u_int cl; +{ + if (cldata[cl].authuser && + cldata[cl].authfrom < cldata[cl].instance->in) + { + /* + ** another instance preceding this one in the configuration + ** has already authenticated the user, no need to bother + ** doing anything here then. (the other takes precedence) + */ + return -1; + } + if ((cldata[cl].state & A_GOTU) == 0) + /* haven't received username/password pair from ircd yet */ + return 1; + if ((cldata[cl].state & A_GOTP) == 0) + { + /* no password to check -> reject user! */ + cldata[cl].state |= A_DENY; + sendto_ircd("K %d %s %u ", cl, cldata[cl].itsip, + cldata[cl].itsport); + return -1; /* done */ + } + /* + ** + ** + ** INSERT FUNCTION TO CHECK PASSWORD VALIDITY + ** + ** + */ + /* if failure, see above */ + /* if success: */ + cldata[cl].state |= A_UNIX; + if (cldata[cl].authuser) + free(cldata[cl].authuser); + cldata[cl].authuser = mystrdup(cldata[cl].user); + cldata[cl].authfrom = cldata[cl].instance->in; + sendto_ircd("U %d %s %u %s", cl, cldata[cl].itsip, cldata[cl].itsport, + cldata[cl].authuser); + return -1; /* done */ +} + +/* + * passwd_work + * + * This procedure is called whenever there's new data in the buffer. + * Returns 0 if everything went fine, and there is more work to be done, + * Returns -1 if the module has finished its work (and cleaned up). + * + * It is responsible for sending error messages where appropriate. + */ +int +passwd_work(cl) +u_int cl; +{ + return -1; +} + +/* + * passwd_clean + * + * This procedure is called whenever the module should interrupt its work. + * It is responsible for cleaning up any allocated data, and in particular + * closing file descriptors. + */ +void +passwd_clean(cl) +u_int cl; +{ +} + +/* + * passwd_timeout + * + * This procedure is called whenever the timeout set by the module is + * reached. + * + * Returns 0 if things are okay, -1 if authentication was aborted. + */ +int +passwd_timeout(cl) +u_int cl; +{ +} + +static aModule Module_passwd = + { "passwd", passwd_init, passwd_release, passwd_stats, + passwd_start, passwd_work, passwd_timeout, passwd_clean }; + +aModule * +passwd_load() +{ + return &Module_passwd; +} diff --git a/contrib/tkserv/CHANGES b/contrib/tkserv/CHANGES new file mode 100644 index 0000000..e983ded --- /dev/null +++ b/contrib/tkserv/CHANGES @@ -0,0 +1,37 @@ +1.0.0b8 : Ported TkServ to C. +1.0.0b8 : It is now possible to QUIT the service via SQUERY. +1.0.0b9 : Added default expiration if no time value was specified (koopal) +1.0.0b9 : It is now possible to remove existing tklines "manually" (koopal) +1.0.0b10: the pwd of the service went to the cmd line (koopal) +1.0.0 : Official release of TkServ +1.0.1 : Applied some fixes to make TkServ work under BSDI (primetime) +1.0.1 : no address of a local var is returned anymore :) (primetime) +1.0.2 : Added forgotten tkserv.access.example to the package (primetime) +1.0.2 : IP masks (x.x.x.*) are now also be recognized as IPs (primetime) +1.0.2 : hostnames are now also possible in the restriction field (primetime) +1.0.3 : DEBUGGING is now functional and displays all service<->server + traffic to the standard output +1.0.3 : TkServ should now also compile under Irix (Szern) +1.0.3 : IP restrictions are now also possible in the access file + - wildcards are allowed (Szern) +1.0.3 : Wildcards do now also work in the oper u@h field of the access + file (Szern) +1.0.3 : Replaced FNM_CASEFOLD by FNM_NOESCAPE +1.0.4 : ':' is not allowed anymore in the TKLINE cmd line (Eumel) +1.0.4 : Fixed lame bug which kept tklines active altho already expired (Eumel) +1.0.5 : TkServ should now also compile under Redhat Linux. (Tero) +1.0.5 : a few changes for ircd/contrib compliancy +1.0.5 : the semantics for the access file have changed (check out README) +1.0.5 : it is now possible to disallow tklining of specific hosts (tumble) +1.0.6 : Added leading colons for the /squery commands (tumble) +1.0.6 : Added a hint concerning the distribution to the README +1.0.6 : it's now possible to decide whether a user needs to be opered or + not when accessing TkServ +1.0.7 : TkServ won't crash anymore if a bad lifetime is given (Tero) +1.0.8 : A few changes to make TkServ fit better into ircd/contrib. +1.0.8 : TkServ now sends out a hint when it receives an unknown cmd + (Fusion & viha) +1.0.9 : renamed the function logf due to a conflict in *BSD? (Virginie) +1.0.9 : General rename of some tkserv functions +1.2 : Password migration from cmd line to conf file (Earthpig) +1.2 : TkServ now daemonizes itself. (Earthpig) diff --git a/contrib/tkserv/CREDITS b/contrib/tkserv/CREDITS new file mode 100644 index 0000000..617fb16 --- /dev/null +++ b/contrib/tkserv/CREDITS @@ -0,0 +1,60 @@ +Thanks to the following people, who have contributed in one way or another +to the development of TkServ: + +- Andre 'koopal' Koopal + + beta testing + + default expiration + + removal of tklines before expiration (manual removal) + + password migration from config.h to cmd line + +- Asu 'primetime' Pala + + fix for BSDI + + IP recognition bug + + forgotten tkserv.access.example file + + hostnames in the restriction field of the access file + +- 'Szern' + + fix for Irix + + IPs in the restriction field + + wildcards in the u@h oper field of the access file + +- Michael 'Eumel' Neumayer + + colons are not allowed anymore outside the password parameter + + expired tklines do now get removed really automatically + +- Tero 'Tero' Saari + + RedHat Linux cludge + + no crashes anymore when a bad lifetime is given + +- Andrew ´Earthpig´ Snare + + password back to conf file (more secure) + + automatic daemonization + +- 'tumble' + + possibility to explicitly disallow specific hosts from getting tklined + + leading colons for the /squery commands in the README + +- Kristian 'Fusion' Bergmann & 'viha' + + Sending out of a hint when an unknown command is received + +- 'Virginie' + + rename of the logf function because of conflict under *BSD? + +- 'jbn' + + expiration of tklines / default expiration + +- The EPIC Software Labs + + for their nice ircII-EPIC client from which i took some networking + stuff, see http://www.snafu.de/~kl/epic/index.html for more about + epic + +- Kai 'Oswald' Seidler + + for his NoteServ, on which TkServ is based and which has helped me a + lot in making TkServ, see http://oswald.pages.de for more + +- Christophe 'syrk' Kalt and Vesa 'Vesa' Ruokonen + + for giving me the impulse to this kind of service :) + + +And finally thanks to all the Linux people out there for contributing +to the world's best OS! :-) diff --git a/contrib/tkserv/INSTALL b/contrib/tkserv/INSTALL new file mode 100644 index 0000000..9bc69bd --- /dev/null +++ b/contrib/tkserv/INSTALL @@ -0,0 +1,20 @@ +How to install TkServ +--------------------- + +Yes, there isn't any configure yet. That's why the compilation on some +machines could be difficult because you may have to include one or two +libraries by hand. I'll try to create a configure file in the future. + +Up to now, i've only compiled TkServ on Linux, Solaris and Irix. I hope you +won't get into trouble when trying to compile on another OS. But everyone +should be running Linux anyway. :-) + +So here we go: + +1. Unpack and untar the archive. (which you might already have done :) +2. RTFM. :-> +3. run "./configure" (if you haven't already done so) +3. Edit the tkconf.h file. +4. "make tkserv" + +Good luck, Kasi diff --git a/contrib/tkserv/README b/contrib/tkserv/README new file mode 100644 index 0000000..a7b7c47 --- /dev/null +++ b/contrib/tkserv/README @@ -0,0 +1,290 @@ +Welcome to TkServ ! +=+=+=+=+=+=+=+=+=+= + +This program is released under the GNU General Public License. +A copy of this license is included in the distribution. + +I) Introduction +--------------- + +TkServ is a so-called temporary k-line service. + +[If you don't know what a service is, consult the documentation which comes +along with the irc2.10.x package (if you don't know services, you shouldn't +be reading this anyway ;).] + +This is what TkServ does - roughly: On request, it adds a given k-line +pattern to the server's k-line list and (sooner or later, see below) then +removes it. The adding/removing is done via the ircd.conf file. + +The purpose/advantages of a temporary k-line service: + + - it facilitates the process of k-lining users + - added k-lines disappear automatically (see below) + - it allows _also_ remote users (only if they are listed in the access + file of the service - see below) to temp k-line users on the respective + server + - it allows people to specify a duration for each tkline + - it is more effective than /kill but practically as easy to use + - it could therefore act as a replacement for the /kill command - which in + fact is more or less its longtime goal... + + +II) Security concerns +--------------------- + +Of course, when allowing remote "access" to the ircd.conf file, the main +concern of most admins is security. Therefore, here's a list of the +procedures used by TkServ to ensure that only authorized users may add +temporary k-lines to the server's conf file [origin == the person who is +sending a request]: + +- the origin's user@host has to match one of the u@h's in the tkserv.access + file (case sensitive!) +- the origin has always to specify a password which has to match the + password that belongs to the corresponding user@host in the access file + (case sensitive!) +- the origin has to be opered, if you want to +- it is possible to allow an authorized user to only tkline given hostnames + or TLDs + +Especially the third point equals to strong security, because: Could you +imagine any cracker who has gained O: on some server, wasting his time on +trying to get access to a remote server's temp k-line list instead of +playing around with his O: ? See, neither could i. ;-) + + +III) Installation +----------------- + +A) Precondition + + The only thing you need in order to run TkServ is an "ircd.conf" file, + an "ircd.pid" file and an IRC server which has been compiled with + USE_SERVICES #define'd in the config.h file (!). + +B) Editing the configuration file (config.h) + + You have to change the following entries in the config file: + + TKSERV_ADMIN_NAME (your real name) + TKSERV_ADMIN_CONTACT (mail address) + TKSERV_ADMIN_OTHER (your nick, for example) + + TKSERV_NAME (the name of the service appearing on /SERVLIST) + TKSERV_DESC (a neato description :) + TKSERV_DIST (the distribution of the service) + +| A few words to the distribution of the service. Here are the pros & +| contras of a global TkServ from my point of view: +| +| [contra] It makes the /servlist become unnecessarily big and less handy +| [contra] You can detect also local services by /trace'ing a server +| [contra] You can access a local TkServ by setting up a special client +| on the concerned server (maybe with a special I: line) +| +| [pro] A global TkServ is more comfortable to use for remote users. +| [pro] If you want to see which server is running one (for e.g. to +| request access to it), you do only have to do a /servlist. + + TKSERV_PATH (the abs. path to your ircd.conf, no trailing slash please!) + TKSERV_LOGFILE (the abs. path to your tkserv logfile, no trailing slash) + TKSERV_ACCESSFILE (the abs. path to your tkserv access file, ditto) + + TKSERV_DEBUG (for debugging only, displayes traffic to standard output) + +C) Compiling the source + +TkServ will be compiled along with the irc server. + +D) Setting up the access file: tkserv.access + + If anyone should be authorized to use TkServ on your server, he/she has + to figure in the access file. The format of it is: + +| [!][] +| +| Which means: +| [!] [] +| +| A '!' before the u@h means that the specified user doesn't need to be +| opered when accessing TkServ. Before the FQDN/IP, it means that the user +| is not allowed to tkline that given FQDN/IP. See below. +| +| Examples: +| (1) foo@bar.com foo-pass +| (2) some@user.on.the.net some.passw1 *.net,207.128.* +| another@user.foo.com Akfdsv.df *netcom.com,*.ca +| you@get.the.picture.org ditto. *.org,dialup*.lamer.net,194.44.44.* +| oper@dialup*.dialup.net pwd1.2 *dialup.net,145.44.*,*.fr +| (3) !luser@doesnt.need.to.be.opered.org bleh !elite.org,*.org +| (4) !~luser@no.ident.no.oper.com yo *.com +| +| (1) Any oper who is running identd and whose userhost equals to +| foo@bar.com can tkline everyone if supplied password equals +| foo-pass. +| (2) Any oper with identd whose u@h equals to some@user.on.the.net +| can tkline everyone whose TLD is ".net" or who is IRCing within +| the IP subnet 207.128.*, if correct password is given. +| (3) Any luser (no need to be opered) whose u@h/passwd equals can tkline +| everyone whose TLD is ".org" except the host "elite.org" +| ("*@elite.org"). +| +| Generally, you should be aware of the fact that if you put something +| in the FQDN/IP field, then you automatically restrict the access. +| Therefore, you must then also indicate all the allowed FQDNs/IPs. +| +| The access routines are pretty flexible. So pay attention in what order +| you allow/disallow what. :) +| +| Other examples: +| !foo@bar.com foo-pass !*.net,*.com,!*.com +| some@user.on.the.net some.passw1 *.net,207.128.*,!127.0.0.* +| another@user.foo.com Akfdsv.df *netcom.com,!*trends.ca,*.ca +| +| Notice that if you allow "*.de" and after it you forbid "blah.de", +| this won't work. The oper will still be able to tkline blah.de since +| "*.de" appears before "!blah.de" in the access field. +| +| Are we confused, yet? ;-) + + For some other examples, refer to the tkserv.access.example file, which + is included in the package. + + The u@h field for the user can also contain wildcards, as you can see. + +| If you specify an FQDN (or several of them in a comma-separated +| list), the concerned user will only be allowed to tkline users from +| that FQDN(s). Everything is done via 'wildcard-matching' (if any). +| I.e. that "home.blah.de" matches only "*@home.blah.de". If you want +| to allow a whole TLD, you have to do this by putting "*.tld" in the +| access field. + +! An empty FQDN/IP field means that the concerned user can tkline everyone. ! + [Except *@* that is.] + +E) Setting up the S: line in your ircd.conf file + + If you're not yet familiar with S: lines, consult the documentation of + the ircd package. + + S::::33554432: + + is the FQDN from which the service will connect to the server. + + The service type 33554432 is mandatory! Currently, TkServ will refuse + any other service type. [Actually, it won't, but it's good to think that + it will... ;-] + + The service class should refer to an existing class (according to the + documentation :). + +F) Starting TkServ + + The command line syntax of TkServ looks like this: + + tkserv + or + tkserv + + Example: + + tkserv localhost 6667 my-serv.pass + + Where is the address of your IRC server, the port to + which TkServ will connect and the password for the service. + +G) Adding temp k-klines (TKLINE) + + Provided that TkServ recognizes you, you can add temporary k-lines via + the TKLINE command, which has three different variants: + + (1) :TKLINE + (2) :TKLINE + (3) :TKLINE -1 + + (1) adds a tkline for with an expire time of hours and + with the reason . + (2) adds a tkline for with the default expire time (2 hours) and + with the reason . + (3) removes any existing tklines found for . + + Examples: + + (1) :TKLINE my.pass 5 lamer@lamers.org dont flood + (2) :TKLINE blah. *@foo.com stop spamming + (3) :TKLINE my.pass -1 lamer@lamers.org + + must be > 0 and < 168. + +| [If your client doesn't support SQUERY, the entire cmd line has to be: +| "/quote squery :tkline ...". If it does support it, +| then "/squery tkline ..." should do it.] +| +| [And yes, ircII-EPIC4 supports SQUERY and SERVLIST! ;-)] +| +| If a non-opered user tries to use TKLINE without having a matching entry +| in the access file, he gets "Only IRC-Operators may use this command" as +| an error message. This is not correct anymore, but i didn't bother to +| change it (since it may prevent kids from playing around with TkServ :). + +H) Online help/info + +TkServ does also have a little online help which is accessible via +"/squery help". + +I) Quitting the service + +To make TkServ quit IRC you have to send him the following SQUERY: + +QUIT + +Where corresponds to password that you indicated at startup. +Be aware that anyone who knows that password can make your TkServ quit. + +J) Debugging + +If you #define TKSERV_DEBUG in the config.h file, everything which is sent +to the server from the service and from the server to the service will be +displayed to the standard output. + + +IV) Misc, or what goes where + +TkServ will create the following permanent files in your ircd directory: + +ircd.conf.tkserv (backup of the ircd.conf file) +tkserv.log (TkServ's log file) + +The latter will contain most of the error messages (in case something goes +wrong - what we all don't hope ;) as well as logs of successful TKLINE +requests. + +The tkserv.access file has to be in the directory specified in the config.h +file. If no tkserv.access file is found, no one will be able to add temp +k-lines. + +Now and then you should zero your TkServ logfile because this won't happen +by itself. =) + + +V) Credits + +See the CREDITS file. + + +VI) Bugs, comments, suggestions... + +Send everything to kl@snafu.de or to Kasi@IRC. + + +VII) The TkServ-mailinglist + +There's now a mailinglist for TkServ out there. It is used for general +announcements (bugs, new releases, etc.) concerning TkServ. Since it's a +read-only mailinglist, it doesn't have much traffic. You can subscribe to +it by sending a mail to tkserv@kl.Snafu.DE with "subscribe" in the subject +or in the body of the mail. + + +Enjoy, -Kasi diff --git a/contrib/tkserv/proto.h b/contrib/tkserv/proto.h new file mode 100644 index 0000000..edf23b7 --- /dev/null +++ b/contrib/tkserv/proto.h @@ -0,0 +1,24 @@ +void sendto_server(char *buf, ...); +void sendto_user(char *text, ...); +void process_server_output(char *line); +void parse_server_output(char *buffer); +int server_output(int fd, char *buffer); + +void service_pong(void); +void service_notice(char **args); +void service_squery(char **args); +int service_userhost(char *args); +void squery_help(char **args); +void squery_tkline(char **args); +void squery_quit(char **args); + +void sendlog(char *text, ...); +char *ts(void); + +int is_opered(void); +int is_authorized(char *pwd, char *host); + +void exec_cmd(char *cmd, ...); +int add_tkline(char *host, char *user, char *reason, int lifetime); +int check_tklines(char *host, char *user, int lifetime); +void rehash(int what); diff --git a/contrib/tkserv/tkserv.access.example b/contrib/tkserv/tkserv.access.example new file mode 100644 index 0000000..4269c93 --- /dev/null +++ b/contrib/tkserv/tkserv.access.example @@ -0,0 +1,10 @@ +foo@bar.com foo.pass *netcom.com,*.net +someone@SomeOrg.org aldkf.23 eleet.org,165.55.45.* +~blah@ppp*.blah.de igh.pass +user@users.Online.net ukuk.ua1 +some@ip*.user.com blah 204.85.*,194.55.43.* +you.get@the.picture.com pass ppp*.lame.com,*.org,dialin*.whitehouse.gov,*.net,*.uk +disallow@something.com bleh !*.de,!*.fr,*.net,*.org,*.com,!195.144.45.* +disallow@another.host.fr yo !hugo.fr,!admin.irc.fr,*.fr,*.ca,195.55.66.* +!luser@who.doesnt.need.to.be.opered.de yeh *.de + diff --git a/contrib/tkserv/tkserv.c b/contrib/tkserv/tkserv.c new file mode 100644 index 0000000..92f281d --- /dev/null +++ b/contrib/tkserv/tkserv.c @@ -0,0 +1,1022 @@ +/* +** Powered by Linux. :-) +** +** Copyright (c) 1998 Kaspar 'Kasi' Landsberg, +** +** File : tkserv.c v1.2 +** Author : Kaspar 'Kasi' Landsberg, +** Desc. : Temporary K-line Service. +** For further info see the README file. +** Location : http://www.snafu.de/~kl/tkserv +** Usage : tkserv +** E.g. : tkserv localhost 6667 +** +** This program is distributed under the GNU General Public License in the +** hope that it will be useful, but without any warranty. Without even the +** implied warranty of merchantability or fitness for a particular purpose. +** See the GNU General Public License for details. +** +** Note: The C version of this service is based on parts of the +** ircII-EPIC IRC client by the EPIC Software Labs and on +** the NoteServ service by Kai 'Oswald' Seidler - see +** http://oswald.pages.de for more about NoteServ. +** Thanks to both. =) +** +** PS: Casting rules the world! (doh) +*/ + +#include "os.h" +#undef strcasecmp +#include "config.h" +#include "tkconf.h" +#include "proto.h" + +/* Max. kill reason length */ +#define TKS_MAXKILLREASON 128 + +/* Used max. length for an absolute Unix path */ +#define TKS_MAXPATH 128 + +/* Max. buffer length (don't change this?) */ +#define TKS_MAXBUFFER 8192 + +/* don't change this either(?) */ +#define TKS_MAXARGS 250 + +/* The version information */ +#define TKS_VERSION "Hello, i'm TkServ v1.2." + +static char *nuh; +FILE *tks_logf; +int fd = -1, tklined = 0; + +/* +** Returns the current time in a formated way. +** Yes, "ts" stands for "time stamp". I know, +** this hurts, but i couldn't find any better +** description. ;-> +*/ +char *tks_ts(void) +{ + static char tempus[256]; + time_t now; + struct tm *loctime; + + /* Get the current time */ + now = time(NULL); + + /* Convert it to local time representation */ + loctime = localtime(&now); + + strftime(tempus, 256, "@%H:%M %m/%d", loctime); + + return(tempus); +} + +/* logging routine, with timestamps */ +void tks_log(char *text, ...) +{ + char txt[TKS_MAXBUFFER]; + va_list va; + + tks_logf = fopen(TKSERV_LOGFILE, "a"); + va_start(va, text); + vsprintf(txt, text, va); + + if (tks_logf != NULL) + fprintf(tks_logf, "%s %s\n", txt, tks_ts()); + else + { + perror(TKSERV_LOGFILE); + va_end(va); + return; + } + + va_end(va); + fclose(tks_logf); +} + +/* an optimized system() function */ +void exec_cmd(char *cmd, ...) +{ + char command[TKS_MAXBUFFER]; + va_list va; + + va_start(va, cmd); + vsprintf(command, cmd, va); + system(command); + va_end(va); +} + +/* sends a string (<= TKS_MAXBUFFER) to the server */ +void sendto_server(char *buf, ...) +{ + char buffer[TKS_MAXBUFFER]; + va_list va; + + va_start(va, buf); + vsprintf(buffer, buf, va); + write(fd, buffer, strlen(buffer)); + va_end(va); + +#ifdef TKSERV_DEBUG + printf("%s", buffer); +#endif +} + +/* sends a NOTICE to the SQUERY origin */ +void sendto_user(char *text, ...) +{ + char *nick, *ch; + char txt[TKS_MAXBUFFER]; + va_list va; + + nick = (char *) strdup(nuh); + ch = (char *) strchr(nick, '!'); + *ch = '\0'; + + va_start(va, text); + vsprintf(txt, text, va); + sendto_server("NOTICE %s :%s\n", nick, txt); + va_end(va); +} + +void process_server_output(char *line) +{ + char *ptr; + static char *args[TKS_MAXARGS]; + int i, argc = 0; + + while ((ptr = (char *) strchr(line, ' ')) && argc < TKS_MAXARGS) + { + args[argc] = line; + argc++; + *ptr = '\0'; + line = ptr + 1; + } + + args[argc] = line; + + for (i = argc + 1; i < TKS_MAXARGS; i++) + args[i] = ""; + + /* + ** After successfull registering, backup the ircd.conf file + ** and set the perms of the log file -- the easy way :) + */ + if ((*args[0] == ':') && (!strcmp(args[1], "SERVSET"))) + { + chmod(TKSERV_ACCESSFILE, S_IRUSR | S_IWRITE); + chmod(TKSERV_LOGFILE, S_IRUSR | S_IWRITE); + exec_cmd("cp "CPATH" "TKSERV_IRCD_CONFIG_BAK); + tks_log("Registration successful."); + } + + /* We do only react upon PINGs, SQUERYs and &NOTICES */ + if (!strcmp(args[0], "PING")) + service_pong(); + + if ((*args[0] == ':') && (!strcmp(args[1], "SQUERY"))) + service_squery(args); + + if (!strcmp(args[0], "&NOTICES")) + service_notice(args); +} + +/* reformats the server output */ +void parse_server_output(char *buffer) +{ + char *ch, buf[TKS_MAXBUFFER]; + static char tmp[TKS_MAXBUFFER]; + + /* server sent an empty line, so just return */ + if (!buffer && !*buffer) + return; + + while ((ch = (char *) strchr(buffer, '\n'))) + { + *ch = '\0'; + + if (*(ch - 1) == '\r') + *(ch - 1) == '\0'; + + sprintf(buf, "%s%s", tmp, buffer); + *tmp = '\0'; + process_server_output(buf); + buffer = ch + 1; + } + + if (*buffer) + strcpy(tmp, buffer); +} + +/* reads and returns output from the server */ +int server_output(int fd, char *buffer) +{ + int n = read(fd, buffer, TKS_MAXBUFFER); + buffer[n] = '\0'; + +#ifdef TKSERV_DEBUG + printf("%s", buffer); +#endif + + return(n); +} + +/* is the origin of the /squery opered? */ +int is_opered(void) +{ + char *nick, *ch, *token, *u_num, *userh; + char buffer[TKS_MAXBUFFER]; + + nick = (char *) strdup(nuh); + ch = (char *) strchr(nick, '!'); + *ch = '\0'; + sendto_server("USERHOST %s\n", nick); + + /* get the USERHOST reply (hopefully) */ + server_output(fd, buffer); + + token = (char *) strtok(buffer, " "); + token = (char *) strtok(NULL, " "); + u_num = (char *) strdup(token); + token = (char *) strtok(NULL, " "); + token = (char *) strtok(NULL, " "); + userh = (char *) strdup(token); + + /* if we got the USERHOST reply, perform the check */ + if (!strcmp(u_num, "302")) + { + char *ch; + ch = (char *) strchr(userh, '=') - 1; + + /* is the origin opered? */ + if (*ch == '*') + { + char *old_uh, *new_uh, *ch; + + old_uh = (char *) (strchr(nuh, '!') + 1); + new_uh = (char *) (strchr(userh, '=') + 2); + + if (ch = (char *) strchr(new_uh, '\r')) + *ch = '\0'; + + /* Does the u@h of the USERHOST reply correspond to the u@h of our origin? */ + if (!strcmp(old_uh, new_uh)) + return(1); + else + /* + ** race condition == we sent a USERHOST request and got the USERHHOST reply, + ** but this reply doesn't correspond to our origin of the SQUERY -- + ** this should never happen (but never say never ;) + */ + sendto_user("A race condition has occured -- please try again."); + } + } + else + /* + ** race condition == we sent a USERHOST request but the next message from + ** the server was not a USERHOST reply (usually due to lag) + */ + sendto_user("A race condition has occured -- please try again (and ignore the following error message)."); + + return(0); +} + +/* +** Look for an entry in the access file and +** see if the origin needs to be opered +*/ +int must_be_opered() +{ + FILE *fp; + + /* if the access file exists, check for auth */ + if ((fp = fopen(TKSERV_ACCESSFILE, "r")) != NULL) + { + char buffer[TKS_MAXBUFFER]; + char *access_uh, *token, *uh; + + while (fgets(buffer, TKS_MAXBUFFER, fp)) + { + uh = (char *) (strchr(nuh, '!') + 1); + token = (char *) strtok(buffer, " "); + + if (token) + access_uh = (char *) strdup(token); + + /* check for access file corruption */ + if (!access_uh) + { + tks_log("Corrupt access file. RTFM. :-)"); + + return(0); + } + + /* do we need an oper? */ + if (*access_uh == '!') + { + if (!fnmatch((char *) (strchr(access_uh, '!') + 1), uh, 0)) + return(0); + } + } + } + else + tks_log("%s not found.", TKSERV_ACCESSFILE); + + return(1); +} + +/* check whether origin is authorized to use the service */ +int is_authorized(char *pwd, char *host) +{ + FILE *fp; + + /* if the access file exists, check for authorization */ + if ((fp = fopen(TKSERV_ACCESSFILE, "r")) != NULL) + { + char buffer[TKS_MAXBUFFER]; + char *access_uh, *access_pwd; + char *token, *uh, *ch, *tlds = NULL; + + while (fgets(buffer, TKS_MAXBUFFER, fp)) + { + uh = (char *) (strchr(nuh, '!') + 1); + token = (char *) strtok(buffer, " "); + + if (token) + access_uh = (char *) strdup(token); + + if (*access_uh == '!') + access_uh = (char *) (strchr(access_uh, '!') + 1); + + token = (char *) strtok(NULL, " "); + + if (token) + access_pwd = (char *) strdup(token); + + token = (char *) strtok(NULL, " "); + + if (token) + tlds = (char *) strdup(token); + else + if (ch = (char *) strchr(access_pwd, '\n')) + *ch = '\0'; + + /* check for access file corruption */ + if (!access_uh || !access_pwd) + { + tks_log("Corrupt access file. RTFM. :-)"); + + return(0); + } + + /* check uh, pass and TLD */ + if (!fnmatch(access_uh, uh, 0)) + if (!strcmp(pwd, access_pwd)) + if (!tlds) + return(1); + else + { + char *token, *ch; + + /* blah */ + if (ch = (char *) strchr(tlds, '\n')) + *ch = '\0'; + + token = (char *) strtok(tlds, ","); + + /* '!' negates the given host/domain -> not allowed to tkline */ + if (*token == '!') + { + if (!fnmatch(((char *) strchr(token, '!') + 1), host, 0)) + { + sendto_user("You are not allowed to tkline \"%s\",", host); + return(0); + } + } + else if (!fnmatch(token, host, 0)) + return(1); + + /* walk thru the list */ + while (token = (char *) strtok(NULL, ",")) + { + if (*token == '!') + { + if (!fnmatch((char *) (strchr(token, '!') + 1), host, 0)) + { + sendto_user("You are not allowed to tkline \"%s\",", host); + return(0); + } + } + else if (!fnmatch(token, host, 0)) + return(1); + } + + sendto_user("You are not allowed to tkline \"%s\".", host); + } + } + + } + else + tks_log("%s not found.", TKSERV_ACCESSFILE); + + return(0); +} + +/*************** ircd.conf section ****************/ + +/* Appends new tklines to the ircd.conf file */ +int add_tkline(char *host, char *user, char *reason, int lifetime) +{ + FILE *iconf; + + if (iconf = fopen(CPATH, "a")) + { + time_t now; + + now = time(NULL); + fprintf(iconf, "K:%s:%s:%s:0 # %d %u tkserv\n", + host, reason, user, lifetime, now); + fclose(iconf); + rehash(1); + tks_log("K:%s:%s:%s:0 added for %d hour(s) by %s.", + host, reason, user, lifetime, nuh); + + return(1); + } + else + tks_log("Couldn't write to "CPATH); + + return(0); +} + +/* Check for expired tklines in the ircd.conf file */ +int check_tklines(char *host, char *user, int lifetime) +{ + FILE *iconf, *iconf_tmp; + + if ((iconf = fopen(CPATH, "r")) && (iconf_tmp = fopen(TKSERV_IRCD_CONFIG_TMP, "w"))) + { + int count = 0, found = 0; + time_t now; + char buffer[TKS_MAXBUFFER]; + char buf_tmp[TKS_MAXBUFFER]; + + /* just in case... */ + chmod(TKSERV_IRCD_CONFIG_TMP, S_IRUSR | S_IWRITE); + + now = time(NULL); + + while (fgets(buffer, TKS_MAXBUFFER, iconf)) + { + if ((*buffer != 'K') || (!strstr(buffer, "tkserv"))) + fprintf(iconf_tmp, buffer); + else + { + /* + ** If lifetime has a value of -1, look for matching + ** tklines and remove them. Otherwise, perform + ** the expiration check. + */ + if (lifetime == -1) + { + char *token; + char buf[TKS_MAXBUFFER]; + + strcpy(buf, buffer); + token = (char *) strtok(buf, ":"); + token = (char *) strtok(NULL, ":"); + + if (!strcasecmp(token, host)) + { + token = (char *) strtok(NULL, ":"); + token = (char *) strtok(NULL, ":"); + + if (!strcasecmp(token, user)) + { + count++; + found = 1; + } + else + fprintf(iconf_tmp, buffer); + } + else + fprintf(iconf_tmp, buffer); + } + else + { + char *ch, *token; + char buf[TKS_MAXBUFFER]; + unsigned long int lifetime, then; + + strcpy(buf, buffer); + ch = (char *) strrchr(buf, '#'); + token = (char *) strtok(ch, " "); + token = (char *) strtok(NULL, " "); + lifetime = strtoul(token, NULL, 0); + token = (char *) strtok(NULL, " "); + then = strtoul(token, NULL, 0); + + if (!(((now - then) / (60 * 60)) >= lifetime)) + fprintf(iconf_tmp, buffer); + else + found = 1; + } + } + } + + fclose(iconf); + fclose(iconf_tmp); + exec_cmd("cp %s %s", TKSERV_IRCD_CONFIG_TMP,CPATH); + unlink(TKSERV_IRCD_CONFIG_TMP); + + if (found) + rehash(-1); + + return(count); + } + else + tks_log("Error while checking for expired tklines..."); +} + +/* reloads the ircd.conf file -- the easy way */ +void rehash(int what) +{ + exec_cmd("kill -HUP `cat "PPATH"`"); + + if (what != -1) + tklined = what; +} + +/*************** end of ircd.conf section **************/ + +/*************** The service command section *************/ + +/* On PING, send PONG and check for expired tklines */ +void service_pong(void) +{ + sendto_server("PONG %s\n", TKSERV_NAME); + check_tklines(NULL, NULL, 0); +} + +/* +** If we get a rehash, tell the origin that the tklines are active/removed +** and check for expired tklines... +*/ +void service_notice(char **args) +{ + if ((!strcmp(args[4], "reloading") && (!strcmp(args[5], TKSERV_IRCD_CONF))) || + (!strcmp(args[3], "rehashing") && (!strcmp(args[4], "Server")))) + { + if (tklined) + { + sendto_user("TK-line%s.", (tklined > 1) ? "(s) removed" : " active"); + tklined = 0; + } + } +} + +/* parse the received SQUERY */ +void service_squery(char **args) +{ + char *cmd, *ch; + + nuh = (char *) strdup(args[0] + 1); + cmd = (char *) strdup(args[3] + 1); + + if (ch = (char *) strchr(cmd, '\r')) + *ch = '\0'; + + if (!strcasecmp(cmd, "admin")) + { + sendto_user(TKSERV_ADMIN_NAME); + sendto_user(TKSERV_ADMIN_CONTACT); + sendto_user(TKSERV_ADMIN_OTHER); + } + + else if (!strcasecmp(cmd, "help")) + squery_help(args); + + else if (!strcasecmp(cmd, "info")) + { + sendto_user("This service is featuring temporary k-lines."); + sendto_user("It's available at http://www.snafu.de/~kl/tkserv."); + } + + else if (!strcasecmp(cmd, "quit")) + squery_quit(args); + + else if (!strcasecmp(cmd, "tkline")) + squery_tkline(args); + + else if (!strcasecmp(cmd, "version")) + sendto_user(TKS_VERSION); + + else + sendto_user("Unknown command. Try HELP."); +} + +/* SQUERY HELP */ +void squery_help(char **args) +{ + char *ch, *help_about; + + help_about = args[4]; + + if (help_about && *help_about) + { + if (ch = (char *) strchr(help_about, '\r')) + *ch = '\0'; + + if (!strcasecmp(help_about, "admin")) + sendto_user("ADMIN shows you the administrative info for this service."); + + if (!strcasecmp(help_about, "help")) + sendto_user("HELP shows you the help text for ."); + + if (!strcasecmp(help_about, "info")) + sendto_user("INFO shows you a short description about this service."); + + if (!strcasecmp(help_about, "tkline")) + { + sendto_user("TKLINE adds a temporary entry to the server's k-line list."); + sendto_user("TKLINE is a privileged command."); + } + + if (!strcasecmp(help_about, "version")) + sendto_user("VERSION shows you the version information of this service."); + } + else + { + sendto_user("Available commands:"); + sendto_user("HELP, INFO, VERSION, ADMIN, TKLINE."); + sendto_user("Send HELP for further help."); + } +} + +/* SQUERY TKLINE */ +void squery_tkline(char **args) +{ + int lifetime, i; + char *passwd, *pattern, *host, *ch, *user = "*"; + char reason[TKS_MAXKILLREASON]; + + /* Before we go thru all this, make sure we don't waste our time... */ + if (must_be_opered()) + { + if (!is_opered()) + { + sendto_user("Only IRC-Operators may use this command."); + return; + } + } + + i = 5; + + while (args[i] && *args[i]) + { + if (strchr(args[i], ':')) + { + sendto_user("Colons are only allowed in the password."); + return; + } + + i++; + } + + if (args[5] && *args[5]) + { + if (isdigit(*args[5]) || (*args[5] == '-')) + lifetime = atoi(args[5]); + else + { + sendto_user("The lifetime may only contain digits."); + return; + } + } + else + { + sendto_user("Usage: TKLINE [] "); + return; + } + + /* TKLINE */ + if ((lifetime > 0) && !(args[7] && *args[7])) + { + sendto_user("Usage: TKLINE "); + return; + } + + /* TKLINE (default expiration) */ + if ((lifetime == 0) && !(args[6] && *args[6])) + { + sendto_user("Usage: TKLINE "); + return; + } + + /* TKLINE -1 (removal of tklines) */ + if ((lifetime == -1) && !(args[6] && *args[6])) + { + sendto_user("Usage: TKLINE -1 "); + return; + } + + if ((lifetime >= 768) || (lifetime < -1)) + { + sendto_user(" must be greater than 0 and less than 768."); + return; + } + + /* I don't want to get confused, so all this may be a bit redundant */ + + if (lifetime > 0) + { + passwd = args[4]; + pattern = args[6]; + strcpy(reason, args[7]); + i = 8; + + /* I know... */ + while(args[i] && *args[i]) + { + strncat(reason, " ", TKS_MAXKILLREASON - strlen(reason) - 1); + strncat(reason, args[i], TKS_MAXKILLREASON - strlen(reason) - 1); + i++; + } + + if (ch = (char *) strchr(reason, '\r')) + *ch = '\0'; + } + + if (lifetime == 0) + { + if (!(strchr(args[5], '@') || strchr(args[5], '*') || + strchr(args[5], '.'))) + { + sendto_user(" must be greater than 0."); + return; + } + + passwd = args[4]; + lifetime = 2; /* Default lifetime */ + pattern = args[5]; + strcpy(reason, args[6]); + i = 7; + + while(args[i] && *args[i]) + { + strncat(reason, " ", TKS_MAXKILLREASON - strlen(reason) - 1); + strncat(reason, args[i], TKS_MAXKILLREASON - strlen(reason) - 1); + i++; + } + + if (ch = (char *) strchr(reason, '\r')) + *ch = '\0'; + } + + if (lifetime == -1) + { + passwd = args[4]; + pattern = args[6]; + + if (ch = (char *) strchr(pattern, '\r')) + *ch = '\0'; + } + + + /* Don't allow "*@*" and "*" in the pattern */ + if (!strcmp(pattern, "*@*") || !strcmp(pattern, "*")) + { + sendto_user("The pattern \"%s\" is not allowed.", pattern); + tks_log("%s tried to tkline/untkline \"%s\".", nuh, pattern); + return; + } + + /* Split the pattern up into username and hostname */ + if (ch = (char *) strchr(pattern, '@')) + { + host = (char *) (strchr(pattern, '@') + 1); + user = pattern; + *ch = '\0'; + } + else /* user defaults to "*" */ + host = pattern; + + /* + ** Make sure there's a dot in the hostname. + ** The reason for this being that i "need" a dot + ** later on and that i don't want to perform + ** extra checks whether it's there or not... + ** Call this lazyness, but it also makes the service faster. ;-) + */ + if (!strchr(host, '.')) + { + sendto_user("The hostname must contain at least one dot."); + return; + } + + if (!is_authorized(passwd, host)) + { + sendto_user("Authorization failed."); + return; + } + + if (lifetime == -1) + { + int i; + + i = check_tklines(host, user, lifetime); + sendto_user("%d tkline%sfor \"%s@%s\" found.", i, + (i > 1) ? "s " : " ", user, host); + + if (i > 0) + rehash(2); + } + else + if (!add_tkline(host, user, reason, lifetime)) + sendto_user("Error while trying to edit the "CPATH" file."); +} + +/* SQUERY QUIT +** Each time we receive a QUIT via SQUERY we check whether +** the supplied password matches the one in the conf file or not. +** If not, an error is sent out. If yes, we close the connection to +** the server. +*/ +void squery_quit(char **args) +{ + char *ch; + + if (ch = (char *) strchr(args[4], '\r')) + *ch = '\0'; + + if (!strcmp(args[4], TKSERV_PASSWORD)) + { + tks_log("Got QUIT from %s. Terminating.", nuh); + sendto_server("QUIT :Linux makes the world go round. :)\n"); + } + else + { + sendto_user("I refuse to QUIT. Have a look at the log to see why."); + tks_log("Got QUIT from %s with wrong password. Continuing.", nuh); + } +} + +/**************** End of service command section ***************/ + +int main(int argc, char *argv[]) +{ + + char *host, *port, buffer[TKS_MAXBUFFER], last_buf[TKS_MAXBUFFER]; + char tmp[TKS_MAXPATH]; + + int is_unix = (argv[1] && *argv[1] == '/'); + int sock_type = (is_unix) ? AF_UNIX : AF_INET; + int proto_type = SOCK_STREAM; + int eof = 0; + + struct in_addr LocalHostAddr; + struct sockaddr_in server; + struct sockaddr_in localaddr; + struct hostent *hp; + struct timeval timeout; + + fd_set read_set; + fd_set write_set; + + if ((is_unix) && (argc != 2)) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, " %s \n", argv[0]); + exit(1); + } + else if (argc != 3) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, " %s \n", argv[0]); + exit(1); + } + + if (!strcmp(TKSERV_DIST, "*")) + { + printf("Your service has a global distribution. Please make sure that\n"); + printf("you read the part about the service distribution in the README.\n"); + } + + tks_log("Welcome to TkServ. Lean back and enjoy the show..."); + + if ((fd = socket(sock_type, proto_type, 0)) < 0) + { + perror("socket"); + exit(1); + } + + /* copy the args into something more documentable */ + host = argv[1]; + + if (!is_unix) + port = argv[2]; + + /* Unix domain socket */ + if (is_unix) + { + struct sockaddr_un name; + memset(&name, 0, sizeof(struct sockaddr_un)); + name.sun_family = AF_UNIX; + strcpy(name.sun_path, host); + + if (connect(fd, (struct sockaddr *) &name, strlen(name.sun_path) + 2) == -1) + { + perror("connect"); + close(fd); + exit(1); + } + } + + memset(&localaddr, 0, sizeof(struct sockaddr_in)); + localaddr.sin_family = AF_INET; + localaddr.sin_addr = LocalHostAddr; + localaddr.sin_port = 0; + + if (bind(fd, (struct sockaddr *) &localaddr, sizeof(localaddr))) + { + perror("bind"); + close(fd); + exit(1); + } + + memset(&server, 0, sizeof(struct sockaddr_in)); + memset(&LocalHostAddr, 0, sizeof(LocalHostAddr)); + + if (!(hp = gethostbyname(host))) + { + perror("resolv"); + close(fd); + exit(1); + } + + memmove(&(server.sin_addr), hp->h_addr, hp->h_length); + memmove((void *) &LocalHostAddr, hp->h_addr, sizeof(LocalHostAddr)); + server.sin_family = AF_INET; + server.sin_port = htons(atoi(port)); + + if (connect(fd, (struct sockaddr *) &server, sizeof(server)) == -1) + { + perror("connect"); + exit(1); + } + + /* register the service with SERVICE_WANT_NOTICE */ + sendto_server("PASS %s\n", TKSERV_PASSWORD); + sendto_server("SERVICE %s localhost %s 33554432 0 :%s\n", TKSERV_NAME, TKSERV_DIST, TKSERV_DESC); + sendto_server("SERVSET 33619968\n"); + + timeout.tv_usec = 1000; + timeout.tv_sec = 10; + + /* daemonization... i'm sure it's not complete */ + switch (fork()) + { + case -1: + perror("fork()"); + exit(3); + case 0: + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + if (setsid() == -1) + exit(4); + break; + default: + return 0; + } + + /* listen for server output and parse it */ + while (!eof) + { + FD_ZERO(&read_set); + FD_ZERO(&write_set); + FD_SET(fd, &read_set); + + if (select(FD_SETSIZE, &read_set, &write_set, NULL, &timeout) == -1) + { + perror("select"); + } + + if (!server_output(fd, buffer)) + { + printf("Connection closed.\n"); + printf("Last server output was: %s\n", last_buf); + eof = 1; + } + + strcpy(last_buf, buffer); + parse_server_output(buffer); + } + + close(fd); + + exit(0); +} +/* eof */ -- cgit v1.2.3