diff -urN ircd-hybrid-6.0.2/README.challengeresponse ircd-hybrid-6.0.2+cr/README.challengeresponse
--- ircd-hybrid-6.0.2/README.challengeresponse	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0.2+cr/README.challengeresponse	Wed Apr 11 00:32:27 2001
@@ -0,0 +1,24 @@
+ircd-hybrid-6 Challenge/Response link patch.
+
+This patch modifies hybrid 6 to authenticate server links using challenge-
+response rather than simple PASS. It will, when linking, generate a random
+8 byte challenge, and expect a MD5 hash of this challenge and the link
+password passed back. It will allow fallback to standard PASS authentication
+if this is defined in config.h.
+
+To enable the patch, add
+  #define CHALLENGERESPONSE
+in config.h
+
+To allow fallback to PASS, add
+  #define CHALLENGERESPONSE_FALLBACK
+  #define CHALLENGERESPONSE_EXPIRY  30
+also in config.h
+
+The CHALLENGERESPONSE_EXPIRY is the number of seconds from a connecting server
+sends CHALL until it gives up waiting for the other end and reverts to PASS.
+
+Idea and logics by ievil & einride
+Implemented by einride
+Verified by ???
+
diff -urN ircd-hybrid-6.0.2/include/client.h ircd-hybrid-6.0.2+cr/include/client.h
--- ircd-hybrid-6.0.2/include/client.h	Fri Dec  1 07:28:46 2000
+++ ircd-hybrid-6.0.2+cr/include/client.h	Wed Apr 11 00:32:27 2001
@@ -314,6 +314,11 @@
 #define FLAGS_SENDQEX      0x0800 /* Sendq exceeded */
 #define FLAGS_IPHASH       0x1000 /* iphashed this client */
 
+#ifdef CHALLENGERESPONSE
+#define FLAGS_CHALLENGED   0x2000 /* sent a CHALL, accept RESP from this one */
+#define FLAGS_RESPONDED    0x4000 /* sent a RESP */
+#endif
+
 /* umodes, settable flags */
 #define FLAGS_SERVNOTICE   0x0001 /* server notices such as kill */
 #define FLAGS_CCONN        0x0002 /* Client Connections */
@@ -404,6 +409,13 @@
 #define ClearAccess(x)          ((x)->flags &= ~FLAGS_CHKACCESS)
 #define MyConnect(x)            ((x)->local_flag != 0)
 #define MyClient(x)             (MyConnect(x) && IsClient(x))
+
+#ifdef CHALLENGERESPONSE
+#define Challenged(x)           ((x)->flags & FLAGS_CHALLENGED)
+#define SetChallenged(x)        ((x)->flags |= FLAGS_CHALLENGED)
+#define Responded(x)            ((x)->flags & FLAGS_RESPONDED)
+#define SetResponded(x)         ((x)->flags |= FLAGS_RESPONDED)
+#endif
 
 /* oper flags */
 #define MyOper(x)               (MyConnect(x) && IsOper(x))
diff -urN ircd-hybrid-6.0.2/include/config.h ircd-hybrid-6.0.2+cr/include/config.h
--- ircd-hybrid-6.0.2/include/config.h	Mon Feb 19 05:47:00 2001
+++ ircd-hybrid-6.0.2+cr/include/config.h	Wed Apr 11 00:32:27 2001
@@ -39,6 +39,29 @@
  *
  */
 
+
+/* Challenge/Response patch v1
+ * 
+ * Challenge & Response makes the server link authentication use an
+ * md5 based hash to securly auhtenticate with the remote server.
+ *
+ * The C/N lines passwords are used to generate the hashes used and it 
+ * is adviceable to use a diffrent pass for C and N.
+ *
+ * To allow fallback to PASS, add
+ *  #define CHALLENGERESPONSE_FALLBACK
+ *  #define CHALLENGERESPONSE_EXPIRY  30
+ *
+ * CHALLENGERESPONSE_EXPIRY is defined in seconds.
+ *
+ */
+
+#define CHALLENGERESPONSE
+#undef CHALLENGERESPONSE_FALLBACK
+#define CHALLENGERESPONSE_EXPIRY 15
+
+
+
 /***************** MAKE SURE THIS IS CORRECT!!!!!!!!! **************/
 /* ONLY EDIT "HARD_FDLIMIT_" and "INIT_MAXCLIENTS" */
 
diff -urN ircd-hybrid-6.0.2/include/m_commands.h ircd-hybrid-6.0.2+cr/include/m_commands.h
--- ircd-hybrid-6.0.2/include/m_commands.h	Sat Jul 31 04:44:44 1999
+++ ircd-hybrid-6.0.2+cr/include/m_commands.h	Wed Apr 11 00:32:27 2001
@@ -98,4 +98,8 @@
 extern int m_htm(struct Client *,struct Client *,int,char **);
 extern int m_set(struct Client *,struct Client *,int,char **);
 
+#ifdef CHALLENGERESPONSE
+extern int m_chall(struct Client *,struct Client *,int,char **);
+extern int m_resp(struct Client *,struct Client *,int,char **);
+#endif
 #endif /* INCLUDED_m_commands_h */
diff -urN ircd-hybrid-6.0.2/include/md5.h ircd-hybrid-6.0.2+cr/include/md5.h
--- ircd-hybrid-6.0.2/include/md5.h	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0.2+cr/include/md5.h	Wed Apr 11 00:32:27 2001
@@ -0,0 +1,48 @@
+/* 
+ * md5.h
+ *   header file for md5c.c
+ */
+/* 
+ * Copyright (C) 1991, 1992  RSA Data Security, Inc.
+ * Created 1991.
+ * All rights reserved.
+ * 
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ * 
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ * 
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * 
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#ifndef INCLUDED_md5_h
+#define INCLUDED_md5_h
+
+typedef unsigned int u_32bit_t;
+typedef unsigned char *POINTER;
+typedef u_32bit_t UINT4;
+
+/* MD5 context. */
+typedef struct {
+  UINT4 state[4];                                   /* state (ABCD) */
+  UINT4 count[2];        /* number of bits, modulo 2^64 (lsb first) */
+  unsigned char buffer[64];                         /* input buffer */
+} MD5_CTX;
+
+
+void MD5Init (MD5_CTX * context);
+void MD5Update (MD5_CTX * context, unsigned char * input, unsigned int inputLen);
+void MD5Final (unsigned char * digest, MD5_CTX * context);
+
+#endif
diff -urN ircd-hybrid-6.0.2/include/msg.h ircd-hybrid-6.0.2+cr/include/msg.h
--- ircd-hybrid-6.0.2/include/msg.h	Thu Nov  9 04:46:52 2000
+++ ircd-hybrid-6.0.2+cr/include/msg.h	Wed Apr 11 00:32:27 2001
@@ -120,6 +120,10 @@
 
 #define MSG_GLINE    "GLINE"    /* GLINE */
 
