[IRC-Dev CVS] [CVS] Module ircd-ircdev: Change committed
Brought to you by:
zolty
From: Toni G. <zo...@us...> - 2004-11-24 16:05:43
|
CVSROOT : /cvsroot/irc-dev Module : ircd-ircdev Commit time: 2004-11-24 16:05:11 UTC Modified files: ircd/ircd_alloc.c ircd/ircd_events.c ircd/ircd_features.c ircd/ircd_log.c ircd/ircd_relay.c ircd/ircd_reply.c ircd/ircd_signal.c ircd/ircd_snprintf.c ircd/ircd_string.c Added files: ircd/ircd_auth.c ircd/ircd_crypt.c ircd/ircd_crypt_native.c ircd/ircd_crypt_plain.c ircd/ircd_crypt_smd5.c ircd/ircd_md5.c ircd/ircd_res.c ircd/ircd_reslib.c Log message: Author: zoltan <zo...@ir...> Log message: 2004-11-24 Toni García <zo...@ir...> 1.0.alpha13 * Comentarios para Doxygen * Excepciones de Silences * Soporte total de IPv6 * Sincronizacion Undernet ---------------------- diff included ---------------------- Index: ircd-ircdev/ircd/ircd_alloc.c diff -u ircd-ircdev/ircd/ircd_alloc.c:1.2 ircd-ircdev/ircd/ircd_alloc.c:1.3 --- ircd-ircdev/ircd/ircd_alloc.c:1.2 Sun Feb 22 08:11:42 2004 +++ ircd-ircdev/ircd/ircd_alloc.c Wed Nov 24 08:05:00 2004 @@ -18,146 +18,86 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: ircd_alloc.c,v 1.2 2004/02/22 16:11:42 zolty Exp $ - * + */ +/** @file + * @brief IRC daemon memory allocation functions. + * @version $Id: ircd_alloc.c,v 1.3 2004/11/24 16:05:00 zolty Exp $ */ #include "config.h" #include "ircd_alloc.h" #include "ircd_string.h" #include "s_debug.h" -#include <string.h> #include <assert.h> +#include <string.h> -#if !defined(MDEBUG) -/* - * RELEASE: allocation functions - */ - -static void nomem_handler(void) -{ - Debug((DEBUG_FATAL, "Out of memory, exiting")); - exit(2); -} +static void nomem_handler(void); +/** Variable holding out-of-memory callback. */ static OutOfMemoryHandler noMemHandler = nomem_handler; -void set_nomem_handler(OutOfMemoryHandler handler) -{ - noMemHandler = handler; -} - -#if defined(FROBONFREE) || defined(FROBONMALLOC) +/** Default handler for out-of-memory conditions. */ static void -memfrob(void *ptr, size_t size) -{ - unsigned char *p = ptr, *ep = p + size - 4; - while (p <= ep) - { - *(unsigned long*)p = 0xDEADBEEF; - p += 4; - } - switch (ep - p) - { - case 3: - *(unsigned short*)p = 0xDEAD; - p[2] = 0xBE; - return; - case 2: - *(unsigned short*)p = 0xDEAD; - return; - case 1: - *p++ = 0xDE; - return; - } - return; -} -#endif - -void* MyMalloc(size_t size) +nomem_handler(void) { - void* p = -#ifdef FROBONFREE - malloc(size + sizeof(size_t)); +#ifdef MDEBUG + assert(0); #else - malloc(size); -#endif - if (!p) - (*noMemHandler)(); -#ifdef FROBONFREE - *(size_t*)p = size; - p = ((size_t*)p) + 1; -#endif -#ifdef FROBONMALLOC - memfrob(p, size); + Debug((DEBUG_FATAL, "Out of memory, exiting")); + exit(2); #endif - return p; } -void* MyRealloc(void* x, size_t size) +/** Set callback function for out-of-memory conditions. */ +void +set_nomem_handler(OutOfMemoryHandler handler) { -#ifdef FROBONFREE - size_t old_size = ((size_t*)x)[-1]; - if (old_size > size) - memfrob(((char*)x) + size, old_size - size); - x = realloc(((size_t*)x) - 1, size + sizeof(size_t)); -#else - x = realloc(x, size); -#endif - if (!x) - (*noMemHandler)(); - /* Both are needed in all cases to work with realloc... */ -#if defined(FROBONMALLOC) && defined(FROBONFREE) - if (old_size < size) - memfrob(((char*)x) + old_size, size - old_size); -#endif -#ifdef FROBONFREE - *(size_t*)x = size; - x = ((size_t*)x) + 1; -#endif - return x; + noMemHandler = handler; } -void* MyCalloc(size_t nelem, size_t size) +/** Allocate memory. + * @param[in] size Number of bytes to allocate. + * @param[in] x Type of allocation (ignored). + * @param[in] y Name of file doing allocation (ignored). + * @param[in] z Line number doing allocation (ignored). + * @return Newly allocated block of memory. + */ +void* DoMalloc(size_t size, const char* x, const char* y, int z) { - void* p = -#ifdef FROBONFREE - malloc(nelem * size + sizeof(size_t)); -#else - malloc(nelem * size); -#endif - if (!p) + void* t = malloc(size); + if (!t) (*noMemHandler)(); -#ifdef FROBONFREE - *((size_t*)p) = nelem * size; - p = ((size_t*)p) + 1; -#endif - memset(p, 0, size * nelem); - return p; + return t; } -#ifdef FROBONFREE -void -MyFrobulatingFree(void *p) +/** Allocate zero-initialized memory. + * @param[in] size Number of bytes to allocate. + * @param[in] x Type of allocation (ignored). + * @param[in] y Name of file doing allocation (ignored). + * @param[in] z Line number doing allocation (ignored). + * @return Newly allocated block of memory. + */ +void* DoMallocZero(size_t size, const char* x, const char* y, int z) { - size_t *stp = (size_t*)p; - if (p == NULL) - return; - memfrob(p, stp[-1]); - free(stp - 1); + void* t = malloc(size); + if (!t) + (*noMemHandler)(); + memset(t, 0, size); + return t; } -#endif -#else /* defined(MDEBUG) */ -/* - * DEBUG: allocation functions +/** Resize an allocated block of memory. + * @param[in] orig Original block to resize. + * @param[in] size Minimum size for new block. + * @param[in] file Name of file doing reallocation (ignored). + * @param[in] line Line number doing reallocation (ignored). */ -void set_nomem_handler(OutOfMemoryHandler handler) +void* DoRealloc(void *orig, size_t size, const char *file, int line) { - assert(0 != handler); - fda_set_nomem_handler(handler); + void* t = realloc(orig, size); + if (!t) + (*noMemHandler)(); + return t; } -#endif /* defined(MDEBUG) */ - Index: ircd-ircdev/ircd/ircd_auth.c diff -u /dev/null ircd-ircdev/ircd/ircd_auth.c:1.1 --- /dev/null Wed Nov 24 08:05:12 2004 +++ ircd-ircdev/ircd/ircd_auth.c Wed Nov 24 08:05:00 2004 @@ -0,0 +1,825 @@ +/* + * IRC-Dev IRCD - An advanced and innovative IRC Daemon, ircd/ircd_iauth.c + * + * Copyright (C) 2002-2004 IRC-Dev Development Team <de...@ir...> + * Copyright (C) 2004 Michael Poole <md...@tr...> + * Copyright (C) 2001 Perry Lorier <is...@co...> + * + * 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/** @file + * @brief IAuth client implementation for an IRC server. + * @version $Id: ircd_auth.c,v 1.1 2004/11/24 16:05:00 zolty Exp $ + */ +#include "config.h" +#include "client.h" +#include "ircd_alloc.h" +#include "ircd_auth.h" +#include "ircd_events.h" +#include "ircd_features.h" +#include "ircd_log.h" +#include "ircd_osdep.h" +#include "ircd_snprintf.h" +#include "ircd_string.h" +#include "ircd.h" +#include "msg.h" +#include "msgq.h" +#include "res.h" +#include "s_bsd.h" +#include "s_debug.h" +#include "s_misc.h" +#include "s_user.h" +#include "send.h" + +#include <assert.h> +#include <errno.h> +#include <netdb.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +/** Describes state of a single pending IAuth request. */ +struct IAuthRequest { + struct IAuthRequest *iar_prev; /**< previous request struct */ + struct IAuthRequest *iar_next; /**< next request struct */ + struct Client *iar_client; /**< client being authenticated */ + char iar_timed; /**< if non-zero, using parent i_request_timer */ +}; + +/** Enumeration of IAuth connection flags. */ +enum IAuthFlag +{ + IAUTH_BLOCKED, /**< socket buffer full */ + IAUTH_CONNECTED, /**< server greeting/handshake done */ + IAUTH_ABORT, /**< abort connection asap */ + IAUTH_ICLASS, /**< tell iauth about all local users */ + IAUTH_CLOSING, /**< candidate to be disposed */ + IAUTH_LAST_FLAG /**< total number of flags */ +}; +/** Declare a bitset structure indexed by IAuthFlag. */ +DECLARE_FLAGSET(IAuthFlags, IAUTH_LAST_FLAG); + +/** Describes state of an IAuth connection. */ +struct IAuth { + struct IAuthRequest i_list_head; /**< doubly linked list of requests */ + struct MsgQ i_sendQ; /**< messages queued to send */ + struct Socket i_socket; /**< connection to server */ + struct Timer i_reconn_timer; /**< when to reconnect the connection */ + struct Timer i_request_timer; /**< when the current request times out */ + struct IAuthFlags i_flags; /**< connection state/status/flags */ + struct DNSQuery i_query; /**< DNS lookup for iauth server */ + unsigned int i_recvM; /**< messages received */ + unsigned int i_sendM; /**< messages sent */ + unsigned int i_recvK; /**< kilobytes received */ + unsigned int i_sendK; /**< kilobytes sent */ + unsigned short i_recvB; /**< bytes received modulo 1024 */ + unsigned short i_sendB; /**< bytes sent modulo 1024 */ + time_t i_reconnect; /**< seconds to wait before reconnecting */ + time_t i_timeout; /**< seconds to wait for a request */ + unsigned int i_count; /**< characters used in i_buffer */ + char i_buffer[BUFSIZE+1]; /**< partial unprocessed line from server */ + char i_passwd[PASSWDLEN+1]; /**< password for connection */ + char i_host[HOSTLEN+1]; /**< iauth server hostname */ + struct irc_sockaddr i_addr; /**< iauth server ip address and port */ + struct IAuth *i_next; /**< next connection in list */ +}; + +/** Return flags element of \a iauth. */ +#define i_flags(iauth) ((iauth)->i_flags) +/** Return whether flag \a flag is set on \a iauth. */ +#define IAuthGet(iauth, flag) FlagHas(&i_flags(iauth), flag) +/** Set flag \a flag on \a iauth. */ +#define IAuthSet(iauth, flag) FlagSet(&i_flags(iauth), flag) +/** Clear flag \a flag from \a iauth. */ +#define IAuthClr(iauth, flag) FlagClr(&i_flags(iauth), flag) +/** Get blocked state for \a iauth. */ +#define i_GetBlocked(iauth) IAuthGet(iauth, IAUTH_BLOCKED) +/** Set blocked state for \a iauth. */ +#define i_SetBlocked(iauth) IAuthSet(iauth, IAUTH_BLOCKED) +/** Clear blocked state for \a iauth. */ +#define i_ClrBlocked(iauth) IAuthClr(iauth, IAUTH_BLOCKED) +/** Get connected flag for \a iauth. */ +#define i_GetConnected(iauth) IAuthGet(iauth, IAUTH_CONNECTED) +/** Set connected flag for \a iauth. */ +#define i_SetConnected(iauth) IAuthSet(iauth, IAUTH_CONNECTED) +/** Clear connected flag for \a iauth. */ +#define i_ClrConnected(iauth) IAuthClr(iauth, IAUTH_CONNECTED) +/** Get abort flag for \a iauth. */ +#define i_GetAbort(iauth) IAuthGet(iauth, IAUTH_ABORT) +/** Set abort flag for \a iauth. */ +#define i_SetAbort(iauth) IAuthSet(iauth, IAUTH_ABORT) +/** Clear abort flag for \a iauth. */ +#define i_ClrAbort(iauth) IAuthClr(iauth, IAUTH_ABORT) +/** Get IClass flag for \a iauth. */ +#define i_GetIClass(iauth) IAuthGet(iauth, IAUTH_ICLASS) +/** Set IClass flag for \a iauth. */ +#define i_SetIClass(iauth) IAuthSet(iauth, IAUTH_ICLASS) +/** Clear IClass flag for \a iauth. */ +#define i_ClrIClass(iauth) IAuthClr(iauth, IAUTH_ICLASS) +/** Get closing flag for \a iauth. */ +#define i_GetClosing(iauth) IAuthGet(iauth, IAUTH_CLOSING) +/** Set closing flag for \a iauth. */ +#define i_SetClosing(iauth) IAuthSet(iauth, IAUTH_CLOSING) +/** Clear closing flag for \a iauth. */ +#define i_ClrClosing(iauth) IAuthClr(iauth, IAUTH_CLOSING) + +/** Return head of request linked list for \a iauth. */ +#define i_list_head(iauth) ((iauth)->i_list_head) +/** Return socket event generator for \a iauth. */ +#define i_socket(iauth) ((iauth)->i_socket) +/** Return reconnect timer for \a iauth. */ +#define i_reconn_timer(iauth) ((iauth)->i_reconn_timer) +/** Return request timeout timer for \a iauth. */ +#define i_request_timer(iauth) ((iauth)->i_request_timer) +/** Return DNS query for \a iauth. */ +#define i_query(iauth) ((iauth)->i_query) +/** Return received bytes (modulo 1024) for \a iauth. */ +#define i_recvB(iauth) ((iauth)->i_recvB) +/** Return received kilobytes (modulo 1024) for \a iauth. */ +#define i_recvK(iauth) ((iauth)->i_recvK) +/** Return received megabytes for \a iauth. */ +#define i_recvM(iauth) ((iauth)->i_recvM) +/** Return sent bytes (modulo 1024) for \a iauth. */ +#define i_sendB(iauth) ((iauth)->i_sendB) +/** Return sent kilobytes (modulo 1024) for \a iauth. */ +#define i_sendK(iauth) ((iauth)->i_sendK) +/** Return sent megabytes for \a iauth. */ +#define i_sendM(iauth) ((iauth)->i_sendM) +/** Return outbound message queue for \a iauth. */ +#define i_sendQ(iauth) ((iauth)->i_sendQ) +/** Return reconnection interval for \a iauth. */ +#define i_reconnect(iauth) ((iauth)->i_reconnect) +/** Return request timeout interval for \a iauth. */ +#define i_timeout(iauth) ((iauth)->i_timeout) +/** Return length of unprocessed message data for \a iauth. */ +#define i_count(iauth) ((iauth)->i_count) +/** Return start of unprocessed message data for \a iauth. */ +#define i_buffer(iauth) ((iauth)->i_buffer) +/** Return password we send for \a iauth. */ +#define i_passwd(iauth) ((iauth)->i_passwd) +/** Return server hostname for \a iauth. */ +#define i_host(iauth) ((iauth)->i_host) +/** Return address of IAuth server for \a iauth. */ +#define i_addr(iauth) ((iauth)->i_addr) +/** Return server port for \a iauth. */ +#define i_port(iauth) ((iauth)->i_addr.port) +/** Return next IAuth connection after \a iauth. */ +#define i_next(iauth) ((iauth)->i_next) + +/** Command table entry. */ +struct IAuthCmd { + const char *iac_name; /**< Name of command. */ + void (*iac_func)(struct IAuth *iauth, int, char *[]); /**< Handler function. */ +}; + +/** Active %IAuth connection(s). */ +struct IAuth *iauth_active; + +static void iauth_write(struct IAuth *iauth); +static void iauth_reconnect(struct IAuth *iauth); +static void iauth_disconnect(struct IAuth *iauth); +static void iauth_sock_callback(struct Event *ev); +static void iauth_send_request(struct IAuth *iauth, struct IAuthRequest *iar); +static void iauth_dispose_request(struct IAuth *iauth, struct IAuthRequest *iar); +static void iauth_cmd_doneauth(struct IAuth *iauth, int argc, char *argv[]); +static void iauth_cmd_badauth(struct IAuth *iauth, int argc, char *argv[]); + +/** Table of responses we might get from the IAuth server. */ +static const struct IAuthCmd iauth_cmdtab[] = { + { "DoneAuth", iauth_cmd_doneauth }, + { "BadAuth", iauth_cmd_badauth }, + { NULL, NULL } +}; + +/** Start (or update) a connection to an %IAuth server. + * If a connection already exists for the specified server name and + * port, update it with the other parameters; otherwise allocate a new + * IAuth record. + * @param[in] host %IAuth server hostname. + * @param[in] port %IAuth server port. + * @param[in] passwd Password to send. + * @param[in] reconnect Reconnect interval. + * @param[in] timeout Request timeout interval. + * @return IAuth structure for that connection. + */ +struct IAuth *iauth_connect(char *host, unsigned short port, char *passwd, time_t reconnect, time_t timeout) +{ + struct IAuth *iauth; + + for (iauth = iauth_active; iauth; iauth = i_next(iauth)) { + if (!ircd_strncmp(i_host(iauth), host, HOSTLEN) + && (i_port(iauth) == port)) { + i_ClrClosing(iauth); + i_reconnect(iauth) = reconnect; + if (t_active(&i_reconn_timer(iauth)) && (t_expire(&i_reconn_timer(iauth)) > CurrentTime + i_reconnect(iauth))) + timer_chg(&i_reconn_timer(iauth), TT_RELATIVE, i_reconnect(iauth)); + break; + } + } + if (NULL == iauth) { + if (iauth_active && !i_GetClosing(iauth_active)) { + log_write(LS_CONFIG, L_WARNING, 0, "Creating extra active IAuth connection to %s:%d.", host, port); + } + iauth = MyCalloc(1, sizeof(*iauth)); + i_list_head(iauth).iar_prev = &i_list_head(iauth); + i_list_head(iauth).iar_next = &i_list_head(iauth); + msgq_init(&i_sendQ(iauth)); + ircd_strncpy(i_host(iauth), host, HOSTLEN); + memset(&i_addr(iauth), 0, sizeof(i_addr(iauth))); + i_port(iauth) = port; + iauth_active = iauth; + i_reconnect(iauth) = reconnect; + iauth_reconnect(iauth); + } + if (passwd) + ircd_strncpy(i_passwd(iauth), passwd, PASSWDLEN); + else + i_passwd(iauth)[0] = '\0'; + i_timeout(iauth) = timeout; + i_SetIClass(iauth); + return iauth; +} + +/** Mark all %IAuth connections as closing. */ +void iauth_mark_closing(void) +{ + struct IAuth *iauth; + for (iauth = iauth_active; iauth; iauth = i_next(iauth)) + i_SetClosing(iauth); +} + +/** Close a particular %IAuth connection. + * @param[in] iauth %Connection to close. + */ +void iauth_close(struct IAuth *iauth) +{ + /* Figure out what to do with the closing connection's requests. */ + if (i_list_head(iauth).iar_next != &i_list_head(iauth)) { + struct IAuthRequest *iar; + if (iauth_active || i_next(iauth)) { + /* If iauth_active != NULL, send requests to it; otherwise if + * i_next(iauth) != NULL, we can hope it or some later + * connection will be active. + */ + struct IAuth *target = iauth_active ? iauth_active : i_next(iauth); + + /* Append iauth->i_list_head to end of target->i_list_head. */ + iar = i_list_head(iauth).iar_next; + iar->iar_prev = i_list_head(target).iar_prev; + i_list_head(target).iar_prev->iar_next = iar; + iar = i_list_head(iauth).iar_prev; + iar->iar_next = &i_list_head(target); + i_list_head(target).iar_prev = iar; + + /* If the target is not closing, send the requests. */ + for (iar = i_list_head(iauth).iar_next; + iar != &i_list_head(target); + iar = iar->iar_next) { + if (!i_GetClosing(target)) + iauth_send_request(target, iar); + } + } else { + /* No active connections - approve the requests and drop them. */ + while ((iar = i_list_head(iauth).iar_next) != &i_list_head(iauth)) { + struct Client *client = iar->iar_client; + iauth_dispose_request(iauth, iar); + register_user(client, client, cli_name(client), cli_username(client)); + } + } + } + /* Make sure the connection closes with an empty request list. */ + i_list_head(iauth).iar_prev = &i_list_head(iauth); + i_list_head(iauth).iar_next = &i_list_head(iauth); + /* Cancel the timer, if it is active. */ + if (t_active(&i_reconn_timer(iauth))) + timer_del(&i_reconn_timer(iauth)); + if (t_active(&i_request_timer(iauth))) + timer_del(&i_request_timer(iauth)); + /* Disconnect from the server. */ + if (s_fd(&i_socket(iauth)) != -1) + iauth_disconnect(iauth); + /* Free memory. */ + MyFree(iauth); +} + +/** Close all %IAuth connections marked as closing. */ +void iauth_close_unused(void) +{ + struct IAuth *prev, *iauth, *next; + + for (prev = NULL, iauth = iauth_active; iauth; iauth = next) { + next = i_next(iauth); + if (i_GetClosing(iauth)) { + /* Update iauth_active linked list. */ + if (prev) + i_next(prev) = next; + else + iauth_active = next; + /* Close and destroy the connection. */ + iauth_close(iauth); + } else { + prev = iauth; + } + } +} + +/** Send a line to an %IAuth server. + * @param[in] iauth %Connection to send on. + * @param[in] format Format string for message. + */ +static void iauth_send(struct IAuth *iauth, const char *format, ...) +{ + va_list vl; + struct MsgBuf *mb; + + va_start(vl, format); + mb = msgq_vmake(0, format, vl); + va_end(vl); + msgq_add(&i_sendQ(iauth), mb, 0); + msgq_clean(mb); +} + +/** Report a protocol violation from the %IAuth server. + * @param[in] iauth %Connection that experienced the violation. + * @param[in] format Format string for message to operators. + */ +static void iauth_protocol_violation(struct IAuth *iauth, const char *format, ...) +{ + struct VarData vd; + assert(iauth != 0); + assert(format != 0); + vd.vd_format = format; + va_start(vd.vd_args, format); + sendwallto_group_butone(&me, WALL_DESYNCH, NULL, "IAuth protocol violation: %v", &vd); + va_end(vd.vd_args); +} + +/** Send on-connect burst to an %IAuth server. + * @param[in] iauth %Connection that has completed. + */ +static void iauth_on_connect(struct IAuth *iauth) +{ + struct IAuthRequest *iar; + if (EmptyString(i_passwd(iauth))) + iauth_send(iauth, "Server %s", cli_name(&me)); + else + iauth_send(iauth, "Server %s %s", cli_name(&me), i_passwd(iauth)); + if (i_GetIClass(iauth)) { + /* TODO: report local users to iauth */ + iauth_send(iauth, "EndUsers"); + } + i_SetConnected(iauth); + for (iar = i_list_head(iauth).iar_next; + iar != &i_list_head(iauth); + iar = iar->iar_next) + iauth_send_request(iauth, iar); + iauth_write(iauth); +} + +/** Complete disconnection of an %IAuth connection. + * @param[in] iauth %Connection to fully close. + */ +static void iauth_disconnect(struct IAuth *iauth) +{ + close(s_fd(&i_socket(iauth))); + socket_del(&i_socket(iauth)); + s_fd(&i_socket(iauth)) = -1; +} + +/** DNS completion callback for an %IAuth connection. + * @param[in] vptr Pointer to the IAuth struct. + * @param[in] he DNS reply parameters. + */ +static void iauth_dns_callback(void *vptr, struct DNSReply *he) +{ + struct IAuth *iauth = vptr; + if (!he) { + sendto_opmask_butone(0, SNO_OLDSNO, "IAuth connection to %s failed: host lookup failed", i_host(iauth)); + } else { + memcpy(&i_addr(iauth).addr, &he->addr, sizeof(i_addr(iauth).addr)); + if (!irc_in_addr_valid(&i_addr(iauth).addr)) { + sendto_opmask_butone(0, SNO_OLDSNO, "IAuth connection to %s failed: host came back as unresolved", i_host(iauth)); + return; + } + iauth_reconnect(iauth); + } +} + +/** Timer callback for reconnecting to %IAuth. + * @param[in] ev Timer event for reconnect. + */ +static void iauth_reconnect_ev(struct Event *ev) +{ + if (ev_type(ev) == ET_EXPIRE) + iauth_reconnect(t_data(ev_timer(ev))); +} + +/** Schedule a reconnection for \a iauth. + * @param[in] iauth %Connection that needs to be reconnected. + */ +static void iauth_schedule_reconnect(struct IAuth *iauth) +{ + struct Timer *timer; + assert(!t_active(&i_reconn_timer(iauth))); + timer = timer_init(&i_reconn_timer(iauth)); + timer_add(timer, iauth_reconnect_ev, iauth, TT_RELATIVE, i_reconnect(iauth)); +} + +/** Initiate a (re-)connection to \a iauth. + * @param[in] iauth %Connection that should be initiated. + */ +static void iauth_reconnect(struct IAuth *iauth) +{ + IOResult result; + int fd; + + Debug((DEBUG_INFO, "IAuth attempt connection to %s port %p.", i_host(iauth), i_port(iauth))); + if (!irc_in_addr_valid(&i_addr(iauth).addr) + && !ircd_aton(&i_addr(iauth).addr, i_host(iauth))) { + i_query(iauth).vptr = iauth; + i_query(iauth).callback = iauth_dns_callback; + gethost_byname(i_host(iauth), &i_query(iauth)); + return; + } + fd = os_socket(&VirtualHost, SOCK_STREAM, "IAuth"); + if (fd < 0) + return; + if (!os_set_sockbufs(fd, SERVER_TCP_WINDOW, SERVER_TCP_WINDOW)) { + close(fd); + sendto_opmask_butone(0, SNO_OLDSNO, "IAuth reconnect unable to set socket buffers: %s", strerror(errno)); + return; + } + result = os_connect_nonb(fd, &i_addr(iauth)); + if (result == IO_FAILURE) { + close(fd); + sendto_opmask_butone(0, SNO_OLDSNO, "IAuth reconnect unable to initiate connection: %s", strerror(errno)); + return; + } + if (!socket_add(&i_socket(iauth), iauth_sock_callback, iauth, + (result == IO_SUCCESS) ? SS_CONNECTED : SS_CONNECTING, + SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE, fd)) { + close(fd); + sendto_opmask_butone(0, SNO_OLDSNO, "IAuth reconnect unable to add socket: %s", strerror(errno)); + return; + } +} + +/** Read input from \a iauth. + * Reads up to SERVER_TCP_WINDOW bytes per pass. + * @param[in] iauth Readable connection. + */ +static void iauth_read(struct IAuth *iauth) +{ + char *src, *endp, *old_buffer, *argv[MAXPARA + 1]; + unsigned int length, argc, ii; + char readbuf[SERVER_TCP_WINDOW]; + + length = 0; + if (IO_FAILURE == os_recv_nonb(s_fd(&i_socket(iauth)), readbuf, sizeof(readbuf), &length)) + return; + i_recvB(iauth) += length; + if (i_recvB(iauth) > 1023) { + i_recvK(iauth) += i_recvB(iauth) >> 10; + i_recvB(iauth) &= 1023; + } + old_buffer = i_buffer(iauth); + endp = old_buffer + i_count(iauth); + for (src = readbuf; length > 0; --length) { + *endp = *src++; + if (IsEol(*endp)) { + /* Skip blank lines. */ + if (endp == old_buffer) + continue; + /* NUL-terminate line and split parameters. */ + *endp = '\0'; + for (argc = 0, endp = old_buffer; *endp && (argc < MAXPARA); ) { + while (*endp == ' ') + *endp++ = '\0'; + if (*endp == '\0') + break; + if (*endp == ':') + { + argv[argc++] = endp + 1; + break; + } + argv[argc++] = endp; + for (; *endp && *endp != ' '; ++endp) ; + } + argv[argc] = NULL; + /* Count line and reset endp to start of buffer. */ + i_recvM(iauth)++; + endp = old_buffer; + /* Look up command and try to dispatch. */ + if (argc > 0) { + for (ii = 0; iauth_cmdtab[ii].iac_name; ++ii) { + if (!ircd_strcmp(iauth_cmdtab[ii].iac_name, argv[0])) { + iauth_cmdtab[ii].iac_func(iauth, argc, argv); + if (i_GetAbort(iauth)) + iauth_disconnect(iauth); + break; + } + } + } + } + else if (endp < old_buffer + BUFSIZE) + endp++; + } + i_count(iauth) = endp - old_buffer; +} + +/** Send queued output to \a iauth. + * @param[in] iauth Writable connection with queued data. + */ +static void iauth_write(struct IAuth *iauth) +{ + unsigned int bytes_tried, bytes_sent; + IOResult iores; + + if (i_GetBlocked(iauth)) + return; + while (MsgQLength(&i_sendQ(iauth)) > 0) { + iores = os_sendv_nonb(s_fd(&i_socket(iauth)), &i_sendQ(iauth), &bytes_tried, &bytes_sent); + switch (iores) { + case IO_SUCCESS: + msgq_delete(&i_sendQ(iauth), bytes_sent); + i_sendB(iauth) += bytes_sent; + if (i_sendB(iauth) > 1023) { + i_sendK(iauth) += i_sendB(iauth) >> 10; + i_sendB(iauth) &= 1023; + } + if (bytes_tried == bytes_sent) + break; + /* If bytes_sent < bytes_tried, fall through to IO_BLOCKED. */ + case IO_BLOCKED: + i_SetBlocked(iauth); + socket_events(&i_socket(iauth), SOCK_ACTION_ADD | SOCK_EVENT_WRITABLE); + return; + case IO_FAILURE: + iauth_disconnect(iauth); + return; + } + } + /* We were able to flush all events, so remove notification. */ + socket_events(&i_socket(iauth), SOCK_ACTION_DEL | SOCK_EVENT_WRITABLE); +} + +/** Handle socket activity for an %IAuth connection. + * @param[in] ev &Socket event; the IAuth connection is the user data pointer for the socket. + */ +static void iauth_sock_callback(struct Event *ev) +{ + struct IAuth *iauth; + + assert(0 != ev_socket(ev)); + iauth = (struct IAuth*) s_data(ev_socket(ev)); + assert(0 != iauth); + + switch (ev_type(ev)) { + case ET_CONNECT: + socket_state(ev_socket(ev), SS_CONNECTED); + iauth_on_connect(iauth); + break; + case ET_DESTROY: + if (!i_GetClosing(iauth)) + iauth_schedule_reconnect(iauth); + break; + case ET_READ: + iauth_read(iauth); + break; + case ET_WRITE: + i_ClrBlocked(iauth); + iauth_write(iauth); + break; + case ET_EOF: + iauth_disconnect(iauth); + break; + case ET_ERROR: + sendto_opmask_butone(0, SNO_OLDSNO, "IAuth socket error: %s", strerror(ev_data(ev))); + log_write(LS_SOCKET, L_ERROR, 0, "IAuth socket error: %s", strerror(ev_data(ev))); + iauth_disconnect(iauth); + break; + default: + assert(0 && "Unrecognized event type"); + break; + } +} + +/* Functions related to IAuthRequest structs */ + +/** Handle timeout while waiting for a response. + * @param[in] ev Timer event that expired. + */ +static void iauth_request_ev(struct Event *ev) +{ + /* TODO: this could probably be more intelligent */ + if (ev_type(ev) == ET_EXPIRE) { + sendto_opmask_butone(0, SNO_OLDSNO, "IAuth request timed out; reconnecting"); + iauth_reconnect(t_data(ev_timer(ev))); + } +} + +/** Send a authorization request to an %IAuth server. + * @param[in] iauth %Connection to send request on. + * @param[in] iar Request to send. + */ +static void iauth_send_request(struct IAuth *iauth, struct IAuthRequest *iar) +{ + struct Client *client; + + /* If iauth is not connected, we must defer the request. */ + if (!i_GetConnected(iauth)) { + Debug((DEBUG_SEND, "IAuth deferring request for %s because we are not connected.", cli_name(iar->iar_client))); + return; + } + + /* If no timed request, set up expiration timer. */ + if (!t_active(&i_request_timer(iauth))) { + struct Timer *timer = timer_init(&i_request_timer(iauth)); + timer_add(timer, iauth_request_ev, iauth, TT_RELATIVE, i_timeout(iauth)); + iar->iar_timed = 1; + } else + iar->iar_timed = 0; + + /* Send the FullAuth request. */ + client = iar->iar_client; + assert(iar->iar_client != NULL); + iauth_send(iauth, "FullAuth %x %s %s %s %s %s :%s", + client, cli_name(client), cli_username(client), + cli_user(client)->host, cli_sock_ip(client), + cli_passwd(client), cli_info(client)); + + /* Write to the socket if we can. */ + iauth_write(iauth); +} + +/** Start independent authorization check for a client. + * @param[in] iauth %Connection to send request on. + * @param[in] cptr Client to check. + * @return Zero, or CPTR_KILLED in case of memory allocation failure. + */ +int iauth_start_client(struct IAuth *iauth, struct Client *cptr) +{ + struct IAuthRequest *iar; + + /* Allocate and initialize IAuthRequest struct. */ + if (!(iar = MyCalloc(1, sizeof(*iar)))) + return exit_client(cptr, cptr, &me, "IAuth memory allocation failed"); + iar->iar_next = &i_list_head(iauth); + iar->iar_prev = i_list_head(iauth).iar_prev; + iar->iar_client = cptr; + iar->iar_prev->iar_next = iar; + iar->iar_next->iar_prev = iar; + + /* Send request. */ + iauth_send_request(iauth, iar); + + return 0; +} + +/** Handle a client that is disconnecting. + * If there is a pending %IAuth request for the client, close it. + * @param[in] cptr Client that is disconnecting. + */ +void iauth_exit_client(struct Client *cptr) +{ + if (cli_iauth(cptr)) { + iauth_dispose_request(iauth_active, cli_iauth(cptr)); + cli_iauth(cptr) = NULL; + } else if (IsIAuthed(cptr) && i_GetIClass(iauth_active)) { + /* TODO: report quit to iauth */ + } +} + +/** Find pending request with a particular ID. + * @param[in] iauth %Connection context for the ID. + * @param[in] id Identifier to look up. + * @return IAuthRequest with that ID, or NULL. + */ +static struct IAuthRequest *iauth_find_request(struct IAuth *iauth, char *id) +{ + struct IAuthRequest *curr; + struct Client *target; + target = (struct Client*)strtoul(id, NULL, 16); + for (curr = i_list_head(iauth).iar_next; + curr != &i_list_head(iauth); + curr = curr->iar_next) { + assert(curr->iar_client != NULL); + if (target == curr->iar_client) + return curr; + } + return NULL; +} + +/** Unlink and free a request. + * @param[in] iauth Connection that owns the request. + * @param[in] iar Request to free. + */ +static void iauth_dispose_request(struct IAuth *iauth, struct IAuthRequest *iar) +{ + assert(iar->iar_client != NULL); + if (iar->iar_timed) + timer_del(&i_request_timer(iauth)); + cli_iauth(iar->iar_client) = NULL; + iar->iar_prev->iar_next = iar->iar_next; + iar->iar_next->iar_prev = iar->iar_prev; + MyFree(iar); +} + +/** Handle a DoneAuth response from %IAuth. + * THis means the client is authorized, so let them in. + * @param[in] iauth Connection that sent the message. + * @param[in] argc Argument count. + * @param[in] argv Argument list. + */ +static void iauth_cmd_doneauth(struct IAuth *iauth, int argc, char *argv[]) +{ + struct IAuthRequest *iar; + struct Client *client; + char *id; + char *username; + char *hostname; + char *c_class; +#if defined(UNDERNET) + char *account; +#endif + + if (argc < 5) { + iauth_protocol_violation(iauth, "Only %d parameters for DoneAuth (expected >=5)", argc); + return; + } + id = argv[1]; + username = argv[2]; + hostname = argv[3]; + c_class = argv[4]; +#if defined(UNDERNET) + account = (argc > 5) ? argv[5] : 0; +#endif + iar = iauth_find_request(iauth, id); + if (!iar) { + iauth_protocol_violation(iauth, "Got unexpected DoneAuth for id %s", id); + return; + } + client = iar->iar_client; + ircd_strncpy(cli_username(client), username, USERLEN); + ircd_strncpy(cli_user(client)->host, hostname, HOSTLEN); +#if defined(UNDERNET) + if (account) { + ircd_strncpy(cli_user(client)->account, account, ACCOUNTLEN); + SetAccount(client); + } +#endif + SetIAuthed(client); + iauth_dispose_request(iauth, iar); + register_user(client, client, cli_name(client), username); +} + +/** Handle a BadAuth response from %IAuth. + * This means the client is not authorized, so dump them. + * @param[in] iauth Connection that sent the message. + * @param[in] argc Argument count. + * @param[in] argv Argument list. + */ +static void iauth_cmd_badauth(struct IAuth *iauth, int argc, char *argv[]) +{ + struct IAuthRequest *iar; + struct Client *client; + char *id; + char *reason; + + if (argc < 3) { + iauth_protocol_violation(iauth, "Only %d parameters for BadAuth (expected >=3)", argc); + return; + } + id = argv[1]; + reason = argv[2]; + if (EmptyString(reason)) { + iauth_protocol_violation(iauth, "Empty BadAuth reason for id %s", id); + return; + } + iar = iauth_find_request(iauth, id); + if (!iar) { + iauth_protocol_violation(iauth, "Got unexpected BadAuth for id %s", id); + return; + } + client = iar->iar_client; + iauth_dispose_request(iauth, iar); + exit_client(client, client, &me, reason); +} Index: ircd-ircdev/ircd/ircd_crypt.c diff -u /dev/null ircd-ircdev/ircd/ircd_crypt.c:1.1 --- /dev/null Wed Nov 24 08:05:12 2004 +++ ircd-ircdev/ircd/ircd_crypt.c Wed Nov 24 08:05:00 2004 @@ -0,0 +1,241 @@ +/* + * IRC-Dev IRCD - An advanced and innovative IRC Daemon, ircd/ircd_crypt.c + * + * Copyright (C) 2002-2004 IRC-Dev Development Team <de...@ir...> + * Copyright (C) 2002 hikari + * + * 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/** + * @file + * @brief Core password encryption routines. + * @version $Id: ircd_crypt.c,v 1.1 2004/11/24 16:05:00 zolty Exp $ + * + * This is a new look crypto API for ircu, it can handle different + * password formats by the grace of magic tokens at the begining of the + * password e.g. $SMD5 for Salted MD5, $CRYPT for native crypt(), etc. + * + * Currently crypt routines are implemented for: the native crypt() + * function, Salted MD5 and a plain text mechanism which should only + * be used for testing. I intend to add Blowish, 3DES and possibly + * SHA1 support as well at some point, but I'll need to check the + * possible problems that'll cause with stupid crypto laws. + * + * It's also designed to be "ready" for the modularisation of ircu, so + * someone get round to doing it, because I'm not doing it ;) + * + * The plan for Stage B is to semi-modularise the authentication + * mechanism to allow authentication against some other sources than + * the conf file (whatever takes someones fancy, kerberos, ldap, sql, etc). + * + * -- blessed be, hikari. + */ +#include "config.h" +#include "ircd_crypt.h" +#include "ircd_alloc.h" +#include "ircd_features.h" +#include "ircd_string.h" +#include "s_debug.h" + +/* while we're not modular, we need their init functions */ +#include "ircd_crypt_native.h" +#include "ircd_crypt_plain.h" +#include "ircd_crypt_smd5.h" + +#include <assert.h> +#include <unistd.h> +#include <string.h> + +/* evil global */ +crypt_mechs_t* crypt_mechs_root; + +/** Add a crypt mechanism to the list + * @param mechanism Pointer to the mechanism details struct + * @return 0 on success, anything else on fail. + * + * This routine registers a new crypt mechanism in the loaded mechanisms list, + * making it availabe for comparing passwords. +*/ +int ircd_crypt_register_mech(crypt_mech_t* mechanism) +{ +crypt_mechs_t* crypt_mech; + + Debug((DEBUG_INFO, "ircd_crypt_register_mech: resistering mechanism: %s", mechanism->shortname)); + + /* try to allocate some memory for the new mechanism */ + if ((crypt_mech = (crypt_mechs_t*)MyMalloc(sizeof(crypt_mechs_t))) == NULL) + { + /* aww poot, we couldn't get any memory, scream a little then back out */ + Debug((DEBUG_MALLOC, "ircd_crypt_register_mech: could not allocate memory for %s", mechanism->shortname)); + return -1; + } + + /* ok, we have memory, initialise it */ + memset(crypt_mech, 0, sizeof(crypt_mechs_t)); + + /* assign the data */ + crypt_mech->mech = mechanism; + crypt_mech->next = crypt_mech->prev = NULL; + + /* first of all, is there anything there already? */ + if(crypt_mechs_root->next == NULL) + { + /* nope, just add ourself */ + crypt_mechs_root->next = crypt_mechs_root->prev = crypt_mech; + } else { + /* nice and simple, put ourself at the end */ + crypt_mech->prev = crypt_mechs_root->prev; + crypt_mech->next = NULL; + crypt_mechs_root->prev = crypt_mech->prev->next = crypt_mech; + } + + /* we're done */ + Debug((DEBUG_INFO, "ircd_crypt_register_mech: resistered mechanism: %s, crypt_function is at 0x%X.", crypt_mech->mech->shortname, &crypt_mech->mech->crypt_function)); + Debug((DEBUG_INFO, "ircd_crypt_register_mech: %s: %s", crypt_mech->mech->shortname, crypt_mech->mech->description)); + return 0; +} + +/** Remove a crypt mechanism from the list + * @param mechanism Pointer to the mechanism we want to remove + * @return 0 on success, anything else on fail. +*/ +int ircd_crypt_unregister_mech(crypt_mech_t* mechanism) +{ + +return 0; +} + +/** Wrapper for generating a hashed password passed on the supplied password + * @param key Pointer to the password we want crypted + * @param salt Pointer to the password we're comparing to (for the salt) + * @return Pointer to the generated password (must be MyFree()'d). + * + * This is a wrapper function which attempts to establish the password + * format and funnel it off to the correct mechanism handler function. The + * returned password is compared in the oper_password_match() routine. +*/ +char* ircd_crypt(const char* key, const char* salt) +{ +char *hashed_pass = NULL; +const char *temp_hashed_pass, *mysalt; +crypt_mechs_t* crypt_mech; + + assert(NULL != key); + assert(NULL != salt); + + Debug((DEBUG_DEBUG, "ircd_crypt: key is %s", key)); + Debug((DEBUG_DEBUG, "ircd_crypt: salt is %s", salt)); + + crypt_mech = crypt_mechs_root->next; + + /* by examining the first n characters of a password string we + * can discover what kind of password it is. hopefully. */ + for (;crypt_mech;) + { + if (strlen(salt) < crypt_mech->mech->crypt_token_size) + { + /* try the next mechanism instead */ + Debug((DEBUG_DEBUG, "ircd_crypt: salt is too short, will try next mech at 0x%X", crypt_mech->next)); + crypt_mech = crypt_mech->next; + continue; + } + + Debug((DEBUG_DEBUG, "ircd_crypt: comparing %s with %s", + salt, crypt_mech->mech->crypt_token)); + + if(0 == ircd_strncmp(crypt_mech->mech->crypt_token, salt, crypt_mech->mech->crypt_token_size)) + { + Debug((DEBUG_DEBUG, "ircd_crypt: type is %s", + crypt_mech->mech->shortname)); + + /* before we send this all off to the crypt_function, we need to remove + the tag from it */ + + /* make sure we won't end up with a password comprised entirely of + a single \0 */ + if(strlen(salt) < crypt_mech->mech->crypt_token_size + 1) + return NULL; + + mysalt = salt + crypt_mech->mech->crypt_token_size; + + if(NULL == (temp_hashed_pass = crypt_mech->mech->crypt_function(key, mysalt))) + return NULL; + + Debug((DEBUG_DEBUG, "ircd_crypt: untagged pass is %s", temp_hashed_pass)); + + /* ok, now we need to prefix the password we just got back + with the right tag */ + if(NULL == (hashed_pass = (char *)MyMalloc(sizeof(char)*strlen(temp_hashed_pass) + crypt_mech->mech->crypt_token_size + 1))) + { + Debug((DEBUG_MALLOC, "ircd_crypt: unable to allocate memory for temp_hashed_pass")); + return NULL; + } + memset(hashed_pass, 0, sizeof(char)*strlen(temp_hashed_pass) + +crypt_mech->mech->crypt_token_size + 1); + ircd_strncpy(hashed_pass, crypt_mech->mech->crypt_token, + crypt_mech->mech->crypt_token_size); + ircd_strncpy(hashed_pass + crypt_mech->mech->crypt_token_size, temp_hashed_pass, strlen(temp_hashed_pass)); + Debug((DEBUG_DEBUG, "ircd_crypt: tagged pass is %s", hashed_pass)); + } else { + Debug((DEBUG_DEBUG, "ircd_crypt: will try next mechansim at 0x%X", + crypt_mech->next)); + crypt_mech = crypt_mech->next; + continue; + } + return hashed_pass; + } + + /* try to use native crypt for an old-style (untagged) password */ + if (strlen(salt) > 2) + { + temp_hashed_pass = (char*)ircd_crypt_native(key, salt); + if (!ircd_strcmp(temp_hashed_pass, salt)) + return strdup(temp_hashed_pass); + } + + return NULL; +} + +/** Some basic init. + * This function loads initalises the crypt mechanisms linked list and + * currently loads the default mechanisms (Salted MD5, Crypt() and PLAIN). + * The last step is only needed while ircu is not properly modular. + * + * When ircu is modular this will be the entry function for the ircd_crypt + * module. + * +*/ +void ircd_crypt_init(void) +{ + + if((crypt_mechs_root = MyMalloc(sizeof(crypt_mechs_t))) == NULL) + { + /* awooga - can't allocate memory for the root structure */ + Debug((DEBUG_MALLOC, "init_crypt: Could not allocate memory for crypt_mechs_root")); + return; + } + + crypt_mechs_root->mech = NULL; + crypt_mechs_root->next = crypt_mechs_root->prev = NULL; + +/* temporary kludge until we're modular. manualy call the + register funtions for crypt mechanisms */ + ircd_register_crypt_smd5(); + ircd_register_crypt_plain(); + ircd_register_crypt_native(); + +return; +} Index: ircd-ircdev/ircd/ircd_crypt_native.c diff -u /dev/null ircd-ircdev/ircd/ircd_crypt_native.c:1.1 --- /dev/null Wed Nov 24 08:05:12 2004 +++ ircd-ircdev/ircd/ircd_crypt_native.c Wed Nov 24 08:05:00 2004 @@ -0,0 +1,88 @@ +/* + * IRC-Dev IRCD - An advanced and innovative IRC Daemon, ircd/ircd_crypt_native.c + * + * Copyright (C) 2002-2004 IRC-Dev Development Team <de...@ir...> + * Copyright (C) 1990-1991 Armin Gruner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/** + * @file + * @brief Native crypt() function routines + * @version $Id: ircd_crypt_native.c,v 1.1 2004/11/24 16:05:00 zolty Exp $ + * + * Routines for handling passwords encrypted with the system's native crypt() + * function (typicaly a DES encryption routine, but can be anything nowdays). + * + */ +#define _XOPEN_SOURCE +#define _XOPEN_VERSION 4 + +#include "config.h" +#include "ircd_crypt.h" +#include "ircd_crypt_native.h" +#include "s_debug.h" +#include "ircd_alloc.h" + +#include <assert.h> +#include <unistd.h> +#ifdef HAVE_CRYPT_H +#include <crypt.h> +#endif + +/** Simple routine that just calls crypt() with the supplied password and salt + * @param key The password we're encrypting. + * @param salt The salt we're using to encrypt key + * @return The encrypted password. + * + * Well this bit is (kinda) intact from the original oper password routines :) + * It's a very simple wrapper routine that just calls crypt and returns the + * result. + * -- hikari + */ +const char* ircd_crypt_native(const char* key, const char* salt) +{ + assert(NULL != key); + assert(NULL != salt); + + Debug((DEBUG_DEBUG, "ircd_crypt_native: key is %s", key)); + Debug((DEBUG_DEBUG, "ircd_crypt_native: salt is %s", salt)); + + return (const char*)crypt(key, salt); +} + +/* register ourself with the list of crypt mechanisms -- hikari */ +void ircd_register_crypt_native(void) +{ +crypt_mech_t* crypt_mech; + + if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL) + { + Debug((DEBUG_MALLOC, "Could not allocate space for crypt_native")); + return; + } + + crypt_mech->mechname = "native"; + crypt_mech->shortname = "crypt_native"; + crypt_mech->description = "System native crypt() function mechanism."; + crypt_mech->crypt_function = &ircd_crypt_native; + crypt_mech->crypt_token = "$CRYPT$"; + crypt_mech->crypt_token_size = 7; + + ircd_crypt_register_mech(crypt_mech); + +return; +} Index: ircd-ircdev/ircd/ircd_crypt_plain.c diff -u /dev/null ircd-ircdev/ircd/ircd_crypt_plain.c:1.1 --- /dev/null Wed Nov 24 08:05:12 2004 +++ ircd-ircdev/ircd/ircd_crypt_plain.c Wed Nov 24 08:05:00 2004 @@ -0,0 +1,86 @@ +/* + * IRC-Dev IRCD - An advanced and innovative IRC Daemon, ircd/ircd_crypt_plain.c + * + * Copyright (C) 2002-2004 IRC-Dev Development Team <de...@ir...> + * Copyright (C) 2002 hikari + * + * 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/** + * @file + * @brief Routines for PLAIN passwords. + * @version $Id: ircd_crypt_plain.c,v 1.1 2004/11/24 16:05:00 zolty Exp $ + * + * PLAIN text encryption. Oxymoron and a half that. + */ +#include "config.h" +#include "ircd_crypt.h" +#include "ircd_crypt_plain.h" +#include "s_debug.h" +#include "ircd_alloc.h" + +#include <assert.h> +#include <unistd.h> + +/** Just sends back the supplied password. + * @param key The password + * @param salt The salt + * @return The password + * + * Yes I know it's an oxymoron, but still, it's handy for testing. + * + * What you need more help with seeing what this does? + * + */ +const char* ircd_crypt_plain(const char* key, const char* salt) +{ + assert(NULL != salt); + assert(NULL != key); + + Debug((DEBUG_DEBUG, "ircd_crypt_plain: key is %s", key)); + Debug((DEBUG_DEBUG, "ircd_crypt_plain: salt is %s", salt)); + + /* yes, that's it. we just send key back out again, + pointless I know */ + return key; +} + +/** register ourself with the list of crypt mechanisms + * Registers the PLAIN mechanism in the list of available crypt mechanisms. + * When we're modular this will be the entry function for the module. + * + * -- hikari */ +void ircd_register_crypt_plain(void) +{ +crypt_mech_t* crypt_mech; + + if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL) + { + Debug((DEBUG_MALLOC, "Could not allocate space for crypt_plain")); + return; + } + + crypt_mech->mechname = "plain"; + crypt_mech->shortname = "crypt_plain"; + crypt_mech->description = "Plain text \"crypt\" mechanism."; + crypt_mech->crypt_function = &ircd_crypt_plain; + crypt_mech->crypt_token = "$PLAIN$"; + crypt_mech->crypt_token_size = 7; + + ircd_crypt_register_mech(crypt_mech); + +return; +} Index: ircd-ircdev/ircd/ircd_crypt_smd5.c diff -u /dev/null ircd-ircdev/ircd/ircd_crypt_smd5.c:1.1 --- /dev/null Wed Nov 24 08:05:14 2004 +++ ircd-ircdev/ircd/ircd_crypt_smd5.c Wed Nov 24 08:05:00 2004 @@ -0,0 +1,234 @@ +/* + * IRC-Dev IRCD - An advanced and innovative IRC Daemon, ircd/ircd_crypt_smd5.c + * + * Copyright (C) 2002-2004 IRC-Dev Development Team <de...@ir...> + * Copyright (C) 2002 hikari + * + * 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +/** + * @file + * @brief Routines for Salted MD5 passwords + * @version $Id: ircd_crypt_smd5.c,v 1.1 2004/11/24 16:05:00 zolty Exp $ + * + * ircd_crypt_smd5 is largely taken from md5_crypt.c from the Linux PAM + * source code. it's been modified to fit in with ircu and some of the + * undeeded code has been removed. the source file md5_crypt.c has the + * following licence, so if any of our opers or admins are in Denmark + * they better go buy them a drink ;) -- hikari + * + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * <ph...@lo...> wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + */ +#include "config.h" +#include "ircd_crypt.h" +#include "ircd_crypt_smd5.h" +#include "ircd_md5.h" +#include "s_debug.h" +#include "ircd_alloc.h" + +#include <assert.h> +#include <string.h> +#include <unistd.h> + +static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */ +"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + +/** Converts a binary value into a BASE64 encoded string. + * @param s Pointer to the output string + * @param v The unsigned long we're working on + * @param n The number of bytes we're working with + * + * This is used to produce the normal MD5 hash everyone is familar with. + * It takes the value v and converts n bytes of it it into an ASCII string in + * 6-bit chunks, the resulting string is put at the address pointed to by s. + * + */ +static void to64(char *s, unsigned long v, int n) +{ + while (--n >= 0) { + *s++ = itoa64[v & 0x3f]; + v >>= 6; + } +} + +/** Produces a Salted MD5 crypt of a password using the supplied salt + * @param key The password we're encrypting + * @param salt The salt we're using to encrypt it + * @return The Salted MD5 password of key and salt + * + * Erm does exactly what the brief comment says. If you think I'm writing a + * description of how MD5 works, you have another thing comming. Go and read + * Applied Cryptopgraphy by Bruce Schneier. The only difference is we use a + * salt at the begining of the password to perturb it so that the same password + * doesn't always produce the same hash. + * + */ +const char* ircd_crypt_smd5(const char* key, const char* salt) +{ +const char *magic = "$1$"; +static char passwd[120]; +char *p; +const char *sp, *ep; +unsigned char final[16]; +int sl, pl, i, j; +MD5_CTX ctx, ctx1; +unsigned long l; + + assert(NULL != key); + assert(NULL != salt); + + Debug((DEBUG_DEBUG, "ircd_crypt_smd5: key = %s", key)); + Debug((DEBUG_DEBUG, "ircd_crypt_smd5: salt = %s", salt)); + + /* Refine the Salt first */ + ep = sp = salt; + + for (ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++) + continue; + + /* get the length of the true salt */ + sl = ep - sp; + + MD5Init(&ctx); + + /* The password first, since that is what is most unknown */ + MD5Update(&ctx,(unsigned const char *)key,strlen(key)); + + /* Then our magic string */ + MD5Update(&ctx,(unsigned const char *)magic,strlen(magic)); + + /* Then the raw salt */ + MD5Update(&ctx,(unsigned const char *)sp,sl); + + /* Then just as many characters of the MD5(key,salt,key) */ + MD5Init(&ctx1); + MD5Update(&ctx1,(unsigned const char *)key,strlen(key)); + MD5Update(&ctx1,(unsigned const char *)sp,sl); + MD5Update(&ctx1,(unsigned const char *)key,strlen(key)); + MD5Final(final,&ctx1); + for (pl = strlen(key); pl > 0; pl -= 16) + MD5Update(&ctx,(unsigned const char *)final,pl>16 ? 16 : pl); + + /* Don't leave anything around in vm they could use. */ + memset(final, 0, sizeof final); + + /* Then something really weird... */ + for (j = 0, i = strlen(key); i; i >>= 1) + if (i & 1) + MD5Update(&ctx, (unsigned const char *)final+j, 1); + else + MD5Update(&ctx, (unsigned const char *)key+j, 1); + + /* Now make the output string. */ + memset(passwd, 0, 120); + strncpy(passwd, sp, sl); + strcat(passwd, "$"); + + MD5Final(final,&ctx); + + /* + * and now, just to make sure things don't run too fast + * On a 60 Mhz Pentium this takes 34 msec, so you would + * need 30 seconds to build a 1000 entry dictionary... + */ + for (i = 0; i < 1000; i++) { + MD5Init(&ctx1); + + if (i & 1) + MD5Update(&ctx1,(unsigned const char *)key,strlen(key)); + else + MD5Update(&ctx1,(unsigned const char *)final,16); + + if (i % 3) + MD5Update(&ctx1,(unsigned const char *)sp,sl); + + if (i % 7) + MD5Update(&ctx1,(unsigned const char *)key,strlen(key)); + + if (i & 1) + MD5Update(&ctx1,(unsigned const char *)final,16); + else + MD5Update(&ctx1,(unsigned const char *)key,strlen(key)); + + MD5Final(final,&ctx1); + } + + p = passwd + strlen(passwd); + + Debug((DEBUG_DEBUG, "passwd = %s", passwd)); + + /* Turn the encrypted binary data into a BASE64 encoded string we can read + * and display -- hikari */ + l = (final[0] << 16) | (final[6] << 8) | final[12]; + to64(p, l, 4); + p += 4; + l = (final[1] << 16) | (final[7] << 8) | final[13]; + to64(p, l, 4); + p += 4; + l = (final[2] << 16) | (final[8] << 8) | final[14]; + to64(p, l, 4); + p += 4; + l = (final[3] << 16) | (final[9] << 8) | final[15]; + to64(p, l, 4); + p += 4; + l = (final[4] << 16) | (final[10] << 8) | final[5]; + to64(p, l, 4); + p += 4; + l = final[11]; + to64(p, l, 2); + p += 2; + *p = '\0'; + + /* Don't leave anything around in vm they could use. */ + memset(final, 0, sizeof final); + +return passwd; +} + +/* end borrowed code */ + +/** Register ourself with the list of crypt mechanisms + * Registers the SMD5 mechanism in the list of available crypt mechanisms. When + * we're modular this will be the entry function for the module. + * + */ +void ircd_register_crypt_smd5(void) +{ +crypt_mech_t* crypt_mech; + + if ((crypt_mech = (crypt_mech_t*)MyMalloc(sizeof(crypt_mech_t))) == NULL) + { + Debug((DEBUG_MALLOC, "Could not allocate space for crypt_smd5")); + return; + } + + crypt_mech->mechname = "smd5"; + crypt_mech->shortname = "crypt_smd5"; + crypt_mech->description = "Salted MD5 password hash mechanism."; + crypt_mech->crypt_function = &ircd_crypt_smd5; + crypt_mech->crypt_token = "$SMD5$"; + crypt_mech->crypt_token_size = 6 ; + + ircd_crypt_register_mech(crypt_mech); + +return; +} Index: ircd-ircdev/ircd/ircd_events.c diff -u ircd-ircdev/ircd/ircd_events.c:1.3 ircd-ircdev/ircd/ircd_events.c:1.4 --- ircd-ircdev/ircd/ircd_events.c:1.3 Sun Feb 22 08:11:42 2004 +++ ircd-ircdev/ircd/ircd_events.c Wed Nov 24 08:05:00 2004 @@ -18,8 +18,10 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - * $Id: ircd_events.c,v 1.3 2004/02/22 16:11:42 zolty Exp $ - * + */ +/** @file + * @brief Implementation of event loop mid-layer. + * @version $Id: ircd_events.c,v 1.4 2004/11/24 16:05:00 zolty Exp $ */ #include "config.h" @@ -36,13 +38,14 @@ #include <stdlib.h> #include <unistd.h> -#define SIGS_PER_SOCK 10 /* number of signals to process per socket +#define SIGS_PER_SOCK 10 /**< number of signals to process per socket readable event */ #ifdef USE_KQUEUE extern struct Engine engine_kqueue; #define ENGINE_KQUEUE &engine_kqueue, #else +/** Address of kqueue engine (if used). */ #define ENGINE_KQUEUE #endif /* USE_KQUEUE */ @@ -50,6 +53,7 @@ extern struct Engine engine_devpoll; #define ENGINE_DEVPOLL &engine_devpoll, #else +/** Address of /dev/poll engine (if used). */ #define ENGINE_DEVPOLL #endif /* USE_DEVPOLL */ @@ -57,18 +61,21 @@ extern struct Engine engine_epoll; #define ENGINE_EPOLL &engine_epoll, #else +/** Address of epoll engine (if used). */ #define ENGINE_EPOLL #endif /* USE_EPOLL */ #ifdef USE_POLL extern struct Engine engine_poll; +/** Address of fallback (poll) engine. */ #define ENGINE_FALLBACK &engine_poll, #else extern struct Engine engine_select; +/** Address of fallback (select) engine. */ #define ENGINE_FALLBACK &engine_select, #endif /* USE_POLL */ -/* list of engines to try */ +/** list of engines to try */ static const struct Engine *evEngines[] = { ENGINE_KQUEUE ENGINE_EPOLL @@ -77,22 +84,25 @@ 0 }; -/* signal routines pipe data */ +/** Signal routines pipe data. + * This is used if an engine does not implement signal handling itself + * (when Engine::eng_signal is NULL). + */ static struct { - int fd; /* signal routine's fd */ - struct Socket sock; /* and its struct Socket */ + int fd; /**< signal routine's fd */ + struct Socket sock; /**< and its struct Socket */ } sigInfo = { -1 }; -/* All the thread info */ +/** All the thread info */ static struct { - struct Generators gens; /* List of all generators */ - struct Event* events_free; /* struct Event free list */ - unsigned int events_alloc; /* count of allocated struct Events */ - const struct Engine* engine; /* core engine being used */ + struct Generators gens; /**< List of all generators */ + struct Event* events_free; /**< struct Event free list */ + unsigned int events_alloc; /**< count of allocated struct Events */ + const struct Engine* engine; /**< core engine being used */ #ifdef IRCD_THREADED - struct GenHeader* genq_head; /* head of generator event queue */ - struct GenHeader* genq_tail; /* tail of generator event queue */ - unsigned int genq_count; /* count of generators on queue */ + struct GenHeader* genq_head; /**< head of generator event queue */ + struct GenHeader* genq_tail; /**< tail of generator event queue */ + unsigned int genq_count; /**< count of generators on queue */ #en... [truncated message content] |