diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/README.challengeresponse ircd-hybrid-6.0/README.challengeresponse
--- ircd-hybrid-6.0.orig/README.challengeresponse	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0/README.challengeresponse	Sat Jun 16 20:41:09 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 -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/include/client.h ircd-hybrid-6.0/include/client.h
--- ircd-hybrid-6.0.orig/include/client.h	Sat Jun 16 20:43:22 2001
+++ ircd-hybrid-6.0/include/client.h	Sat Jun 16 20:41:09 2001
@@ -351,6 +351,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 */
 /* Nice, flashy new bitfield math. These are just indexes into the lookup. Fun :)
  *  -- asuffield */
@@ -464,6 +469,13 @@
 #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))
 #define IsOper(x)               (TestBit((x)->umodes,UMODE_OPER))
diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/include/config.h ircd-hybrid-6.0/include/config.h
--- ircd-hybrid-6.0.orig/include/config.h	Sat Jun 16 20:43:22 2001
+++ ircd-hybrid-6.0/include/config.h	Sat Jun 16 20:41:10 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" */
 
@@ -593,7 +616,7 @@
  * need not be the same for both, as long as the opposite end has the
  * right password in the opposite line.
  */
-#define  CRYPT_LINK_PASSWORD
+#undef  CRYPT_LINK_PASSWORD
 
 /* CRYPT_I_PASSWORD - use crypted I-line passwords in the ircd.conf
  * define this if you want to use crypted passwords for connecting users
diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/include/m_commands.h ircd-hybrid-6.0/include/m_commands.h
--- ircd-hybrid-6.0.orig/include/m_commands.h	Sat Jun 16 20:43:21 2001
+++ ircd-hybrid-6.0/include/m_commands.h	Sat Jun 16 20:41:09 2001
@@ -119,4 +119,8 @@
 extern int m_silence(struct Client *, struct Client *, int, char**);
 extern int m_map(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 -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/include/msg.h ircd-hybrid-6.0/include/msg.h
--- ircd-hybrid-6.0.orig/include/msg.h	Sat Jun 16 20:43:21 2001
+++ ircd-hybrid-6.0/include/msg.h	Sat Jun 16 20:41:09 2001
@@ -60,6 +60,10 @@
 
 typedef struct MessageTree MESSAGE_TREE;
 
+#ifdef CHALLENGERESPONSE
+#define MSG_CHALL    "CHALL"    /* CHALL */
+#define MSG_RESP     "RESP"     /* RESP */
+#endif
 
 #define MSG_PRIVATE  "PRIVMSG"  /* PRIV */
 #define MSG_WHO      "WHO"      /* WHO  -> WHOC */
@@ -243,6 +247,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 -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/include/s_cr.h ircd-hybrid-6.0/include/s_cr.h
--- ircd-hybrid-6.0.orig/include/s_cr.h	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0/include/s_cr.h	Sat Jun 16 20:41:09 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, char* salt);
+void cr_gotresponse(struct Client * cptr, char * resp);
+
+#endif
+
+#endif
diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/include/send.h ircd-hybrid-6.0/include/send.h
--- ircd-hybrid-6.0.orig/include/send.h	Sat Jun 16 20:43:22 2001
+++ ircd-hybrid-6.0/include/send.h	Sat Jun 16 20:41:09 2001
@@ -59,6 +59,7 @@
 
 extern  void sendto_realops(const char *, ...);
 extern  void sendto_realops_flag(int, const char *, ...);