+#ifdef CHALLENGERESPONSE
+#define MSG_CHALL    "CHALL"    /* CHALL */
+#define MSG_RESP     "RESP"     /* RESP */
+#endif
 
 #define MSG_LOCOPS   "LOCOPS"   /* LOCOPS */
 #ifdef LWALLOPS
@@ -217,6 +221,10 @@
 #ifdef LTRACE
   { MSG_LTRACE,  m_ltrace,   0, MAXPARA, 1, 0, 0, 0L },
 #endif /* LTRACE */
+#ifdef CHALLENGERESPONSE
+  { MSG_CHALL,   m_chall,    0, MAXPARA, 1, 1, 0, 0L },  
+  { MSG_RESP,    m_resp,     0, MAXPARA, 1, 1, 0, 0L },
+#endif
   { MSG_PASS,    m_pass,     0, MAXPARA, 1, 1, 0, 0L },
   { MSG_LUSERS,  m_lusers,   0, MAXPARA, 1, 0, 0, 0L },
   { MSG_TIME,    m_time,     0, MAXPARA, 1, 0, 0, 0L },
diff -urN ircd-hybrid-6.0.2/include/msg.h~ ircd-hybrid-6.0.2+cr/include/msg.h~
--- ircd-hybrid-6.0.2/include/msg.h~	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0.2+cr/include/msg.h~	Wed Apr 11 00:32:27 2001
@@ -0,0 +1,261 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/msg.h
+ *   Copyright (C) 1990 Jarkko Oikarinen and
+ *                      University of Oulu, Computing Center
+ *
+ *   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: msg.h,v 1.14 2000/11/09 03:46:52 lusky Exp $
+ */
+#ifndef INCLUDED_msg_h
+#define INCLUDED_msg_h
+#ifndef INCLUDED_config_h
+#include "config.h"
+#endif
+
+struct Client;
+
+/* 
+ * Message table structure 
+ */
+struct  Message
+{
+  char  *cmd;
+  int   (* func)();
+  unsigned int  count;                  /* number of times command used */
+  int   parameters;
+  char  flags;
+  /* bit 0 set means that this command is allowed to be used
+   * only on the average of once per 2 seconds -SRB */
+
+  /* I could have defined other bit maps to above instead of the next two
+     flags that I added. so sue me. -Dianora */
+
+  char    allow_unregistered_use;       /* flag if this command can be
+                                           used if unregistered */
+
+  char    reset_idle;                   /* flag if this command causes
+                                           idle time to be reset */
+  unsigned long bytes;
+};
+
+struct MessageTree
+{
+  char*               final;
+  struct Message*     msg;
+  struct MessageTree* pointers[26];
+}; 
+
+typedef struct MessageTree MESSAGE_TREE;
+
+
+#define MSG_PRIVATE  "PRIVMSG"  /* PRIV */
+#define MSG_WHO      "WHO"      /* WHO  -> WHOC */
+#define MSG_WHOIS    "WHOIS"    /* WHOI */
+#define MSG_WHOWAS   "WHOWAS"   /* WHOW */
+#define MSG_USER     "USER"     /* USER */
+#define MSG_NICK     "NICK"     /* NICK */
+#define MSG_SERVER   "SERVER"   /* SERV */
+#define MSG_LIST     "LIST"     /* LIST */
+#define MSG_TOPIC    "TOPIC"    /* TOPI */
+#define MSG_INVITE   "INVITE"   /* INVI */
+#define MSG_VERSION  "VERSION"  /* VERS */
+#define MSG_QUIT     "QUIT"     /* QUIT */
+#define MSG_SQUIT    "SQUIT"    /* SQUI */
+#define MSG_KILL     "KILL"     /* KILL */
+#define MSG_INFO     "INFO"     /* INFO */
+#define MSG_LINKS    "LINKS"    /* LINK */
+#define MSG_STATS    "STATS"    /* STAT */
+#define MSG_USERS    "USERS"    /* USER -> USRS */
+#define MSG_HELP     "HELP"     /* HELP */
+#define MSG_ERROR    "ERROR"    /* ERRO */
+#define MSG_AWAY     "AWAY"     /* AWAY */
+#define MSG_CONNECT  "CONNECT"  /* CONN */
+#define MSG_PING     "PING"     /* PING */
+#define MSG_PONG     "PONG"     /* PONG */
+#define MSG_OPER     "OPER"     /* OPER */
+#define MSG_PASS     "PASS"     /* PASS */
+#define MSG_WALLOPS  "WALLOPS"  /* WALL */
+#define MSG_TIME     "TIME"     /* TIME */
+#define MSG_NAMES    "NAMES"    /* NAME */
+#define MSG_ADMIN    "ADMIN"    /* ADMI */
+#define MSG_TRACE    "TRACE"    /* TRAC */
+#define MSG_LTRACE   "LTRACE"   /* LTRA */
+#define MSG_NOTICE   "NOTICE"   /* NOTI */
+#define MSG_JOIN     "JOIN"     /* JOIN */
+#define MSG_PART     "PART"     /* PART */
+#define MSG_LUSERS   "LUSERS"   /* LUSE */
+#define MSG_MOTD     "MOTD"     /* MOTD */
+#define MSG_MODE     "MODE"     /* MODE */
+#define MSG_KICK     "KICK"     /* KICK */
+#define MSG_USERHOST "USERHOST" /* USER -> USRH */
+#define MSG_ISON     "ISON"     /* ISON */
+#define MSG_REHASH   "REHASH"   /* REHA */
+#define MSG_RESTART  "RESTART"  /* REST */
+#define MSG_CLOSE    "CLOSE"    /* CLOS */
+#define MSG_SVINFO   "SVINFO"   /* SVINFO */
+#define MSG_SJOIN    "SJOIN"    /* SJOIN */
+#define MSG_CAPAB    "CAPAB"    /* CAPAB */
+#define MSG_DIE      "DIE"      /* DIE */
+#define MSG_HASH     "HASH"     /* HASH */
+#define MSG_DNS      "DNS"      /* DNS  -> DNSS */
+#define MSG_OPERWALL "OPERWALL" /* OPERWALL */
+#define MSG_KLINE    "KLINE"    /* KLINE */
+#define MSG_UNKLINE  "UNKLINE"  /* UNKLINE */
+#define MSG_DLINE    "DLINE"    /* DLINE */
+#define MSG_HTM      "HTM"      /* HTM */
+#define MSG_SET      "SET"      /* SET */
+
+#define MSG_GLINE    "GLINE"    /* GLINE */
+
+
+#define MSG_LOCOPS   "LOCOPS"   /* LOCOPS */
+#ifdef LWALLOPS
+#define MSG_LWALLOPS "LWALLOPS" /* Same as LOCOPS */
+#endif /* LWALLOPS */
+#define MSG_KNOCK          "KNOCK"  /* KNOCK */
+
+#define MAXPARA    15 
+
+#define MSG_TESTLINE "TESTLINE"
+
+#ifdef MSGTAB
+#ifndef INCLUDED_m_commands_h
+#include "m_commands.h"       /* m_xxx */
+#endif
+struct Message msgtab[] = {
+#ifdef IDLE_FROM_MSG    /* reset idle time only if privmsg used */
+#ifdef IDLE_CHECK       /* reset idle time only if valid target for privmsg
+                           and target is not source */
+
+  /*                                        |-- allow use even when unreg.
+                                            v   yes/no                  */
+  { MSG_PRIVATE, m_private,  0, MAXPARA, 1, 0, 0, 0L },
+#else
+  { MSG_PRIVATE, m_private,  0, MAXPARA, 1, 0, 1, 0L },
+#endif
+
+  /*                                           ^
+                                               |__ reset idle time when 1 */
+#else   /* IDLE_FROM_MSG */
+#ifdef  IDLE_CHECK      /* reset idle time on anything but privmsg */
+  { MSG_PRIVATE, m_private,  0, MAXPARA, 1, 0, 1, 0L },
+#else
+  { MSG_PRIVATE, m_private,  0, MAXPARA, 1, 0, 0, 0L },
+  /*                                           ^
+                                               |__ reset idle time when 0 */
+#endif  /* IDLE_CHECK */
+#endif  /* IDLE_FROM_MSG */
+
+  { MSG_NICK,    m_nick,     0, MAXPARA, 1, 1, 0, 0L },
+  { MSG_NOTICE,  m_notice,   0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_JOIN,    m_join,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_MODE,    m_mode,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_QUIT,    m_quit,     0, MAXPARA, 1, 1, 0, 0L },
+  { MSG_PART,    m_part,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_KNOCK,   m_knock,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_TOPIC,   m_topic,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_INVITE,  m_invite,   0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_KICK,    m_kick,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_WALLOPS, m_wallops,  0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_LOCOPS,  m_locops,   0, MAXPARA, 1, 0, 0, 0L },
+#ifdef LWALLOPS
+  { MSG_LWALLOPS,m_locops,   0, MAXPARA, 1, 0, 0, 0L },
+#endif /* LWALLOPS */
+
+#ifdef IDLE_FROM_MSG
+
+  /* Only m_private has reset idle flag set */
+  { MSG_PONG,    m_pong,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_PING,    m_ping,     0, MAXPARA, 1, 0, 0, 0L },
+
+#else
+
+  /* else for IDLE_FROM_MSG */
+  /* reset idle flag sense is reversed, only reset idle time
+   * when its 0, for IDLE_FROM_MSG ping/pong do not reset idle time
+   */
+
+  { MSG_PONG,    m_pong,     0, MAXPARA, 1, 0, 1, 0L },
+  { MSG_PING,    m_ping,     0, MAXPARA, 1, 0, 1, 0L },
+
+#endif  /* IDLE_FROM_MSG */
+
+  { MSG_ERROR,   m_error,    0, MAXPARA, 1, 1, 0, 0L },
+  { MSG_KILL,    m_kill,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_USER,    m_user,     0, MAXPARA, 1, 1, 0, 0L },
+  { MSG_AWAY,    m_away,     0, MAXPARA, 1, 0, 0, 0L },
+#ifdef IDLE_FROM_MSG
+  { MSG_ISON,    m_ison,     0, 1,       1, 0, 0, 0L },
+#else
+  /* ISON should not reset idle time ever
+   * remember idle flag sense is reversed when IDLE_FROM_MSG is undefined
+   */
+  { MSG_ISON,    m_ison,     0, 1,       1, 0, 1, 0L },
+#endif /* !IDLE_FROM_MSG */
+  { MSG_SERVER,  m_server,   0, MAXPARA, 1, 1, 0, 0L },
+  { MSG_SQUIT,   m_squit,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_WHOIS,   m_whois,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_WHO,     m_who,      0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_WHOWAS,  m_whowas,   0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_LIST,    m_list,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_NAMES,   m_names,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_USERHOST,m_userhost, 0, 1,       1, 0, 0, 0L },
+  { MSG_TRACE,   m_trace,    0, MAXPARA, 1, 0, 0, 0L },
+#ifdef LTRACE
+  { MSG_LTRACE,  m_ltrace,   0, MAXPARA, 1, 0, 0, 0L },
+#endif /* LTRACE */
+  { MSG_PASS,    m_pass,     0, MAXPARA, 1, 1, 0, 0L },
+  { MSG_LUSERS,  m_lusers,   0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_TIME,    m_time,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_OPER,    m_oper,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_CONNECT, m_connect,  0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_VERSION, m_version,  0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_STATS,   m_stats,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_LINKS,   m_links,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_ADMIN,   m_admin,    0, MAXPARA, 1, 1, 0, 0L },
+  { MSG_USERS,   m_users,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_HELP,    m_help,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_INFO,    m_info,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_MOTD,    m_motd,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_SVINFO,  m_svinfo,   0, MAXPARA, 1, 1, 0, 0L },
+  { MSG_SJOIN,   m_sjoin,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_CAPAB,   m_capab,    0, MAXPARA, 1, 1, 0, 0L },
+  { MSG_OPERWALL, m_operwall,0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_CLOSE,   m_close,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_KLINE,   m_kline,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_UNKLINE, m_unkline,  0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_DLINE,   m_dline,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_GLINE,   m_gline,    0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_HASH,    m_hash,     0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_DNS,     m_dns,      0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_REHASH,  m_rehash,   0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_RESTART, m_restart,  0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_DIE, m_die,          0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_HTM,    m_htm,       0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_SET,    m_set,       0, MAXPARA, 1, 0, 0, 0L },
+  { MSG_TESTLINE,       m_testline,          0, MAXPARA, 1, 0, 0, 0L },
+  { (char *) 0, (int (*)()) 0 , 0, 0,    0, 0, 0, 0L }
+};
+
+struct MessageTree* msg_tree_root;
+
+#else
+extern struct Message       msgtab[];
+extern struct MessageTree*  msg_tree_root;
+#endif
+
+#endif /* INCLUDED_msg_h */
+
diff -urN ircd-hybrid-6.0.2/include/s_cr.h ircd-hybrid-6.0.2+cr/include/s_cr.h
--- ircd-hybrid-6.0.2/include/s_cr.h	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0.2+cr/include/s_cr.h	Wed Apr 11 00:32:27 2001
@@ -0,0 +1,25 @@
+/************************************************************************
+ *   IRC - Internet Relay Chat, include/s_cr.h
+ *   April 7. 2001 - einride
+ */
+
+#ifndef INCLUDED_s_cr_h
+#define INCLUDED_s_cr_h
+
+#include "client.h"
+#include "common.h"
+
+
+#ifdef CHALLENGERESPONSE
+
+#ifdef CHALLENGERESPONSE_FALLBACK
+void cr_checkfallback();
+#endif
+
+void cr_sendchallenge(struct Client * cptr, struct ConfItem * n_conf);
+void cr_sendresponse(struct Client * cptr, struct ConfItem * c_conf, char * chall);
+void cr_gotresponse(struct Client * cptr, char * resp);
+
+#endif
+
+#endif
diff -urN ircd-hybrid-6.0.2/include/setup.h ircd-hybrid-6.0.2+cr/include/setup.h
--- ircd-hybrid-6.0.2/include/setup.h	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0.2+cr/include/setup.h	Wed Apr 11 00:32:27 2001
@@ -0,0 +1,73 @@
+/* include/setup.h.  Generated automatically by configure.  */
+/* include/setup.h.in.  Generated automatically from configure.in by autoheader.
+ *
+ * $Id: setup.h.in,v 1.6 2000/10/06 03:00:57 lusky Exp $ 
+ */
+
+/* Define if you need to in order for stat and other things to work.  */
+/* #undef _POSIX_SOURCE */
+
+/* Define if you have the ANSI C header files.  */
+#define STDC_HEADERS 1
+
+/* Define only one of POSIX, BSD, or SYSV signals.  */
+/* Define if your system has reliable POSIX signals.  */
+/* #undef POSIX_SIGNALS */
+
+/* Define if your system has reliable BSD signals.  */
+#define BSD_RELIABLE_SIGNALS 1
+
+/* Define if your system has unreliable SYSV signals.  */
+/* #undef SYSV_UNRELIABLE_SIGNALS */
+
+/* Define if you have the poll() system call.  */
+#define USE_POLL 1
+
+/* Chose only one of NBLOCK_POSIX, NBLOCK_BSD, and NBLOCK_SYSV */
+/* Define if you have posix non-blocking sockets (O_NONBLOCK) */
+#define NBLOCK_POSIX 1
+
+/* Define if you have BSD non-blocking sockets (O_NDELAY) */
+/* #undef NBLOCK_BSD */
+
+/* Define if you have SYSV non-blocking sockets (FIONBIO) */
+/* #undef NBLOCK_SYSV */
+
+/* Define if you have the mmap() function.  */
+/* #undef USE_MMAP */
+
+/* Define if you are running SOLARIS2.  */
+/* #undef OS_SOLARIS2 */
+
+/* Define if you have the <errno.h> header file.  */
+#define HAVE_ERRNO_H 1
+
+/* Define if you have the <stddef.h> header file.  */
+#define HAVE_STDDEF_H 1
+
+/* Define if you have the <stdlib.h> header file.  */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <string.h> header file.  */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/param.h> header file.  */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <unistd.h> header file.  */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <getopt.h> header file.  */
+#define HAVE_GETOPT_H 1
+
+/* Define if you have the descrypt library (-ldescrypt).  */
+/* #undef HAVE_LIBDESCRYPT */
+
+/* Define if you have the nsl library (-lnsl).  */
+#define HAVE_LIBNSL 1
+
+/* Define if you have the resolv library (-lresolv).  */
+#define HAVE_LIBRESOLV 1
+
+/* Define if you have the socket library (-lsocket).  */
+/* #undef HAVE_LIBSOCKET */
diff -urN ircd-hybrid-6.0.2/src/Makefile.in ircd-hybrid-6.0.2+cr/src/Makefile.in
--- ircd-hybrid-6.0.2/src/Makefile.in	Thu Jun 22 07:40:55 2000
+++ ircd-hybrid-6.0.2+cr/src/Makefile.in	Wed Apr 11 00:32:27 2001
@@ -36,6 +36,7 @@
 	m_admin.c \
 	m_away.c \
 	m_capab.c \
