diff -r b60e98d7b61e include/numeric.h
--- a/include/numeric.h	Tue Mar 06 06:16:53 2012 +0000
+++ b/include/numeric.h	Tue Mar 06 00:33:30 2012 -0600
@@ -375,4 +375,14 @@
 
 #define ERR_STARTTLS            691
 
+#define RPL_LOGGEDIN            900
+#define RPL_LOGGEDOUT           901
+#define ERR_NICKLOCKED          902
+
+#define RPL_SASLSUCCESS         903
+#define ERR_SASLFAIL            904
+#define ERR_SASLTOOLONG         905
+#define ERR_SASLABORTED         906
+#define ERR_SASLALREADY         907
+
 #define ERR_NUMERICERR       999
diff -r b60e98d7b61e include/struct.h
--- a/include/struct.h	Tue Mar 06 06:16:53 2012 +0000
+++ b/include/struct.h	Tue Mar 06 00:33:30 2012 -0600
@@ -369,6 +369,7 @@
 #define PROTO_UHNAMES	0x10000  /* Send n!u@h in NAMES */
 #define PROTO_CLICAP	0x20000  /* client capability negotiation in process */
 #define PROTO_STARTTLS	0x40000	 /* client supports STARTTLS */
+#define PROTO_SASL	0x80000  /* client is doing SASL */
 
 /*
  * flags macros.
@@ -1066,6 +1067,10 @@
 	TS   cputime;
 #endif
 	char *error_str;	/* Quit reason set by dead_link in case of socket/buffer error */
+
+	char sasl_agent[NICKLEN];
+	unsigned char sasl_out;
+	unsigned char sasl_complete;
 };
 
 
diff -r b60e98d7b61e src/modules/Makefile.in
--- a/src/modules/Makefile.in	Tue Mar 06 06:16:53 2012 +0000
+++ b/src/modules/Makefile.in	Tue Mar 06 00:33:30 2012 -0600
@@ -54,7 +54,8 @@
 	 m_connect.so m_dccallow.so m_userip.so m_nick.so m_user.so \
 	 m_mode.so m_watch.so m_part.so m_join.so m_motd.so m_opermotd.so \
 	 m_botmotd.so m_lusers.so m_names.so m_svsnolag.so m_addmotd.so \
-	 m_svslusers.so m_starttls.so m_nopost.so m_issecure.so m_cap.so
+	 m_svslusers.so m_starttls.so m_nopost.so m_issecure.so m_cap.so \
+	 m_sasl.so
 
 #note change of .c to .o
 COMMANDS=m_sethost.o m_chghost.o m_chgident.o m_setname.o m_setident.o \
@@ -77,7 +78,7 @@
 	 m_connect.o m_dccallow.o m_userip.o m_nick.o m_user.o \
 	 m_mode.o m_watch.o m_part.o m_join.o m_motd.o m_opermotd.o \
 	 m_botmotd.o m_lusers.o m_names.o m_svsnolag.o m_starttls.o \
-	 m_nopost.o m_issecure.o m_cap.o
+	 m_nopost.o m_issecure.o m_cap.o m_sasl.o
 
 
 MODULES=commands.so cloak.so $(R_MODULES)
@@ -422,6 +423,9 @@
 m_cap.o: m_cap.c $(INCLUDES)
 	$(CC) $(CFLAGS) $(MODULEFLAGS)  -c m_cap.c
 
+m_sasl.o: m_sasl.c $(INCLUDES)
+	$(CC) $(CFLAGS) $(MODULEFLAGS)  -c m_sasl.c
+
 #############################################################################
 #             .so's section
 #############################################################################
@@ -850,6 +854,10 @@
 	$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
 		-o m_cap.so m_cap.c
 
+m_sasl.so: m_sasl.c $(INCLUDES)
+	$(CC) $(CFLAGS) $(MODULEFLAGS) -DDYNAMIC_LINKING \
+		-o m_sasl.so m_sasl.c
+
 #############################################################################
 #             and now the remaining modules...
 #############################################################################
diff -r b60e98d7b61e src/modules/l_commands.c
--- a/src/modules/l_commands.c	Tue Mar 06 06:16:53 2012 +0000
+++ b/src/modules/l_commands.c	Tue Mar 06 00:33:30 2012 -0600
@@ -127,6 +127,7 @@
 extern int m_nopost_Init(ModuleInfo *modinfo);
 extern int m_issecure_Init(ModuleInfo *modinfo);
 extern int m_cap_Init(ModuleInfo *modinfo);
+extern int m_sasl_Init(ModuleInfo *modinfo);
 #ifdef GUEST
 extern int m_guest_Init(ModuleInfo *modinfo);
 #endif