+extern  void sendto_realops_flags(int*, const char *, ...);
 
 extern  void sendto_ops(const char *, ...);
 extern  void sendto_ops_butone(struct Client *, struct Client *, 
diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/Makefile.in ircd-hybrid-6.0/src/Makefile.in
--- ircd-hybrid-6.0.orig/src/Makefile.in	Sat Jun 16 20:43:21 2001
+++ ircd-hybrid-6.0/src/Makefile.in	Sat Jun 16 20:41:09 2001
@@ -36,6 +36,7 @@
 	m_admin.c \
 	m_away.c \
 	m_capab.c \
+	m_chall.c \
 	m_close.c \
 	m_connect.c \
 	md5.c \
@@ -64,6 +65,7 @@
 	m_pong.c \
 	m_quit.c \
 	m_rehash.c \
+	m_resp.c \
 	m_restart.c \
 	m_services.c \
 	m_server.c \
@@ -93,6 +95,7 @@
 	restart.c \
 	s_auth.c \
 	s_bsd.c \
+	s_cr.c \
 	s_conf.c \
 	s_debug.c \
 	s_log.c \
diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/client.c ircd-hybrid-6.0/src/client.c
--- ircd-hybrid-6.0.orig/src/client.c	Sat Jun 16 20:43:22 2001
+++ ircd-hybrid-6.0/src/client.c	Sat Jun 16 20:41:09 2001
@@ -1101,11 +1101,11 @@
       switch (showip)
         {
           case SHOW_IP:
-#ifndef SERVERHIDE
+	    /*#ifndef SERVERHIDE*/
             ircsprintf(nbuf, "%s[%s@%s]", client->name, client->username,
               client->sockhost);
             break;
-#endif
+	    /*#endif*/
           case MASK_IP:
             ircsprintf(nbuf, "%s[%s@255.255.255.255]", client->name,
               client->username);
diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/ircd.c ircd-hybrid-6.0/src/ircd.c
--- ircd-hybrid-6.0.orig/src/ircd.c	Sat Jun 16 20:43:22 2001
+++ ircd-hybrid-6.0/src/ircd.c	Sat Jun 16 20:41:09 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"
@@ -155,6 +156,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
@@ -527,7 +532,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 -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/m_chall.c ircd-hybrid-6.0/src/m_chall.c
--- ircd-hybrid-6.0.orig/src/m_chall.c	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0/src/m_chall.c	Sat Jun 16 20:41:09 2001
@@ -0,0 +1,151 @@
+
+/************************************************************************
+ *   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[])
+{
+  static int sendflags[] = {UMODE_SERVNOTICE, UMODE_AUSPEX, UMODE_INVALID};
+  char* salt = parc > 3 ? parv[3] : "";
+  char* chall = parc > 2 ? parv[2] : "";
+  char* host = parc > 1 ? parv[1] : "";
+  struct ConfItem *n_conf, *c_conf;
+
+  if (IsPerson(sptr))
+    {
+      if (IsServer(cptr))
+        {
+          sendto_realops("CHALL command from remote user %s -- %s is a hacked server",
+                          get_client_name(sptr,HIDE_IP),
+                          get_client_name(cptr,HIDE_IP));
+        }
+      else
+        {
+          sendto_one(sptr, form_str(ERR_UNKNOWNCOMMAND),
+                     me.name, parv[0], "CHALL");
+        }
+      return 0;
+    }
+
+  sendto_realops_flags(sendflags, "CHALL received from %s, trying to use N:line for %s", get_client_name(cptr, SHOW_IP), host);
+
+  if (parc < 5)
+    {
+      sendto_one(cptr, "ERROR: Invalid challenge");
+      sendto_realops("Invalid CHALL from remote host for %s", host);
+      sendto_ops_flag(UMODE_DEBUG, "Got CHALL '%s' '%s' '%s'", host, chall, salt);
+      return 0;
+    }
+
+  /* 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, salt);
+
+  /* check for TS as in m_pass */
+  if (parc > 4)
+    {
+      if (0 == irccmp(parv[4], "TS"))
+        cptr->tsinfo = TS_DOESTS;
+    }
+  return 0;
+}
+#endif
diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/m_resp.c ircd-hybrid-6.0/src/m_resp.c
--- ircd-hybrid-6.0.orig/src/m_resp.c	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0/src/m_resp.c	Sat Jun 16 20:41:09 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 -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/md5crypt.c ircd-hybrid-6.0/src/md5crypt.c
--- ircd-hybrid-6.0.orig/src/md5crypt.c	Sat Jun 16 20:43:20 2001
+++ ircd-hybrid-6.0/src/md5crypt.c	Sat Jun 16 20:41:09 2001
@@ -41,6 +41,39 @@
  * Use MD5 for what it is best at...
  */
 
+#include "s_log.h"
+
+/* We need to pull this out for the challenge-response thingy -- asuffield */
+char*
+get_salt(const char* pw)
+{
+  static char *magic = "$1$";
+  static char salt[9];
+  const char* sp;
+  const char* ep;
+  int sl;
+
+  /* Refine the Salt first */
+  sp = pw;
+
+  /* If it starts with the magic string, then skip that */
+  if(!strncmp(sp,magic,strlen(magic)))
+    sp += strlen(magic);
+
+  /* It stops at the first '$', max 8 chars */
+  for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)
+    continue;
+
+  /* get the length of the true salt */
+  sl = ep - sp;
+
+  /* and format up to return the salt */
+  strncpy(salt, sp, sl);
+  salt[sl] = '\0';
+
+  return salt;
+}
+
 char *
 libshadow_md5_crypt(const char *pw, const char *salt)
 {
diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/s_bsd.c ircd-hybrid-6.0/src/s_bsd.c
--- ircd-hybrid-6.0.orig/src/s_bsd.c	Sat Jun 16 20:43:22 2001
+++ ircd-hybrid-6.0/src/s_bsd.c	Sat Jun 16 20:41:10 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"
@@ -375,6 +376,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);
   