+	m_chall.c \
 	m_close.c \
 	m_connect.c \
 	m_die.c \
@@ -61,6 +62,7 @@
 	m_pong.c \
 	m_quit.c \
 	m_rehash.c \
+	m_resp.c \
 	m_restart.c \
 	m_server.c \
 	m_set.c \
@@ -77,6 +79,7 @@
 	m_who.c \
 	m_whois.c \
 	match.c \
+	md5.c \
 	motd.c \
 	mtrie_conf.c \
 	oratime.c \
@@ -87,6 +90,7 @@
 	restart.c \
 	s_auth.c \
 	s_bsd.c \
+	s_cr.c \
 	s_conf.c \
 	s_debug.c \
 	s_log.c \
diff -urN ircd-hybrid-6.0.2/src/ircd.c ircd-hybrid-6.0.2+cr/src/ircd.c
--- ircd-hybrid-6.0.2/src/ircd.c	Sun Dec 31 01:12:00 2000
+++ ircd-hybrid-6.0.2+cr/src/ircd.c	Wed Apr 11 00:32:27 2001
@@ -40,6 +40,7 @@
 #include "restart.h"
 #include "s_auth.h"
 #include "s_bsd.h"
+#include "s_cr.h"
 #include "s_conf.h"
 #include "s_debug.h"
 #include "s_log.h"