@@ -180,6 +181,7 @@
 extern int m_nopost_Load(int module_load);
 extern int m_issecure_Load(int module_load);
 extern int m_cap_Load(int module_load);
+extern int m_sasl_Load(int module_load);
 #ifdef GUEST
 extern int m_guest_Load(int module_load);
 #endif
@@ -220,6 +222,7 @@
 extern int m_nopost_Unload();
 extern int m_issecure_Unload();
 extern int m_cap_Unload();
+extern int m_sasl_Unload();
 #ifdef GUEST
 extern int m_guest_Unload();
 #endif
@@ -366,6 +369,7 @@
 	m_nopost_Init(ModCmdsInfo);
 	m_issecure_Init(ModCmdsInfo);
 	m_cap_Init(ModCmdsInfo);
+	m_sasl_Init(ModCmdsInfo);
 #ifdef GUEST
 	m_guest_Init(ModCmdsInfo);
 #endif
@@ -482,6 +486,7 @@
 	m_nopost_Load(module_load);
 	m_issecure_Load(module_load);
 	m_cap_Load(module_load);
+	m_sasl_Load(module_load);
 #ifdef GUEST
 	m_guest_Load(module_load);
 #endif
@@ -598,6 +603,7 @@
 	m_nopost_Unload();
 	m_issecure_Unload();
 	m_cap_Unload();
+	m_sasl_Unload();
 #ifdef GUEST
 	m_guest_Unload();
 #endif