@@ -382,7 +386,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 -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/s_cr.c ircd-hybrid-6.0/src/s_cr.c
--- ircd-hybrid-6.0.orig/src/s_cr.c	Thu Jan  1 01:00:00 1970
+++ ircd-hybrid-6.0/src/s_cr.c	Sat Jun 16 20:43:06 2001
@@ -0,0 +1,126 @@
+#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.
+  */
+  extern char* get_salt(char*);
+  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 %s :TS", me.name, chall, get_salt(n_conf->passwd));
+  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];
+  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* salt) {
+  extern char * libshadow_md5_crypt(const char *pw, const char *salt);
+  char work[PASSWDLEN*2], hash[36];
+  strncpy_irc(work, chall, PASSWDLEN);
+  strncpy_irc(work + strlen(work), c_conf->passwd ? libshadow_md5_crypt(c_conf->passwd, salt) : "", 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 -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/s_serv.c ircd-hybrid-6.0/src/s_serv.c
--- ircd-hybrid-6.0.orig/src/s_serv.c	Sat Jun 16 20:43:22 2001
+++ ircd-hybrid-6.0/src/s_serv.c	Sat Jun 16 20:41:10 2001
@@ -561,7 +561,16 @@
       return exit_client(cptr, cptr, cptr, "No C line for server");
     }
 
-#ifdef 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
+  encr = cptr->passwd;
+#else
+# ifdef CRYPT_LINK_PASSWORD
   /* use first two chars of the password they send in as salt */
 
   /* passwd may be NULL. Head it off at the pass... */
@@ -572,9 +581,10 @@
     }
   else
     encr = "";
-#else
+# else
   encr = cptr->passwd;
-#endif  /* CRYPT_LINK_PASSWORD */
+# endif  /* CRYPT_LINK_PASSWORD */
+#endif
   if (*n_conf->passwd && 0 != strcmp(n_conf->passwd, encr))
     {
       ServerStats->is_ref++;
@@ -608,8 +618,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
       */
diff -ruN -x configure -x *~ -x ircd-hybrid-6.0.orig -x *.rej ircd-hybrid-6.0.orig/src/send.c ircd-hybrid-6.0/src/send.c
--- ircd-hybrid-6.0.orig/src/send.c	Sat Jun 16 20:43:22 2001
+++ ircd-hybrid-6.0/src/send.c	Sat Jun 16 20:41:09 2001
@@ -1362,6 +1362,45 @@
   for (cptr = oper_cptr_list; cptr; cptr = cptr->next_oper_client)
     {
       if(TestBit(cptr->umodes,flag))
+        {
+          (void)ircsprintf(nbuf, ":%s NOTICE %s :*** Notice -- ",
+                           me.name, cptr->name);
+          (void)strncat(nbuf, pattern, sizeof(nbuf) - strlen(nbuf));
+          
+          vsendto_one(cptr, nbuf, args);
+        }
+    } /* for (cptr = oper_cptr_list; cptr; cptr = cptr->next_oper_client) */
+
+  va_end(args);
+} /* sendto_realops_flags() */
+
+/*
+ * sendto_realops_flags
+ *
+ *    Send to *local* ops with *all* matching flags (UMODE_INVALID terminated list)
+ *
+ * Warning: this is expensive to process. Use it carefully.
+ */
+
+void
+sendto_realops_flags(int* flag, const char *pattern, ...)
+
+{
+  va_list args;
+  register aClient *cptr;
+  char nbuf[1024];
+  int* f;
+  int send;
+
+  va_start(args, pattern);
+
+  for (cptr = oper_cptr_list; cptr; cptr = cptr->next_oper_client)
+    {
+      send = 1;
+      for (f = flag; *f != UMODE_INVALID; f++)
+	if (!TestBit(cptr->umodes,*f))
+	  send = 0;
+      if(send)
         {
           (void)ircsprintf(nbuf, ":%s NOTICE %s :*** Notice -- ",
                            me.name, cptr->name);