@@ -154,6 +155,10 @@
 time_t  nextconnect = 1;        /* time for next try_connections call */
 time_t  nextping = 1;           /* same as above for check_pings() */
 
+#ifdef CHALLENGERESPONSE
+time_t  cr_challengeexpirytime = 0;
+#endif
+
 /* code added by mika nystrom (mnystrom@mit.edu) */
 /* this flag is used to signal globally that the server is heavily loaded,
    something which can be taken into account when processing e.g. user commands
@@ -526,7 +531,13 @@
     nextping = check_pings(CurrentTime);
     timeout_auth_queries(CurrentTime);
   }
-
+#ifdef CHALLENGERESPONSE
+#ifdef CHALLENGERESPONSE_FALLBACK
+  if (cr_challengeexpirytime && (CurrentTime >= cr_challengeexpirytime)) {
+    cr_checkfallback();
+  }
+#endif
+#endif
   if (dorehash && !LIFESUX)
     {
       rehash(&me, &me, 1);
diff -urN ircd-hybrid-6.0.2/src/m_chall.c ircd-hybrid-6.0.2+cr/src/m_chall.c
--- ircd-hybrid-6.0.2/src/m_chall.c	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0.2+cr/src/m_chall.c	Wed Apr 11 00:32:27 2001
@@ -0,0 +1,123 @@
+
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/m_chall.c
+ *   April 6. 2001, einride.
+ */
+#include "m_commands.h"  /* m_pass prototype */
+#include "client.h"      /* client struct */
+#include "irc_string.h"  /* strncpy_irc */
+#include "send.h"        /* sendto_one */
+#include "numeric.h"     /* ERR_xxx */
+#include "ircd.h"        /* me */
+#include "s_conf.h"      /* find_conf* */
+#include "s_log.h"
+#include "s_cr.h"
+
+#ifdef CHALLENGERESPONSE
+
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *      cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *              structure (with an open socket connected!). This
+ *              identifies the physical socket where the message
+ *              originated (or which caused the m_function to be
+ *              executed--some m_functions may call others...).
+ *
+ *      sptr    is the source of the message, defined by the
+ *              prefix part of the message if present. If not
+ *              or prefix not found, then sptr==cptr.
+ *
+ *              (!IsServer(cptr)) => (cptr == sptr), because
+ *              prefixes are taken *only* from servers...
+ *
+ *              (IsServer(cptr))
+ *                      (sptr == cptr) => the message didn't
+ *                      have the prefix.
+ *
+ *                      (sptr != cptr && IsServer(sptr) means
+ *                      the prefix specified servername. (?)
+ *
+ *                      (sptr != cptr && !IsServer(sptr) means
+ *                      that message originated from a remote
+ *                      user (not local).
+ *
+ *              combining
+ *
+ *              (!IsServer(sptr)) means that, sptr can safely
+ *              taken as defining the target structure of the
+ *              message in this server.
+ *
+ *      *Always* true (if 'parse' and others are working correct):
+ *
+ *      1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *      2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *              *cannot* be a local connection, unless it's
+ *              actually cptr!). [MyConnect(x) should probably
+ *              be defined as (x == x->from) --msa ]
+ *
+ *      parc    number of variable parameter strings (if zero,
+ *              parv is allowed to be NULL)
+ *
+ *      parv    a NULL terminated list of parameter pointers,
+ *
+ *                      parv[0], sender (prefix string), if not present
+ *                              this points to an empty string.
+ *                      parv[1]...parv[parc-1]
+ *                              pointers to additional parameters
+ *                      parv[parc] == NULL, *always*
+ *
+ *              note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                      non-NULL pointers.
+ */
+
+int m_chall(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char* chall = parc > 2 ? parv[2] : "";
+  char* host = parc > 1 ? parv[1] : "";
+  struct ConfItem *n_conf, *c_conf;
+
+  /* If we know this, we shouldn't be getting a chall */
+  if (IsPerson(cptr) || IsServer(cptr)) 
+    return 0;
+
+  /* See if we got c and n lines. */
+  if (!(n_conf = find_conf_by_name(host, CONF_NOCONNECT_SERVER))) {
+    sendto_ops("Challenge rejected. No N line for server %s", host);
+    log(L_NOTICE, "Challenge rejected. No N line for server %s", host);
+    sendto_one(cptr, "ERROR :Access denied. No N line"); 
+    return exit_client(cptr, cptr, cptr, "Access denied. No N line");    
+  } 
+
+  if (!(c_conf = find_conf_by_name(host, CONF_CONNECT_SERVER))) {
+    sendto_ops("Challenge rejected. No C line for server %s", host);
+    log(L_NOTICE, "Challenge rejected. No C line for server %s", host);
+    sendto_one(cptr, "ERROR :Access denied. No C line"); 
+    return exit_client(cptr, cptr, cptr, "Access denied. No C line");    
+  }
+  
+  /* Check if the ip matches the c/n IPs */
+  if ( (cptr->ip.s_addr != c_conf->ipnum.s_addr) || (cptr->ip.s_addr != n_conf->ipnum.s_addr)) {
+    sendto_ops("Challenge rejected. C/N line IP doesn't match connection");
+    log(L_NOTICE, "Challenge rejected. C/N line IP doesn't match connection");
+    sendto_one(cptr, "ERROR :Access denied. C/N line don't match you"); 
+    return exit_client(cptr, cptr, cptr, "Access denied. C/N line don't match");        
+  }
+  
+  /* Ok, it got c/n lines and correct ip, lets challenge it back */
+  if (!Challenged(cptr))
+    cr_sendchallenge(cptr, n_conf);
+
+  /* And send a response. */
+  cr_sendresponse(cptr, c_conf, chall);
+
+  /* check for TS as in m_pass */
+  if (parc > 3)
+    {
+      if (0 == irccmp(parv[3], "TS"))
+        cptr->tsinfo = TS_DOESTS;
+    }
+  return 0;
+}
+#endif
diff -urN ircd-hybrid-6.0.2/src/m_resp.c ircd-hybrid-6.0.2+cr/src/m_resp.c
--- ircd-hybrid-6.0.2/src/m_resp.c	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0.2+cr/src/m_resp.c	Wed Apr 11 00:32:27 2001
@@ -0,0 +1,106 @@
+
+/************************************************************************
+ *   IRC - Internet Relay Chat, src/m_resp.c
+ *   April 6. 2001, einride.
+ */
+#include "m_commands.h"  /* m_pass prototype */
+#include "client.h"      /* client struct */
+#include "irc_string.h"  /* strncpy_irc */
+#include "send.h"        /* sendto_one */
+#include "numeric.h"     /* ERR_xxx */
+#include "ircd.h"        /* me */
+#include "s_conf.h"      /* find_conf* */
+#include "s_log.h"
+#include "s_cr.h"
+#include "s_serv.h"
+
+#ifdef CHALLENGERESPONSE
+/*
+ * m_functions execute protocol messages on this server:
+ *
+ *      cptr    is always NON-NULL, pointing to a *LOCAL* client
+ *              structure (with an open socket connected!). This
+ *              identifies the physical socket where the message
+ *              originated (or which caused the m_function to be
+ *              executed--some m_functions may call others...).
+ *
+ *      sptr    is the source of the message, defined by the
+ *              prefix part of the message if present. If not
+ *              or prefix not found, then sptr==cptr.
+ *
+ *              (!IsServer(cptr)) => (cptr == sptr), because
+ *              prefixes are taken *only* from servers...
+ *
+ *              (IsServer(cptr))
+ *                      (sptr == cptr) => the message didn't
+ *                      have the prefix.
+ *
+ *                      (sptr != cptr && IsServer(sptr) means
+ *                      the prefix specified servername. (?)
+ *
+ *                      (sptr != cptr && !IsServer(sptr) means
+ *                      that message originated from a remote
+ *                      user (not local).
+ *
+ *              combining
+ *
+ *              (!IsServer(sptr)) means that, sptr can safely
+ *              taken as defining the target structure of the
+ *              message in this server.
+ *
+ *      *Always* true (if 'parse' and others are working correct):
+ *
+ *      1)      sptr->from == cptr  (note: cptr->from == cptr)
+ *
+ *      2)      MyConnect(sptr) <=> sptr == cptr (e.g. sptr
+ *              *cannot* be a local connection, unless it's
+ *              actually cptr!). [MyConnect(x) should probably
+ *              be defined as (x == x->from) --msa ]
+ *
+ *      parc    number of variable parameter strings (if zero,
+ *              parv is allowed to be NULL)
+ *
+ *      parv    a NULL terminated list of parameter pointers,
+ *
+ *                      parv[0], sender (prefix string), if not present
+ *                              this points to an empty string.
+ *                      parv[1]...parv[parc-1]
+ *                              pointers to additional parameters
+ *                      parv[parc] == NULL, *always*
+ *
+ *              note:   it is guaranteed that parv[0]..parv[parc-1] are all
+ *                      non-NULL pointers.
+ */
+
+int m_resp(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
+{
+  char * resp = parc > 1 ? parv[1] : NULL;
+  struct ConfItem *c_conf, *n_conf;
+
+  /* If we didn't challenge, a user most likely sent a RESP. */
+  if (!Challenged(cptr)) {
+    log(L_NOTICE, "Got a RESP but never sent a CHALL? Something's fishy.");
+    return exit_client(cptr, cptr, cptr, "I didn't challenge you!");
+  }
+
+  /* Ok we challenged. Handle the resp */
+  cr_gotresponse(cptr, resp);
+
+  if (!IsUnknown(cptr)) {
+    /* If we're the connecting party, send CAPAB/SERVER now.
+       If not, we're in the state we would be after a single PASS line
+       received, and we just wait for m_server to trigger */
+
+    c_conf = find_conf_name(cptr->confs, cptr->name, CONF_CONNECT_SERVER);
+    n_conf = find_conf_name(cptr->confs, cptr->name, CONF_NOCONNECT_SERVER);  
+    if (c_conf && n_conf)
+      {
+	send_capabilities(cptr, (c_conf->flags & CONF_FLAGS_ZIP_LINK));
+	sendto_one(cptr, "SERVER %s 1 :%s",
+		   my_name_for_link(me.name, n_conf), me.info);
+      }
+  }
+  return 0;
+}
+
+#endif
diff -urN ircd-hybrid-6.0.2/src/md5.c ircd-hybrid-6.0.2+cr/src/md5.c
--- ircd-hybrid-6.0.2/src/md5.c	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0.2+cr/src/md5.c	Wed Apr 11 00:32:27 2001
@@ -0,0 +1,301 @@
+/* 
+ * md5c.c
+ *   RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+/* 
+ * Copyright (C) 1991, 1992  RSA Data Security, Inc.
+ * Created 1991.
+ * All rights reserved.
+ * 
+ * License to copy and use this software is granted provided that it
+ * is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ * Algorithm" in all material mentioning or referencing this software
+ * or this function.
+ * 
+ * License is also granted to make and use derivative works provided
+ * that such works are identified as "derived from the RSA Data
+ * Security, Inc. MD5 Message-Digest Algorithm" in all material
+ * mentioning or referencing the derived work.
+ * 
+ * RSA Data Security, Inc. makes no representations concerning either
+ * the merchantability of this software or the suitability of this
+ * software for any particular purpose. It is provided "as is"
+ * without express or implied warranty of any kind.
+ * 
+ * These notices must be retained in any copies of any part of this
+ * documentation and/or software.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include "md5.h"
+
+static void MD5Transform (UINT4 state[4], unsigned char block[64]);
+static void Decode (UINT4 * output, unsigned char * input, unsigned int len);
+static void Encode (unsigned char * output, UINT4 * input, unsigned int len);
+
+/* 
+ * Constants for MD5Transform routine.
+ */
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+
+static unsigned char PADDING[64] = {
+  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* 
+ * F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* 
+ * ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* 
+ * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+ * Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+  }
+
+/* 
+ * MD5 initialization.
+ * Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (MD5_CTX * context)
+{
+  context->count[0] = context->count[1] = 0;
+  /* Load magic initialization constants. */
+  context->state[0] = 0x67452301;
+  context->state[1] = 0xefcdab89;
+  context->state[2] = 0x98badcfe;
+  context->state[3] = 0x10325476;
+}
+
+/* 
+ * MD5 block update operation.
+ * Continues an MD5 message-digest operation,
+ * processing another message block and updating the context.
+ */
+void MD5Update (MD5_CTX * context, unsigned char * input, unsigned int inputLen)
+{
+  unsigned int i, index, partLen;
+
+  /* Compute number of bytes mod 64 */
+  index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+  /* Update number of bits */
+  if ((context->count[0] += ((UINT4)inputLen << 3))
+   < ((UINT4)inputLen << 3))
+ context->count[1]++;
+  context->count[1] += ((UINT4)inputLen >> 29);
+
+  partLen = 64 - index;
+
+  /* Transform as many times as possible. */
+  if (inputLen >= partLen) {
+ memcpy
+   ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+   MD5Transform (context->state, &input[i]);
+
+ index = 0;
+  }
+  else
+ i = 0;
+
+  /* Buffer remaining input */
+  memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+  inputLen-i);
+}
+
+/* 
+ * MD5 finalization.
+ * Ends an MD5 message-digest operation,
+ * writing the the message digest and zeroizing the context.
+ */
+void MD5Final (unsigned char * digest, MD5_CTX * context)
+{
+  unsigned char bits[8];
+  unsigned int index, padLen;
+
+  /* Save number of bits */
+  Encode (bits, context->count, 8);
+
+  /* Pad out to 56 mod 64. */
+  index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+  padLen = (index < 56) ? (56 - index) : (120 - index);
+  MD5Update (context, PADDING, padLen);
+
+  /* Append length (before padding) */
+  MD5Update (context, bits, 8);
+  /* Store state in digest */
+  Encode (digest, context->state, 16);
+
+  /* Zeroize sensitive information. */
+  memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* 
+ * MD5 basic transformation.
+ * Transforms state based on block.
+ */
+static void MD5Transform (UINT4 state[4], unsigned char block[64])
+{
+  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+  Decode (x, block, 64);
+
+  /* Round 1 */
+  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /*  1 */
+  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /*  2 */
+  FF (c, d, a, b, x[ 2], S13, 0x242070db); /*  3 */
+  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /*  4 */
+  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /*  5 */
+  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /*  6 */
+  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /*  7 */
+  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /*  8 */
+  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /*  9 */
+  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+  GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
+  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+  /* Round 3 */
+  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+  HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
+  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+  /* Round 4 */
+  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+  state[0] += a;
+  state[1] += b;
+  state[2] += c;
+  state[3] += d;
+
+  /* Zeroize sensitive information. */
+  memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* 
+ * Encodes input (UINT4) into output (unsigned char).
+ * Assumes len is a multiple of 4.
+ */
+static void Encode (unsigned char * output, UINT4 * input, unsigned int len)
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+  }
+}
+
+/* 
+ * Decodes input (unsigned char) into output (UINT4).
+ * Assumes len is a multiple of 4.
+ */
+static void Decode (UINT4 * output, unsigned char * input, unsigned int len)
+{
+  unsigned int i, j;
+
+  for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+   (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
diff -urN ircd-hybrid-6.0.2/src/s_bsd.c ircd-hybrid-6.0.2+cr/src/s_bsd.c
--- ircd-hybrid-6.0.2/src/s_bsd.c	Sun Dec 31 01:12:01 2000
+++ ircd-hybrid-6.0.2+cr/src/s_bsd.c	Wed Apr 11 00:32:27 2001
@@ -35,6 +35,7 @@
 #include "restart.h"
 #include "s_auth.h"
 #include "s_conf.h"
+#include "s_cr.h"
 #include "s_log.h"
 #include "s_serv.h"
 #include "s_stats.h"
@@ -374,6 +375,9 @@
   
   SetHandshake(cptr);
 
+#ifdef CHALLENGERESPONSE
+  cr_sendchallenge(cptr, n_conf);
+#else
   if (!EmptyString(c_conf->passwd))
     sendto_one(cptr, "PASS %s :TS", c_conf->passwd);
   
@@ -381,7 +385,7 @@
 
   sendto_one(cptr, "SERVER %s 1 :%s",
              my_name_for_link(me.name, n_conf), me.info);
-
+#endif
   return (IsDead(cptr)) ? 0 : 1;
 }
 
diff -urN ircd-hybrid-6.0.2/src/s_cr.c ircd-hybrid-6.0.2+cr/src/s_cr.c
--- ircd-hybrid-6.0.2/src/s_cr.c	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0.2+cr/src/s_cr.c	Wed Apr 11 00:32:27 2001
@@ -0,0 +1,125 @@
+#include "client.h"
+#include "common.h"
+#include "s_log.h"
+#include "irc_string.h"
+#include "s_bsd.h"
+#include "ircd.h"
+#include "send.h"
+#include "md5.h"
+#include "s_conf.h"
+#include "s_serv.h"
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef CHALLENGERESPONSE
+#ifdef CHALLENGERESPONSE_FALLBACK
+extern time_t cr_challengeexpirytime;
+void cr_checkfallback() {
+  /* The cr_challengeexpirytime was reached. So, let's look through
+     or list for servers we are connecting to which we haven't got
+     a password for (aka no RESP received), and the connect happened 
+     more than CHALLENGERESPONSE_EXPIRY seconds ago. If we find one,
+     we revert to PASS. By lagging servers it'd be possible to provoke
+     a fallback to PASS, so this could be exploited.
+     - einride.
+  */  
+  time_t nextexpiry = 0;
+  struct Client * cptr;
+  struct ConfItem *c_conf, *n_conf;
+  for (cptr=GlobalClientList; cptr; cptr = cptr->next_local_client) {
+    if (Challenged(cptr) && !Responded(cptr)) {
+      if (cptr->firsttime < (CurrentTime - CHALLENGERESPONSE_EXPIRY)) {
+	/* Revert to PASS */
+	log(L_NOTICE, "CR expiry time reached for %s - fallback", cptr->name ? cptr->name : "<unknown>");
+	c_conf = find_conf_by_name(cptr->name, CONF_CONNECT_SERVER);
+	n_conf = find_conf_by_name(cptr->name, CONF_NOCONNECT_SERVER);
+	if (c_conf && n_conf) {
+	  sendto_ops("Trying PASS to authenticate with %s", cptr->name);
+	  if (!EmptyString(c_conf->passwd))
+	    sendto_one(cptr, "PASS %s :TS", c_conf->passwd);
+	  send_capabilities(cptr, (c_conf->flags & CONF_FLAGS_ZIP_LINK));
+	  sendto_one(cptr, "SERVER %s 1 :%s",
+		     my_name_for_link(me.name, n_conf), me.info);
+	} else {
+	  sendto_ops("Can't find C/N lines on CR expiry - dropping %s", cptr->name);
+	  log(L_NOTICE, "Can't find C/N lines on CR expiry - dropping %s", cptr->name);
+	  exit_client(cptr, cptr, cptr, "No C/N lines");
+	}
+      } else {
+	if (!nextexpiry || nextexpiry > (cptr->firsttime + CHALLENGERESPONSE_EXPIRY))
+	  nextexpiry = (cptr->firsttime + CHALLENGERESPONSE_EXPIRY);
+      }
+    }
+  }
+  cr_challengeexpirytime=nextexpiry;
+}
+#endif
+
+void cr_sendchallenge(struct Client * cptr, struct ConfItem * n_conf) {
+  /* Create a challenge using random data and sending it as a hex value.
+     Store this hex value in cptr->passwd, don't want more fields in cptr.
+     As this is sent before anything else, we pass the server name too so
+     the receiving end can look up our C/N lines.
+  */
+  char chall[17]="";
+  unsigned int c;
+  int i;
+  srandom(time(0));
+  for (i=0; i<16; i++) {
+    c = (unsigned int) (16.0 * (random() / (RAND_MAX + 1.0)));
+    chall[i] = (c>=10) ? (c - 10 + 'A' ) : (c + '0');
+  }
+  chall[16]=0;
+  sendto_one(cptr, "CHALL %s %s :TS", me.name, chall);
+  strncpy_irc(cptr->name, n_conf->name, HOSTLEN);
+  strcpy(cptr->passwd, chall);
+  SetChallenged(cptr);
+  sendto_ops("Sent password challenge to %s", cptr->name);
+#ifdef CHALLENGERESPONSE_FALLBACK
+  if (!cr_challengeexpirytime)
+    cr_challengeexpirytime = CurrentTime + CHALLENGERESPONSE_EXPIRY;
+#endif
+}
+
+void cr_hashstring(char * src, char * trg) {
+  unsigned char md[16];
+  int i;
+  MD5_CTX ctx;
+  MD5Init(&ctx);
+  MD5Update(&ctx, src, strlen(src));
+  MD5Final(md, &ctx);
+  ircsprintf(trg, "%08x", * (unsigned int *) &md[0]);
+  ircsprintf(trg + 8, "%08x", * (unsigned int *) &md[4]);
+  ircsprintf(trg + 16, "%08x", * (unsigned int *) &md[8]);
+  ircsprintf(trg + 24, "%08x", * (unsigned int *) &md[12]);
+}
+
+void cr_sendresponse(struct Client * cptr, struct ConfItem * c_conf, char * chall) {
+  char work[PASSWDLEN*2], hash[36];
+  strncpy_irc(work, chall, PASSWDLEN);
+  strncpy_irc(work + strlen(work), c_conf->passwd ? c_conf->passwd : "", PASSWDLEN);
+  cr_hashstring(work, hash);
+  sendto_one(cptr, "RESP %s", hash);
+  SetResponded(cptr);
+  sendto_ops("Sent password response to %s", cptr->name);
+}
+
+void cr_gotresponse(struct Client * cptr, char * resp) {
+  struct ConfItem * n_conf;
+  char work[PASSWDLEN*2], hash[36];
+  n_conf = find_conf_by_name(cptr->name, CONF_NOCONNECT_SERVER);
+  if (n_conf && cptr->passwd[0]) {
+    strncpy_irc(work, cptr->passwd, PASSWDLEN);
+    strncpy_irc(work + strlen(work), n_conf->passwd ? n_conf->passwd : "", PASSWDLEN);
+    cr_hashstring(work, hash);
+    if (!strcmp(resp, hash)) {
+      strncpy_irc(cptr->passwd, n_conf->passwd, PASSWDLEN);
+      sendto_ops("Got a good password response from %s", cptr->name);
+    } else {
+      sendto_ops("Failed password response from %s", cptr->name);
+    }
+  }
+}
+
+#endif
diff -urN ircd-hybrid-6.0.2/src/s_serv.c ircd-hybrid-6.0.2+cr/src/s_serv.c
--- ircd-hybrid-6.0.2/src/s_serv.c	Tue Nov 21 07:49:32 2000
+++ ircd-hybrid-6.0.2+cr/src/s_serv.c	Wed Apr 11 00:32:27 2001
@@ -567,6 +567,14 @@
 #else
   encr = cptr->passwd;
 #endif  /* CRYPT_LINK_PASSWORD */
+#ifdef CHALLENGERESPONSE
+#ifndef CHALLENGERESPONSE_FALLBACK
+  if (!Responded(cptr)) {
+    sendto_realops("Access denied (plaintext password) %s", inpath);
+    return exit_client(cptr, cptr, cptr, "Non CR server");
+  }
+#endif
+#endif
   if (*n_conf->passwd && 0 != strcmp(n_conf->passwd, encr))
     {
       ServerStats->is_ref++;
@@ -596,8 +604,21 @@
 #endif
   if (IsUnknown(cptr))
     {
+#ifdef CHALLENGERESPONSE
+#ifdef CHALLENGERESPONSE_FALLBACK
+      /* If we haven't sent a response by the time we get here,
+         the other end sent a valid PASS and not a CHALL/RESP
+	 - einride. 
+      */
+      if (!Responded(cptr) && (c_conf->passwd[0])) {
+	log(L_NOTICE, "Fallback to PASS authentication for %s", host);
+        sendto_one(cptr,"PASS %s :TS", c_conf->passwd);
+      }
+#endif
+#else
       if (c_conf->passwd[0])
         sendto_one(cptr,"PASS %s :TS", c_conf->passwd);
+#endif
       /*
       ** Pass my info to the new server
       */