diff -r b60e98d7b61e src/modules/m_cap.c
--- a/src/modules/m_cap.c	Tue Mar 06 06:16:53 2012 +0000
+++ b/src/modules/m_cap.c	Tue Mar 06 00:33:30 2012 -0600
@@ -73,6 +73,7 @@
 
 static struct clicap clicap_table[] = {
 	{"multi-prefix", PROTO_NAMESX, CLICAP_FLAGS_NONE},
+	{"sasl", PROTO_SASL, CLICAP_FLAGS_NONE},
 #ifdef USE_SSL
 	{"tls", PROTO_STARTTLS, CLICAP_FLAGS_NONE},
 #endif
diff -r b60e98d7b61e src/modules/m_sasl.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/modules/m_sasl.c	Tue Mar 06 00:33:30 2012 -0600
@@ -0,0 +1,300 @@
+/*
+ *   IRC - Internet Relay Chat, src/modules/m_sasl.c
+ *   (C) 2012 The UnrealIRCd Team
+ *
+ *   See file AUTHORS in IRC package for additional names of
+ *   the programmers.
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 1, or (at your option)
+ *   any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "config.h"
+#include "struct.h"
+#include "common.h"
+#include "sys.h"
+#include "numeric.h"
+#include "msg.h"
+#include "proto.h"
+#include "channel.h"
+#include <time.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _WIN32
+#include <io.h>
+#endif
+#include <fcntl.h>
+#include "h.h"
+#ifdef STRIPBADWORDS
+#include "badwords.h"
+#endif
+#ifdef _WIN32
+#include "version.h"
+#endif
+
+#define MSG_AUTHENTICATE "AUTHENTICATE"
+#define TOK_AUTHENTICATE "SX"
+
+#define MSG_SASL "SASL"
+#define TOK_SASL "SY"
+
+#define MSG_SVSLOGIN "SVSLOGIN"
+#define TOK_SVSLOGIN "SZ"
+
+/*
+ * This is a "lightweight" SASL implementation/stack which uses psuedo-identifiers
+ * to identify connecting clients.  In Unreal 3.3, we should use real identifiers
+ * so that SASL sessions can be correlated.
+ *
+ * The following people were involved in making the current iteration of SASL over
+ * IRC which allowed psuedo-identifiers:
+ *
+ * danieldg, Daniel de Graff <danieldg@inspircd.org>
+ * jilles, Jilles Tjoelker <jilles@stack.nl>
+ * Jobe, Matthew Beeching <jobe@mdbnet.co.uk>
+ * gxti, Michael Tharp <gxti@partiallystapled.com>
+ * nenolod, William Pitcock <nenolod@dereferenced.org>
+ *
+ * Thanks also to all of the client authors which have implemented SASL in their
+ * clients.  With the backwards-compatibility layer allowing "lightweight" SASL
+ * implementations, we now truly have a universal authentication mechanism for
+ * IRC.
+ */
+
+/*
+ * decode_puid
+ *
+ * Decode PUID sent from a SASL agent.  If the servername in the PUID doesn't match
+ * ours, we reject the PUID (by returning NULL).
+ */
+static aClient *
+decode_puid(char *puid)
+{
+	char *it;
+	int slot;
+
+	if ((it = strrchr(puid, '!')) == NULL)
+		return NULL;
+
+	*it++ = '\0';
+	slot = atoi(it);
+
+	if (stricmp(me.name, puid))
+		return NULL;
+
+	return local[slot];
+}
+
+/*
+ * encode_puid
+ *
+ * Encode PUID based on aClient.
+ */
+static const char *
+encode_puid(aClient *client)
+{
+	static char buf[BUFSIZE];
+
+	snprintf(buf, sizeof buf, "%s!%d", me.name, client->slot);
+
+	return buf;
+}
+
+/*
+ * SVSLOGIN message
+ *
+ * parv[0]: source
+ * parv[1]: propagation mask
+ * parv[2]: target PUID
+ * parv[3]: ESVID
+ */
+static int
+m_svslogin(aClient *client_p, aClient *source_p, int parc, char *parv[])
+{
+	if (!stricmp(parv[1], me.name))
+	{
+		aClient *target_p;
+
+		/* is the PUID valid? */
+		if ((target_p = decode_puid(parv[2])) == NULL)
+			return 0;
+
+		if (target_p->user == NULL)
+			make_user(target_p);
+
+		strlcpy(target_p->user->svid, parv[3], sizeof(target_p->user->svid));
+
+		sendto_one(target_p, err_str(RPL_LOGGEDIN), me.name,
+			   BadPtr(target_p->name) ? "*" : target_p->name,
+			   BadPtr(target_p->name) ? "*" : target_p->name,
+			   BadPtr(target_p->user->username) ? "*" : target_p->user->username,
+			   BadPtr(target_p->user->realhost) ? "*" : target_p->user->realhost,
+			   target_p->user->svid, target_p->user->svid);
+
+		return 0;
+	}
+
+	/* not for us; propagate. */
+	sendto_serv_butone_token(client_p, parv[0], MSG_SVSLOGIN, TOK_SVSLOGIN, "%s %s %s",
+				 parv[1], parv[2], parv[3]);
+
+	return 0;
+}
+
+/*
+ * SASL message
+ *
+ * parv[0]: prefix
+ * parv[1]: distribution mask
+ * parv[2]: target PUID
+ * parv[3]: mode/state
+ * parv[4]: data
+ * parv[5]: out-of-bound data
+ */
+static int
+m_sasl(aClient *client_p, aClient *source_p, int parc, char *parv[])
+{
+	if (!stricmp(parv[1], me.name))
+	{
+		aClient *target_p;
+
+		/* is the PUID valid? */
+		if ((target_p = decode_puid(parv[2])) == NULL)
+			return 0;
+
+		if (target_p->user == NULL)
+			make_user(target_p);
+
+		/* reject if another SASL agent is answering */
+		if (*target_p->sasl_agent && stricmp(parv[0], target_p->sasl_agent))
+			return 0;
+		else
+			strlcpy(target_p->sasl_agent, parv[0], sizeof(target_p->sasl_agent));
+
+		if (*parv[3] == 'C')
+			sendto_one(target_p, "AUTHENTICATE %s", parv[4]);
+		else if (*parv[3] == 'D')
+		{
+			if (*parv[4] == 'F')
+				sendto_one(target_p, err_str(ERR_SASLFAIL), me.name, BadPtr(target_p->name) ? "*" : target_p->name);
+			else if (*parv[4] == 'S')
+			{
+				target_p->sasl_complete++;
+				sendto_one(target_p, err_str(RPL_SASLSUCCESS), me.name, BadPtr(target_p->name) ? "*" : target_p->name);
+			}
+
+			*target_p->sasl_agent = '\0';
+		}
+
+		return 0;
+	}
+
+	/* not for us; propagate. */
+	sendto_serv_butone_token(client_p, parv[0], MSG_SASL, TOK_SASL, "%s %s %c %s %s",
+				 parv[1], parv[2], *parv[3], parv[4], parc > 5 ? parv[5] : "");
+
+	return 0;
+}
+
+/*
+ * AUTHENTICATE message
+ *
+ * parv[0]: prefix
+ * parv[1]: data
+ */
+static int
+m_authenticate(aClient *client_p, aClient *source_p, int parc, char *parv[])
+{
+	aClient *agent_p;
+
+	/* Failing to use CAP REQ for sasl is a protocol violation. */
+	if (!CHECKPROTO(source_p, PROTO_SASL))
+		return 0;
+
+	if (source_p->sasl_complete)
+	{
+		sendto_one(source_p, err_str(ERR_SASLALREADY), me.name, BadPtr(source_p->name) ? "*" : source_p->name);
+		return 0;
+	}
+
+	if (strlen(parv[1]) > 400)
+	{
+		sendto_one(source_p, err_str(ERR_SASLTOOLONG), me.name, BadPtr(source_p->name) ? "*" : source_p->name);
+		return 0;
+	}
+
+	if (*source_p->sasl_agent)
+		agent_p = find_client(source_p->sasl_agent, NULL);
+
+	if (agent_p == NULL)
+		sendto_serv_butone_token(NULL, me.name, MSG_SASL, TOK_SASL, "* %s S %s", encode_puid(source_p), parv[1]);
+	else
+		sendto_serv_butone_token(NULL, me.name, MSG_SASL, TOK_SASL, "%s %s C %s", agent_p->user->server, encode_puid(source_p), parv[1]);
+
+	source_p->sasl_out++;
+
+	return 0;
+}
+
+static int
+abort_sasl(struct Client *client_p)
+{
+	if (client_p->sasl_out == 0 || client_p->sasl_complete)
+		return 0;
+
+	client_p->sasl_out = client_p->sasl_complete = 0;
+	sendto_one(client_p, err_str(ERR_SASLABORTED), me.name, BadPtr(client_p->name) ? "*" : client_p->name);
+
+	if (*client_p->sasl_agent)
+	{
+		aClient *agent_p = find_client(client_p->sasl_agent, NULL);
+
+		if (agent_p != NULL)
+		{
+			sendto_serv_butone_token(NULL, me.name, MSG_SASL, TOK_SASL, "%s %s D A", agent_p->user->server, encode_puid(client_p));
+			return 0;
+		}
+	}
+
+	sendto_serv_butone_token(NULL, me.name, MSG_SASL, TOK_SASL, "* %s D A", encode_puid(client_p));
+}
+
+/* This is called on module init, before Server Ready */
+DLLFUNC int MOD_INIT(m_sasl)(ModuleInfo *modinfo)
+{
+	MARK_AS_OFFICIAL_MODULE(modinfo);
+
+	CommandAdd(modinfo->handle, MSG_SASL, TOK_SASL, m_sasl, MAXPARA, M_USER|M_SERVER);
+	CommandAdd(modinfo->handle, MSG_SVSLOGIN, TOK_SVSLOGIN, m_svslogin, MAXPARA, M_USER|M_SERVER);
+	CommandAdd(modinfo->handle, MSG_AUTHENTICATE, TOK_AUTHENTICATE, m_authenticate, MAXPARA, M_UNREGISTERED|M_USER);
+
+	HookAdd(HOOKTYPE_LOCAL_CONNECT, abort_sasl);
+	HookAdd(HOOKTYPE_LOCAL_QUIT, abort_sasl);
+
+	return MOD_SUCCESS;
+}
+
+/* Is first run when server is 100% ready */
+DLLFUNC int MOD_LOAD(m_sasl)(int module_load)
+{
+	return MOD_SUCCESS;
+}
+
+/* Called when module is unloaded */
+DLLFUNC int MOD_UNLOAD(m_sasl)(int module_unload)
+{
+	return MOD_SUCCESS;
+}
diff -r b60e98d7b61e src/s_err.c
--- a/src/s_err.c	Tue Mar 06 06:16:53 2012 +0000
+++ b/src/s_err.c	Tue Mar 06 00:33:30 2012 -0600
@@ -956,14 +956,14 @@
 /* 897 */ NULL,
 /* 898 */ NULL,
 /* 899 */ NULL,
-/* 900 */ NULL,
-/* 901 */ NULL,
-/* 902 */ NULL,
-/* 903 */ NULL,
-/* 904 */ NULL,
-/* 905 */ NULL,
-/* 906 */ NULL,
-/* 907 */ NULL,
+/* 900 RPL_LOGGEDIN */          ":%s 900 %s %s!%s@%s %s :You are now logged in as %s.",
+/* 901 RPL_LOGGEDOUT */         ":%s 901 %s %s!%s@%s :You are now logged out.",
+/* 902 ERR_NICKLOCKED */        ":%s 902 %s :You must use a nick assigned to you.",
+/* 903 RPL_SASLSUCCESS */       ":%s 903 %s :SASL authentication successful",
+/* 904 ERR_SASLFAIL */          ":%s 904 %s :SASL authentication failed",
+/* 905 ERR_SASLTOOLONG */       ":%s 905 %s :SASL message too long",
+/* 906 ERR_SASLABORTED */       ":%s 906 %s :SASL authentication aborted",
+/* 907 ERR_SASLALREADY */       ":%s 907 %s :You have already completed SASL authentication",
 /* 908 */ NULL,
 /* 909 */ NULL,
 /* 910 */ NULL,
