about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ngircd/channel.c29
-rw-r--r--src/ngircd/client.c70
-rw-r--r--src/ngircd/client.h3
-rw-r--r--src/ngircd/conf.c46
-rw-r--r--src/ngircd/conf.h7
-rw-r--r--src/ngircd/conn-ssl.c2
-rw-r--r--src/ngircd/conn.c118
-rw-r--r--src/ngircd/conn.h11
-rw-r--r--src/ngircd/defines.h4
-rw-r--r--src/ngircd/io.c14
-rw-r--r--src/ngircd/irc-cap.c4
-rw-r--r--src/ngircd/irc-info.c29
-rw-r--r--src/ngircd/irc-login.c2
-rw-r--r--src/ngircd/irc-mode.c23
-rw-r--r--src/ngircd/irc-server.c3
-rw-r--r--src/ngircd/irc.c8
-rw-r--r--src/ngircd/login.c7
-rw-r--r--src/ngircd/match.c49
-rw-r--r--src/ngircd/match.h12
-rw-r--r--src/ngircd/messages.h22
-rw-r--r--src/ngircd/pam.c4
-rw-r--r--src/tool/tool.c18
22 files changed, 347 insertions, 138 deletions
diff --git a/src/ngircd/channel.c b/src/ngircd/channel.c
index 90d2efab..8d001a82 100644
--- a/src/ngircd/channel.c
+++ b/src/ngircd/channel.c
@@ -66,16 +66,8 @@ static void Set_KeyFile PARAMS((CHANNEL *Chan, const char *KeyFile));
 GLOBAL void
 Channel_Init( void )
 {
-	CHANNEL *sc;
-
 	My_Channels = NULL;
 	My_Cl2Chan = NULL;
-
-	sc = Channel_Create("&SERVER");
-	if (sc) {
-		Channel_SetModes(sc, "mnPt");
-		Channel_SetTopic(sc, Client_ThisServer(), "Server Messages");
-	}
 } /* Channel_Init */
 
 
@@ -103,11 +95,12 @@ Channel_GetListInvites(CHANNEL *c)
 }
 
 
+/**
+ * Generate predefined persistent channels and &SERVER
+ */
 GLOBAL void
 Channel_InitPredefined( void )
 {
-	/* Generate predefined persistent channels */
-
 	CHANNEL *new_chan;
 	const struct Conf_Channel *conf_chan;
 	const char *c;
@@ -160,6 +153,18 @@ Channel_InitPredefined( void )
 	}
 	if (channel_count)
 		array_free(&Conf_Channels);
+
+	/* Make sure the local &SERVER channel exists */
+	if (!Channel_Search("&SERVER")) {
+		new_chan = Channel_Create("&SERVER");
+		if (new_chan) {
+			Channel_SetModes(new_chan, "mnPt");
+			Channel_SetTopic(new_chan, Client_ThisServer(),
+					 "Server Messages");
+		} else
+			Log(LOG_ERR, "Failed to create \"&SERVER\" channel!");
+	} else
+		LogDebug("Required channel \"&SERVER\" already exists, ok.");
 } /* Channel_InitPredefined */
 
 
@@ -877,6 +882,10 @@ Can_Send_To_Channel(CHANNEL *Chan, CLIENT *From)
 	if (strchr(Channel_Modes(Chan), 'n') && !is_member)
 		return false;
 
+	if (strchr(Channel_Modes(Chan), 'M') && !Client_HasMode(From, 'R')
+	    && !Client_HasMode(From, 'o'))
+		return false;
+
 	if (has_voice || is_halfop || is_op || is_chanadmin || is_owner)
 		return true;
 
diff --git a/src/ngircd/client.c b/src/ngircd/client.c
index 49e27395..4728c7a4 100644
--- a/src/ngircd/client.c
+++ b/src/ngircd/client.c
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2010 Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de)
  *
  * 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
@@ -441,18 +441,6 @@ Client_SetFlags( CLIENT *Client, const char *Flags )
 
 
 GLOBAL void
-Client_SetPassword( CLIENT *Client, const char *Pwd )
-{
-	/* set password sent by client */
-
-	assert( Client != NULL );
-	assert( Pwd != NULL );
-
-	strlcpy(Client->pwd, Pwd, sizeof(Client->pwd));
-} /* Client_SetPassword */
-
-
-GLOBAL void
 Client_SetAway( CLIENT *Client, const char *Txt )
 {
 	/* Set AWAY reason of client */
@@ -699,27 +687,36 @@ Client_Hostname(CLIENT *Client)
 
 /**
  * Get potentially cloaked hostname of a client.
+ *
  * If the client has not enabled cloaking, the real hostname is used.
+ * Please note that this function uses a global static buffer, so you can't
+ * nest invocations without overwriting earlier results!
+ *
  * @param Client Pointer to client structure
  * @return Pointer to client hostname
  */
 GLOBAL char *
 Client_HostnameCloaked(CLIENT *Client)
 {
+	static char Cloak_Buffer[CLIENT_HOST_LEN];
+
 	assert(Client != NULL);
-	if (Client_HasMode(Client, 'x'))
-		return Client_ID(Client->introducer);
-	else
+
+	if (!Client_HasMode(Client, 'x'))
 		return Client_Hostname(Client);
-} /* Client_HostnameCloaked */
 
+	/* Do simple mapping to the server ID? */
+	if (!*Conf_CloakHostModeX)
+		return Client_ID(Client->introducer);
 
-GLOBAL char *
-Client_Password( CLIENT *Client )
-{
-	assert( Client != NULL );
-	return Client->pwd;
-} /* Client_Password */
+	strlcpy(Cloak_Buffer, Client->host, CLIENT_HOST_LEN);
+	strlcat(Cloak_Buffer, Conf_CloakHostSalt, CLIENT_HOST_LEN);
+
+	snprintf(Cloak_Buffer, CLIENT_HOST_LEN, Conf_CloakHostModeX,
+		 Hash(Cloak_Buffer));
+
+	return Cloak_Buffer;
+} /* Client_HostnameCloaked */
 
 
 GLOBAL char *
@@ -812,10 +809,12 @@ Client_Mask( CLIENT *Client )
 
 /**
  * Return ID of a client with cloaked hostname: "client!user@server-name"
+ *
  * This client ID is used for IRC prefixes, for example.
  * Please note that this function uses a global static buffer, so you can't
  * nest invocations without overwriting earlier results!
  * If the client has not enabled cloaking, the real hostname is used.
+ *
  * @param Client Pointer to client structure
  * @return Pointer to global buffer containing the client ID
  */
@@ -823,7 +822,6 @@ GLOBAL char *
 Client_MaskCloaked(CLIENT *Client)
 {
 	static char Mask_Buffer[GETID_LEN];
-	char Cloak_Buffer[GETID_LEN];
 
 	assert (Client != NULL);
 
@@ -831,16 +829,8 @@ Client_MaskCloaked(CLIENT *Client)
 	if (!Client_HasMode(Client, 'x'))
 		return Client_Mask(Client);
 
-	if(*Conf_CloakHostModeX) {
-		strlcpy(Cloak_Buffer, Client->host, GETID_LEN);
-		strlcat(Cloak_Buffer, Conf_CloakHostSalt, GETID_LEN);
-		snprintf(Cloak_Buffer, GETID_LEN, Conf_CloakHostModeX, Hash(Cloak_Buffer));
-	} else {
-		strncpy(Cloak_Buffer, Client_ID(Client->introducer), GETID_LEN);
-	}
-
-	snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s",
-		Client->id, Client->user, Cloak_Buffer);
+	snprintf(Mask_Buffer, GETID_LEN, "%s!%s@%s", Client->id, Client->user,
+		 Client_HostnameCloaked(Client));
 
 	return Mask_Buffer;
 } /* Client_MaskCloaked */
@@ -905,6 +895,16 @@ Client_CheckNick(CLIENT *Client, char *Nick)
 		return false;
 	}
 
+	if (Client_Type(Client) != CLIENT_SERVER
+	    && Client_Type(Client) != CLIENT_SERVICE) {
+		/* Make sure that this isn't a restricted/forbidden nick name */
+		if (Conf_NickIsBlocked(Nick)) {
+			IRC_WriteStrClient(Client, ERR_FORBIDDENNICKNAME_MSG,
+					   Client_ID(Client), Nick);
+			return false;
+		}
+	}
+
 	/* Nickname already registered? */
 	if (Client_Search(Nick)) {
 		IRC_WriteStrClient(Client, ERR_NICKNAMEINUSE_MSG,
@@ -1175,7 +1175,7 @@ Client_Introduce(CLIENT *From, CLIENT *Client, int Type)
 	Client_SetType(Client, Type);
 
 	if (From) {
-		if (Conf_IsService(Conf_GetServer(Client_Conn(From)),
+		if (Conf_NickIsService(Conf_GetServer(Client_Conn(From)),
 				   Client_ID(Client)))
 			Client_SetType(Client, CLIENT_SERVICE);
 		LogDebug("%s \"%s\" (+%s) registered (via %s, on %s, %d hop%s).",
diff --git a/src/ngircd/client.h b/src/ngircd/client.h
index 4dbcc7a0..16b2a61a 100644
--- a/src/ngircd/client.h
+++ b/src/ngircd/client.h
@@ -47,7 +47,6 @@ typedef struct _CLIENT
 	CONN_ID conn_id;		/* ID of the connection (if local) or NONE (remote) */
 	struct _CLIENT *introducer;	/* ID of the servers which the client is connected to */
 	struct _CLIENT *topserver;	/* toplevel servers (only valid if client is a server) */
-	char pwd[CLIENT_PASS_LEN];	/* password received of the client */
 	char host[CLIENT_HOST_LEN];	/* hostname of the client */
 	char user[CLIENT_USER_LEN];	/* user name ("login") */
 #if defined(PAM) && defined(IDENTAUTH)
@@ -109,7 +108,6 @@ GLOBAL char *Client_OrigUser PARAMS(( CLIENT *Client ));
 #endif
 GLOBAL char *Client_Hostname PARAMS(( CLIENT *Client ));
 GLOBAL char *Client_HostnameCloaked PARAMS(( CLIENT *Client ));
-GLOBAL char *Client_Password PARAMS(( CLIENT *Client ));
 GLOBAL char *Client_Modes PARAMS(( CLIENT *Client ));
 GLOBAL char *Client_Flags PARAMS(( CLIENT *Client ));
 GLOBAL CLIENT *Client_Introducer PARAMS(( CLIENT *Client ));
@@ -129,7 +127,6 @@ GLOBAL void Client_SetID PARAMS(( CLIENT *Client, const char *Nick ));
 GLOBAL void Client_SetUser PARAMS(( CLIENT *Client, const char *User, bool Idented ));
 GLOBAL void Client_SetOrigUser PARAMS(( CLIENT *Client, const char *User ));
 GLOBAL void Client_SetInfo PARAMS(( CLIENT *Client, const char *Info ));
-GLOBAL void Client_SetPassword PARAMS(( CLIENT *Client, const char *Pwd ));
 GLOBAL void Client_SetType PARAMS(( CLIENT *Client, int Type ));
 GLOBAL void Client_SetHops PARAMS(( CLIENT *Client, int Hops ));
 GLOBAL void Client_SetToken PARAMS(( CLIENT *Client, int Token ));
diff --git a/src/ngircd/conf.c b/src/ngircd/conf.c
index b0911373..627e6d3f 100644
--- a/src/ngircd/conf.c
+++ b/src/ngircd/conf.c
@@ -346,7 +346,7 @@ Conf_Test( void )
 
 	puts("[LIMITS]");
 	printf("  ConnectRetry = %d\n", Conf_ConnectRetry);
-	printf("  MaxConnections = %ld\n", Conf_MaxConnections);
+	printf("  MaxConnections = %d\n", Conf_MaxConnections);
 	printf("  MaxConnectionsIP = %d\n", Conf_MaxConnectionsIP);
 	printf("  MaxJoins = %d\n", Conf_MaxJoins > 0 ? Conf_MaxJoins : -1);
 	printf("  MaxNickLength = %u\n", Conf_MaxNickLength - 1);
@@ -636,14 +636,41 @@ Conf_AddServer(const char *Name, UINT16 Port, const char *Host,
 }
 
 /**
- * Check if the given nick name is an service.
+ * Check if the given nick name is reserved for services on a particular server.
  *
+ * @param ConfServer The server index to check.
+ * @param Nick The nick name to check.
  * @returns true if the given nick name belongs to an "IRC service".
  */
 GLOBAL bool
-Conf_IsService(int ConfServer, const char *Nick)
+Conf_NickIsService(int ConfServer, const char *Nick)
 {
-	return MatchCaseInsensitive(Conf_Server[ConfServer].svs_mask, Nick);
+	assert (ConfServer >= 0);
+	assert (ConfServer < MAX_SERVERS);
+
+	return MatchCaseInsensitiveList(Conf_Server[ConfServer].svs_mask,
+					Nick, ",");
+}
+
+/**
+ * Check if the given nick name is blocked for "normal client" use.
+ *
+ * @param ConfServer The server index or NONE to check all configured servers.
+ * @param Nick The nick name to check.
+ * @returns true if the given nick name belongs to an "IRC service".
+ */
+GLOBAL bool
+Conf_NickIsBlocked(const char *Nick)
+{
+	int i;
+
+	for(i = 0; i < MAX_SERVERS; i++) {
+		if (!Conf_Server[i].name[0])
+			continue;
+		if (Conf_NickIsService(i, Nick))
+			return true;
+	}
+	return false;
 }
 
 /**
@@ -653,7 +680,7 @@ static void
 Set_Defaults(bool InitServers)
 {
 	int i;
-	char random[RANDOM_SALT_LEN];
+	char random[RANDOM_SALT_LEN + 1];
 
 	/* Global */
 	strcpy(Conf_ServerName, "");
@@ -1405,7 +1432,7 @@ Handle_LIMITS(int Line, char *Var, char *Arg)
 		return;
 	}
 	if (strcasecmp(Var, "MaxConnections") == 0) {
-		Conf_MaxConnections = atol(Arg);
+		Conf_MaxConnections = atoi(Arg);
 		if (!Conf_MaxConnections && strcmp(Arg, "0"))
 			Config_Error_NaN(Line, Var);
 		return;
@@ -1884,6 +1911,13 @@ Validate_Config(bool Configtest, bool Rehash)
 	bool config_valid = true;
 	char *ptr;
 
+	/* Emit a warning when the config file is not a full path name */
+	if (NGIRCd_ConfFile[0] && NGIRCd_ConfFile[0] != '/') {
+		Config_Error(LOG_WARNING,
+			"Not specifying a full path name to \"%s\" can cause problems when rehashing the server!",
+			NGIRCd_ConfFile);
+	}
+
 	/* Validate configured server name, see RFC 2812 section 2.3.1 */
 	ptr = Conf_ServerName;
 	do {
diff --git a/src/ngircd/conf.h b/src/ngircd/conf.h
index 4e7e3796..7a4e38aa 100644
--- a/src/ngircd/conf.h
+++ b/src/ngircd/conf.h
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001-2011 Alexander Barton (alex@barton.de) and Contributors.
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
  *
  * 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
@@ -206,7 +206,7 @@ GLOBAL bool Conf_ConnectIPv6;
 GLOBAL bool Conf_ConnectIPv4;
 
 /** Maximum number of simultaneous connections to this server */
-GLOBAL long Conf_MaxConnections;
+GLOBAL int Conf_MaxConnections;
 
 /** Maximum number of channels a user can join */
 GLOBAL int Conf_MaxJoins;
@@ -244,7 +244,8 @@ GLOBAL bool Conf_EnablePassiveServer PARAMS((const char *Name));
 GLOBAL bool Conf_DisableServer PARAMS(( const char *Name ));
 GLOBAL bool Conf_AddServer PARAMS(( const char *Name, UINT16 Port, const char *Host, const char *MyPwd, const char *PeerPwd ));
 
-GLOBAL bool Conf_IsService PARAMS((int ConfServer, const char *Nick));
+GLOBAL bool Conf_NickIsService PARAMS((int ConfServer, const char *Nick));
+GLOBAL bool Conf_NickIsBlocked PARAMS((const char *Nick));
 
 /* Password required by WEBIRC command */
 GLOBAL char Conf_WebircPwd[CLIENT_PASS_LEN];
diff --git a/src/ngircd/conn-ssl.c b/src/ngircd/conn-ssl.c
index 5d44b30f..8f7b70af 100644
--- a/src/ngircd/conn-ssl.c
+++ b/src/ngircd/conn-ssl.c
@@ -625,6 +625,8 @@ ConnectAccept( CONNECTION *c, bool connect)
 #endif /* _GNUTLS */
 	Conn_OPTION_DEL(c, (CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ|CONN_SSL_CONNECT));
 	ConnSSL_LogCertInfo(c);
+
+	Conn_StartLogin(CONNECTION2ID(c));
 	return 1;
 }
 
diff --git a/src/ngircd/conn.c b/src/ngircd/conn.c
index 06236fd4..81a0f450 100644
--- a/src/ngircd/conn.c
+++ b/src/ngircd/conn.c
@@ -88,7 +88,7 @@
 
 static bool Handle_Write PARAMS(( CONN_ID Idx ));
 static bool Conn_Write PARAMS(( CONN_ID Idx, char *Data, size_t Len ));
-static int New_Connection PARAMS(( int Sock ));
+static int New_Connection PARAMS(( int Sock, bool IsSSL ));
 static CONN_ID Socket2Index PARAMS(( int Sock ));
 static void Read_Request PARAMS(( CONN_ID Idx ));
 static unsigned int Handle_Buffer PARAMS(( CONN_ID Idx ));
@@ -134,7 +134,7 @@ static void
 cb_listen(int sock, short irrelevant)
 {
 	(void) irrelevant;
-	(void) New_Connection(sock);
+	(void) New_Connection(sock, false);
 }
 
 
@@ -152,7 +152,7 @@ cb_listen_ssl(int sock, short irrelevant)
 	int fd;
 
 	(void) irrelevant;
-	fd = New_Connection(sock);
+	fd = New_Connection(sock, true);
 	if (fd < 0)
 		return;
 	io_event_setcb(My_Connections[fd].sock, cb_clientserver_ssl);
@@ -918,6 +918,30 @@ va_dcl
 	return ok;
 } /* Conn_WriteStr */
 
+GLOBAL char*
+Conn_Password( CONN_ID Idx )
+{
+	assert( Idx > NONE );
+	if (My_Connections[Idx].pwd == NULL)
+		return (char*)"\0";
+	else
+		return My_Connections[Idx].pwd;
+} /* Conn_Password */
+
+GLOBAL void
+Conn_SetPassword( CONN_ID Idx, const char *Pwd )
+{
+	assert( Idx > NONE );
+
+	if (My_Connections[Idx].pwd)
+		free(My_Connections[Idx].pwd);
+
+	My_Connections[Idx].pwd = strdup(Pwd);
+	if (My_Connections[Idx].pwd == NULL) {
+		Log(LOG_EMERG, "Can't allocate memory! [Conn_SetPassword]");
+		exit(1);
+	}
+} /* Conn_SetPassword */
 
 /**
  * Append Data to the outbound write buffer of a connection.
@@ -1146,6 +1170,8 @@ Conn_Close( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClie
 
 	array_free(&My_Connections[Idx].rbuf);
 	array_free(&My_Connections[Idx].wbuf);
+	if (My_Connections[Idx].pwd != NULL)
+		free(My_Connections[Idx].pwd);
 
 	/* Clean up connection structure (=free it) */
 	Init_Conn_Struct( Idx );
@@ -1336,17 +1362,18 @@ Count_Connections(ng_ipaddr_t *a)
  * Initialize new client connection on a listening socket.
  *
  * @param Sock	Listening socket descriptor.
+ * @param IsSSL	true if this socket expects SSL-encrypted data.
  * @returns	Accepted socket descriptor or -1 on error.
  */
 static int
-New_Connection(int Sock)
+New_Connection(int Sock, bool IsSSL)
 {
 #ifdef TCPWRAP
 	struct request_info req;
 #endif
 	ng_ipaddr_t new_addr;
 	char ip_str[NG_INET_ADDRSTRLEN];
-	int new_sock, new_sock_len, identsock;
+	int new_sock, new_sock_len;
 	CLIENT *c;
 	long cnt;
 
@@ -1466,30 +1493,56 @@ New_Connection(int Sock)
 	Log(LOG_INFO, "Accepted connection %d from %s:%d on socket %d.",
 	    new_sock, My_Connections[new_sock].host,
 	    ng_ipaddr_getport(&new_addr), Sock);
+	Account_Connection();
+
+#ifdef SSL_SUPPORT
+	/* Delay connection initalization until SSL handshake is finished */
+	if (!IsSSL)
+#endif
+		Conn_StartLogin(new_sock);
+
+	return new_sock;
+} /* New_Connection */
+
+
+/**
+ * Finish connection initialization, start resolver subprocess.
+ *
+ * @param Idx Connection index.
+ */
+GLOBAL void
+Conn_StartLogin(CONN_ID Idx)
+{
+	int ident_sock = -1;
+
+	assert(Idx >= 0);
+
+	/* Nothing to do if DNS (and resolver subprocess) is disabled */
+	if (!Conf_DNS)
+		return;
 
-	identsock = new_sock;
 #ifdef IDENTAUTH
-	if (!Conf_Ident)
-		identsock = -1;
+	/* Should we make an IDENT request? */
+	if (Conf_Ident)
+		ident_sock = My_Connections[Idx].sock;
 #endif
-	if (Conf_DNS) {
-		if (Conf_NoticeAuth) {
+
+	if (Conf_NoticeAuth) {
+		/* Send "NOTICE AUTH" messages to the client */
 #ifdef IDENTAUTH
-			if (Conf_Ident)
-				(void)Conn_WriteStr(new_sock,
-					"NOTICE AUTH :*** Looking up your hostname and checking ident");
-			else
+		if (Conf_Ident)
+			(void)Conn_WriteStr(Idx,
+				"NOTICE AUTH :*** Looking up your hostname and checking ident");
+		else
 #endif
-				(void)Conn_WriteStr(new_sock,
-					"NOTICE AUTH :*** Looking up your hostname");
-		}
-		Resolve_Addr(&My_Connections[new_sock].proc_stat, &new_addr,
-			     identsock, cb_Read_Resolver_Result);
+			(void)Conn_WriteStr(Idx,
+				"NOTICE AUTH :*** Looking up your hostname");
+		(void)Handle_Write(Idx);
 	}
 
-	Account_Connection();
-	return new_sock;
-} /* New_Connection */
+	Resolve_Addr(&My_Connections[Idx].proc_stat, &My_Connections[Idx].addr,
+		     ident_sock, cb_Read_Resolver_Result);
+}
 
 
 /**
@@ -1839,10 +1892,10 @@ Check_Connections(void)
 				if (My_Connections[i].lastping <
 				    time(NULL) - Conf_PongTimeout) {
 					/* Timeout */
-					LogDebug
-					    ("Connection %d: Ping timeout: %d seconds.",
-					     i, Conf_PongTimeout);
-					snprintf(msg, sizeof(msg), "Ping timeout: %d seconds", Conf_PongTimeout);
+					snprintf(msg, sizeof(msg),
+						 "Ping timeout: %d seconds",
+						 Conf_PongTimeout);
+					LogDebug("Connection %d: %s.", i, msg);
 					Conn_Close(i, NULL, msg, true);
 				}
 			} else if (My_Connections[i].lastdata <
@@ -2231,7 +2284,8 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events )
 		Client_SetHostname(c, readbuf);
 		if (Conf_NoticeAuth)
 			(void)Conn_WriteStr(i,
-					"NOTICE AUTH :*** Found your hostname");
+					"NOTICE AUTH :*** Found your hostname: %s",
+					My_Connections[i].host);
 #ifdef IDENTAUTH
 		++identptr;
 		if (*identptr) {
@@ -2256,8 +2310,10 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events )
 			}
 			if (Conf_NoticeAuth) {
 				(void)Conn_WriteStr(i,
-					"NOTICE AUTH :*** Got %sident response",
-					*ptr ? "invalid " : "");
+					"NOTICE AUTH :*** Got %sident response%s%s",
+					*ptr ? "invalid " : "",
+					*ptr ? "" : ": ",
+					*ptr ? "" : identptr);
 			}
 		} else {
 			Log(LOG_INFO, "IDENT lookup for connection %d: no result.", i);
@@ -2266,6 +2322,10 @@ cb_Read_Resolver_Result( int r_fd, UNUSED short events )
 					"NOTICE AUTH :*** No ident response");
 		}
 #endif
+
+		if (Conf_NoticeAuth)
+			(void)Handle_Write(i);
+
 		Class_HandleServerBans(c);
 	}
 #ifdef DEBUG
diff --git a/src/ngircd/conn.h b/src/ngircd/conn.h
index 4752ec1e..e42a2ae6 100644
--- a/src/ngircd/conn.h
+++ b/src/ngircd/conn.h
@@ -42,7 +42,7 @@
 #define CONN_SSL_WANT_READ	128	/* SSL/TLS library needs to read protocol data */
 #define CONN_SSL_FLAGS_ALL	(CONN_SSL_CONNECT|CONN_SSL|CONN_SSL_WANT_WRITE|CONN_SSL_WANT_READ)
 #endif
-typedef long CONN_ID;
+typedef int CONN_ID;
 
 #include "client.h"
 #include "proc.h"
@@ -72,6 +72,7 @@ typedef struct _Connection
 	ng_ipaddr_t addr;		/* Client address */
 	PROC_STAT proc_stat;		/* Status of resolver process */
 	char host[HOST_LEN];		/* Hostname */
+	char *pwd;			/* password received of the client */
 	array rbuf;			/* Read buffer */
 	array wbuf;			/* Write buffer */
 	time_t signon;			/* Signon ("connect") time */
@@ -100,6 +101,8 @@ GLOBAL CONNECTION *My_Connections;
 GLOBAL CONN_ID Pool_Size;
 GLOBAL long WCounter;
 
+#define CONNECTION2ID(x) (long)(x - My_Connections)
+
 #endif /* CONN_MODULE */
 
 
@@ -111,10 +114,15 @@ GLOBAL void Conn_CloseAllSockets PARAMS((int ExceptOf));
 GLOBAL unsigned int Conn_InitListeners PARAMS(( void ));
 GLOBAL void Conn_ExitListeners PARAMS(( void ));
 
+GLOBAL void Conn_StartLogin PARAMS((CONN_ID Idx));
+
 GLOBAL void Conn_Handler PARAMS(( void ));
 
 GLOBAL bool Conn_WriteStr PARAMS(( CONN_ID Idx, const char *Format, ... ));
 
+GLOBAL char* Conn_Password PARAMS(( CONN_ID Idx ));
+GLOBAL void Conn_SetPassword PARAMS(( CONN_ID Idx, const char *Pwd ));
+
 GLOBAL void Conn_Close PARAMS(( CONN_ID Idx, const char *LogMsg, const char *FwdMsg, bool InformClient ));
 
 GLOBAL void Conn_SyncServerStruct PARAMS(( void ));
@@ -122,6 +130,7 @@ GLOBAL void Conn_SyncServerStruct PARAMS(( void ));
 GLOBAL CONN_ID Conn_GetFromProc PARAMS((int fd));
 GLOBAL CLIENT* Conn_GetClient PARAMS((CONN_ID i));
 GLOBAL PROC_STAT* Conn_GetProcStat PARAMS((CONN_ID i));
+
 #ifdef SSL_SUPPORT
 GLOBAL bool Conn_GetCipherInfo PARAMS((CONN_ID Idx, char *buf, size_t len));
 GLOBAL bool Conn_UsesSSL PARAMS((CONN_ID Idx));
diff --git a/src/ngircd/defines.h b/src/ngircd/defines.h
index d0dc9ce1..ba7adf17 100644
--- a/src/ngircd/defines.h
+++ b/src/ngircd/defines.h
@@ -161,10 +161,10 @@
 #endif
 
 /** Supported user modes. */
-#define USERMODES "acCiorRswx"
+#define USERMODES "aBcCiorRswx"
 
 /** Supported channel modes. */
-#define CHANMODES "abehiIklmnoOPqrRstvz"
+#define CHANMODES "abehiIklmMnoOPqrRstvz"
 
 /** Away message for users connected to linked servers. */
 #define DEFAULT_AWAY_MSG "Away"
diff --git a/src/ngircd/io.c b/src/ngircd/io.c
index 9ffdfd6b..cce6ef53 100644
--- a/src/ngircd/io.c
+++ b/src/ngircd/io.c
@@ -86,6 +86,20 @@ static int io_masterfd;
 
 static int io_dispatch_kqueue(struct timeval *tv);
 static bool io_event_change_kqueue(int, short, const int action);
+
+#ifndef EV_SET
+/* Taken from /usr/include/sys/event.h of FreeBSD 8.1 and required by all
+ * platforms that have kqueue but lack EV_SET() -- for example FreeBSD 4. */
+#define EV_SET(kevp, a, b, c, d, e, f) do {	\
+	struct kevent *__kevp__ = (kevp);	\
+	__kevp__->ident = (a);			\
+	__kevp__->filter = (b);			\
+	__kevp__->flags = (c);			\
+	__kevp__->fflags = (d);			\
+	__kevp__->data = (e);			\
+	__kevp__->udata = (f);			\
+} while(0)
+#endif
 #endif
 
 #ifdef IO_USE_POLL
diff --git a/src/ngircd/irc-cap.c b/src/ngircd/irc-cap.c
index 2ea4c9af..af34c38c 100644
--- a/src/ngircd/irc-cap.c
+++ b/src/ngircd/irc-cap.c
@@ -275,8 +275,8 @@ Parse_CAP(int Capabilities, char *Args)
  * @param Capabilities Capability flags (bitmask).
  * @return Pointer to textual representation.
  */
-char
-*Get_CAP_String(int Capabilities)
+char *
+Get_CAP_String(int Capabilities)
 {
 	static char txt[COMMAND_LEN];
 
diff --git a/src/ngircd/irc-info.c b/src/ngircd/irc-info.c
index 879da3da..7a122ef7 100644
--- a/src/ngircd/irc-info.c
+++ b/src/ngircd/irc-info.c
@@ -864,6 +864,8 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
 	assert( Client != NULL );
 	assert( Chan != NULL );
 
+	IRC_SetPenalty(Client, 1);
+
 	is_member = Channel_IsMemberOf(Chan, Client);
 
 	/* Secret channel? */
@@ -882,9 +884,6 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
 
 		is_visible = strchr(client_modes, 'i') == NULL;
 		if (is_member || is_visible) {
-			if (IRC_CheckListTooBig(Client, count, MAX_RPL_WHO, "WHO"))
-				break;
-
 			strcpy(flags, who_flags_status(client_modes));
 			if (is_ircop)
 				strlcat(flags, "*", sizeof(flags));
@@ -898,6 +897,11 @@ IRC_WHO_Channel(CLIENT *Client, CHANNEL *Chan, bool OnlyOps)
 			count++;
 		}
 	}
+
+	/* If there are a lot of clients, augment penalty a bit */
+	if (count > MAX_RPL_WHO)
+		IRC_SetPenalty(Client, 1);
+
 	return IRC_WriteStrClient(Client, RPL_ENDOFWHO_MSG, Client_ID(Client),
 				  Channel_Name(Chan));
 }
@@ -926,6 +930,7 @@ IRC_WHO_Mask(CLIENT *Client, char *Mask, bool OnlyOps)
 	if (Mask)
 		ngt_LowerStr(Mask);
 
+	IRC_SetPenalty(Client, 3);
 	for (c = Client_First(); c != NULL; c = Client_Next(c)) {
 		if (Client_Type(c) != CLIENT_USER)
 			continue;
@@ -1029,13 +1034,11 @@ IRC_WHO(CLIENT *Client, REQUEST *Req)
 		chan = Channel_Search(Req->argv[0]);
 		if (chan) {
 			/* Members of a channel have been requested */
-			IRC_SetPenalty(Client, 1);
 			return IRC_WHO_Channel(Client, chan, only_ops);
 		}
 		if (strcmp(Req->argv[0], "0") != 0) {
 			/* A mask has been given. But please note this RFC
 			 * stupidity: "0" is same as no arguments ... */
-			IRC_SetPenalty(Client, 3);
 			return IRC_WHO_Mask(Client, Req->argv[0], only_ops);
 		}
 	}
@@ -1125,6 +1128,12 @@ IRC_WHOIS_SendReply(CLIENT *Client, CLIENT *from, CLIENT *c)
 				Client_ID(from), Client_ID(c)))
 		return DISCONNECTED;
 
+	/* IRC-Bot? */
+	if (Client_HasMode(c, 'B') &&
+	    !IRC_WriteStrClient(from, RPL_WHOISBOT_MSG,
+				Client_ID(from), Client_ID(c)))
+		return DISCONNECTED;
+
 	/* Connected using SSL? */
 	if (Conn_UsesSSL(Client_Conn(c)) &&
 	    !IRC_WriteStrClient(from, RPL_WHOISSSL_MSG, Client_ID(from),
@@ -1491,7 +1500,15 @@ Show_MOTD_Sendline(CLIENT *Client, const char *msg)
 static bool
 Show_MOTD_End(CLIENT *Client)
 {
-	return IRC_WriteStrClient( Client, RPL_ENDOFMOTD_MSG, Client_ID( Client ));
+	if (!IRC_WriteStrClient(Client, RPL_ENDOFMOTD_MSG, Client_ID(Client)))
+		return DISCONNECTED;
+
+	if (*Conf_CloakHost)
+		return IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG,
+					  Client_ID(Client),
+					  Client_Hostname(Client));
+
+	return CONNECTED;
 }
 
 #ifdef SSL_SUPPORT
diff --git a/src/ngircd/irc-login.c b/src/ngircd/irc-login.c
index 3fb1b902..9e1abdd5 100644
--- a/src/ngircd/irc-login.c
+++ b/src/ngircd/irc-login.c
@@ -87,7 +87,7 @@ IRC_PASS( CLIENT *Client, REQUEST *Req )
 					  Client_ID(Client));
 	}
 
-	Client_SetPassword(Client, Req->argv[0]);
+	Conn_SetPassword(Client_Conn(Client), Req->argv[0]);
 
 	/* Protocol version */
 	if (Req->argc >= 2 && strlen(Req->argv[1]) >= 4) {
diff --git a/src/ngircd/irc-mode.c b/src/ngircd/irc-mode.c
index 3679531d..f3946343 100644
--- a/src/ngircd/irc-mode.c
+++ b/src/ngircd/irc-mode.c
@@ -138,6 +138,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
 {
 	char the_modes[COMMAND_LEN], x[2], *mode_ptr;
 	bool ok, set;
+	bool send_RPL_HOSTHIDDEN_MSG = false;
 	int mode_arg;
 	size_t len;
 
@@ -229,6 +230,14 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
 							ERR_NOPRIVILEGES_MSG,
 							Client_ID(Origin));
 			break;
+		case 'B': /* Bot */
+			if (Client_HasMode(Client, 'r'))
+				ok = IRC_WriteStrClient(Origin,
+							ERR_RESTRICTED_MSG,
+							Client_ID(Origin));
+			else
+				x[0] = 'B';
+			break;
 		case 'c': /* Receive connect notices
 			   * (only settable by IRC operators!) */
 			if (!set || Client_Type(Client) == CLIENT_SERVER
@@ -256,6 +265,14 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
 							ERR_RESTRICTED_MSG,
 							Client_ID(Origin));
 			break;
+		case 'R': /* Registered (not [un]settable by clients) */
+			if (Client_Type(Client) == CLIENT_SERVER)
+				x[0] = 'R';
+			else
+				ok = IRC_WriteStrClient(Origin,
+							ERR_NICKREGISTER_MSG,
+							Client_ID(Origin));
+			break;
 		case 'x': /* Cloak hostname */
 			if (Client_HasMode(Client, 'r'))
 				ok = IRC_WriteStrClient(Origin,
@@ -263,6 +280,7 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
 							Client_ID(Origin));
 			else
 				x[0] = 'x';
+				send_RPL_HOSTHIDDEN_MSG = true;
 			break;
 		default:
 			if (Client_Type(Client) != CLIENT_SERVER) {
@@ -332,6 +350,10 @@ Client_Mode( CLIENT *Client, REQUEST *Req, CLIENT *Origin, CLIENT *Target )
 						  "MODE %s :%s",
 						  Client_ID(Target),
 						  the_modes);
+			if (send_RPL_HOSTHIDDEN_MSG)
+				IRC_WriteStrClient(Client, RPL_HOSTHIDDEN_MSG,
+						   Client_ID(Client),
+						   Client_HostnameCloaked(Client));
 		}
 		LogDebug("%s \"%s\": Mode change, now \"%s\".",
 			 Client_TypeText(Target), Client_Mask(Target),
@@ -538,6 +560,7 @@ Channel_Mode(CLIENT *Client, REQUEST *Req, CLIENT *Origin, CHANNEL *Channel)
 				goto chan_exit;
 			}
 		case 'i': /* Invite only */
+		case 'M': /* Only identified nicks can write */
 		case 'm': /* Moderated */
 		case 'n': /* Only members can write */
 		case 't': /* Topic locked */
diff --git a/src/ngircd/irc-server.c b/src/ngircd/irc-server.c
index 2ce4fadd..f9182d98 100644
--- a/src/ngircd/irc-server.c
+++ b/src/ngircd/irc-server.c
@@ -80,7 +80,8 @@ IRC_SERVER( CLIENT *Client, REQUEST *Req )
 			Conn_Close( Client_Conn( Client ), NULL, "Server not configured here", true);
 			return DISCONNECTED;
 		}
-		if( strcmp( Client_Password( Client ), Conf_Server[i].pwd_in ) != 0 )
+		if( strcmp( Conn_Password( Client_Conn( Client ) ),
+			    Conf_Server[i].pwd_in ) != 0 )
 		{
 			/* wrong password */
 			Log( LOG_ERR, "Connection %d: Got bad password from server \"%s\"!", Client_Conn( Client ), Req->argv[0] );
diff --git a/src/ngircd/irc.c b/src/ngircd/irc.c
index 9508ecc4..efc34d4b 100644
--- a/src/ngircd/irc.c
+++ b/src/ngircd/irc.c
@@ -327,12 +327,18 @@ IRC_HELP( CLIENT *Client, REQUEST *Req )
 
 
 static char *
-Option_String( CONN_ID Idx )
+#ifdef ZLIB
+Option_String(CONN_ID Idx)
+#else
+Option_String(UNUSED CONN_ID Idx)
+#endif
 {
 	static char option_txt[8];
+#ifdef ZLIB
 	UINT16 options;
 
 	options = Conn_Options(Idx);
+#endif
 
 	strcpy(option_txt, "F");	/* No idea what this means, but the
 					 * original ircd sends it ... */
diff --git a/src/ngircd/login.c b/src/ngircd/login.c
index 7f0299cb..460fcd1e 100644
--- a/src/ngircd/login.c
+++ b/src/ngircd/login.c
@@ -93,13 +93,14 @@ Login_User(CLIENT * Client)
 		 * the beahiour of the daemon compiled without PAM support:
 		 * because there can't be any "server password", all
 		 * passwords supplied are classified as "wrong". */
-		if(Client_Password(Client)[0] == '\0')
+		if(Conn_Password(conn)[0] == '\0')
 			return Login_User_PostAuth(Client);
 		Client_Reject(Client, "Non-empty password", false);
 		return DISCONNECTED;
 	}
 
-	if (Conf_PAMIsOptional && strcmp(Client_Password(Client), "") == 0) {
+	if (Conf_PAMIsOptional &&
+	    strcmp(Conn_Password(conn), "") == 0) {
 		/* Clients are not required to send a password and to be PAM-
 		 * authenticated at all. If not, they won't become "identified"
 		 * and keep the "~" in their supplied user name.
@@ -129,7 +130,7 @@ Login_User(CLIENT * Client)
 	}
 #else
 	/* Check global server password ... */
-	if (strcmp(Client_Password(Client), Conf_ServerPwd) != 0) {
+	if (strcmp(Conn_Password(conn), Conf_ServerPwd) != 0) {
 		/* Bad password! */
 		Client_Reject(Client, "Bad server password", false);
 		return DISCONNECTED;
diff --git a/src/ngircd/match.c b/src/ngircd/match.c
index 79699ea0..75bf4358 100644
--- a/src/ngircd/match.c
+++ b/src/ngircd/match.c
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
  *
  * 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
@@ -48,9 +48,9 @@ static int Matche_After_Star PARAMS(( const char *p, const char *t ));
 /**
  * Match string with pattern.
  *
- * @param Pattern	Pattern to match with
- * @param String	Input string
- * @return		true if pattern matches
+ * @param Pattern Pattern to match with
+ * @param String Input string
+ * @return true if pattern matches
  */
 GLOBAL bool
 Match( const char *Pattern, const char *String )
@@ -64,17 +64,46 @@ Match( const char *Pattern, const char *String )
 /**
  * Match string with pattern case-insensitive.
  *
- * @param pattern	Pattern to match with
- * @param searchme	Input string, at most COMMAND_LEN-1 characters long
- * @return		true if pattern matches
+ * @param Pattern Pattern to match with
+ * @param String Input string, at most COMMAND_LEN-1 characters long
+ * @return true if pattern matches
  */
 GLOBAL bool
-MatchCaseInsensitive(const char *pattern, const char *searchme)
+MatchCaseInsensitive(const char *Pattern, const char *String)
 {
 	char haystack[COMMAND_LEN];
 
-	strlcpy(haystack, searchme, sizeof(haystack));
-	return Match(pattern, ngt_LowerStr(haystack));
+	strlcpy(haystack, String, sizeof(haystack));
+	return Match(Pattern, ngt_LowerStr(haystack));
+} /* MatchCaseInsensitive */
+
+
+/**
+ * Match string with pattern case-insensitive.
+ *
+ * @param pattern Pattern to match with
+ * @param String Input string, at most COMMAND_LEN-1 characters long
+ * @param Separator Character separating the individual patterns in the list
+ * @return true if pattern matches
+ */
+GLOBAL bool
+MatchCaseInsensitiveList(const char *Pattern, const char *String,
+		     const char *Separator)
+{
+	char tmp_pattern[COMMAND_LEN], haystack[COMMAND_LEN], *ptr;
+
+	strlcpy(tmp_pattern, Pattern, sizeof(tmp_pattern));
+	strlcpy(haystack, String, sizeof(haystack));
+	ngt_LowerStr(haystack);
+
+	ptr = strtok(tmp_pattern, Separator);
+	while (ptr) {
+		ngt_TrimStr(ptr);
+		if (Match(ptr, haystack))
+			return true;
+		ptr = strtok(NULL, Separator);
+	}
+	return false;
 } /* MatchCaseInsensitive */
 
 
diff --git a/src/ngircd/match.h b/src/ngircd/match.h
index 2efe3f5b..d4107fb6 100644
--- a/src/ngircd/match.h
+++ b/src/ngircd/match.h
@@ -1,6 +1,6 @@
 /*
  * ngIRCd -- The Next Generation IRC Daemon
- * Copyright (c)2001,2002 by Alexander Barton (alex@barton.de)
+ * Copyright (c)2001-2012 Alexander Barton (alex@barton.de) and Contributors.
  *
  * 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
@@ -17,8 +17,14 @@
  * Wildcard pattern matching (header)
  */
 
-GLOBAL bool Match PARAMS(( const char *Pattern, const char *String ));
-GLOBAL bool MatchCaseInsensitive PARAMS(( const char *Pattern, const char *searchme ));
+GLOBAL bool Match PARAMS((const char *Pattern, const char *String));
+
+GLOBAL bool MatchCaseInsensitive PARAMS((const char *Pattern,
+					 const char *String));
+
+GLOBAL bool MatchCaseInsensitiveList PARAMS((const char *Pattern,
+					     const char *String,
+					     const char *Separator));
 
 #endif
 
diff --git a/src/ngircd/messages.h b/src/ngircd/messages.h
index d8041bfd..d99930fa 100644
--- a/src/ngircd/messages.h
+++ b/src/ngircd/messages.h
@@ -21,7 +21,7 @@
 #define RPL_YOURHOST_MSG		"002 %s :Your host is %s, running version ngircd-%s (%s/%s/%s)"
 #define RPL_CREATED_MSG			"003 %s :This server has been started %s"
 #define RPL_MYINFO_MSG			"004 %s %s ngircd-%s %s %s"
-#define RPL_ISUPPORT1_MSG		"005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(qaohv)~&@%%+ CHANTYPES=#&+ CHANMODES=beI,k,l,imnOPRstz CHANLIMIT=#&+:%d :are supported on this server"
+#define RPL_ISUPPORT1_MSG		"005 %s RFC2812 IRCD=ngIRCd CASEMAPPING=ascii PREFIX=(qaohv)~&@%%+ CHANTYPES=#&+ CHANMODES=beI,k,l,imMnOPRstz CHANLIMIT=#&+:%d :are supported on this server"
 #define RPL_ISUPPORT2_MSG		"005 %s CHANNELLEN=%d NICKLEN=%d TOPICLEN=%d AWAYLEN=%d KICKLEN=%d MODES=%d MAXLIST=beI:%d EXCEPTS=e INVEX=I PENALTY :are supported on this server"
 
 #define RPL_TRACELINK_MSG		"200 %s Link %s-%s %s %s V%s %ld %d %d"
@@ -72,6 +72,7 @@
 #define RPL_NOTOPIC_MSG			"331 %s %s :No topic is set"
 #define RPL_TOPIC_MSG			"332 %s %s :%s"
 #define RPL_TOPICSETBY_MSG		"333 %s %s %s %u"
+#define RPL_WHOISBOT_MSG		"335 %s %s :is a IRC Bot"
 #define RPL_INVITING_MSG		"341 %s %s %s%s"
 #define RPL_INVITELIST_MSG		"346 %s %s %s"
 #define RPL_ENDOFINVITELIST_MSG		"347 %s %s :End of channel invite list"
@@ -95,11 +96,12 @@
 #define RPL_YOUREOPER_MSG		"381 %s :You are now an IRC Operator"
 #define RPL_YOURESERVICE_MSG		"383 %s :You are service %s"
 #define RPL_TIME_MSG			"391 %s %s :%s"
+#define RPL_HOSTHIDDEN_MSG		"396 %s %s :is your displayed hostname now"
 
 #define ERR_NOSUCHNICK_MSG		"401 %s %s :No such nick or channel name"
 #define ERR_NOSUCHSERVER_MSG		"402 %s %s :No such server"
 #define ERR_NOSUCHCHANNEL_MSG		"403 %s %s :No such channel"
-#define ERR_CANNOTSENDTOCHAN_MSG	"404 %s %s :Cannot send to channel"
+#define ERR_CANNOTSENDTOCHAN_MSG	"404 %s %s :Cannot send to channel (+m) -- Moderated"
 #define ERR_TOOMANYCHANNELS_MSG		"405 %s %s :You have joined too many channels"
 #define ERR_WASNOSUCHNICK_MSG		"406 %s %s :There was no such nickname"
 #define ERR_NOORIGIN_MSG		"409 %s :No origin specified"
@@ -112,6 +114,7 @@
 #define ERR_NONICKNAMEGIVEN_MSG		"431 %s :No nickname given"
 #define ERR_ERRONEUSNICKNAME_MSG	"432 %s %s :Erroneous nickname"
 #define ERR_NICKNAMETOOLONG_MSG		"432 %s %s :Nickname too long, max. %u characters"
+#define ERR_FORBIDDENNICKNAME_MSG	"432 %s %s :Nickname is forbidden/blocked"
 #define ERR_NICKNAMEINUSE_MSG		"433 %s %s :Nickname already in use"
 #define ERR_USERNOTINCHANNEL_MSG	"441 %s %s %s :They aren't on that channel"
 #define ERR_NOTONCHANNEL_MSG		"442 %s %s :You are not on that channel"
@@ -123,14 +126,14 @@
 #define ERR_NEEDMOREPARAMS_MSG		"461 %s %s :Syntax error"
 #define ERR_ALREADYREGISTRED_MSG	"462 %s :Connection already registered"
 #define ERR_PASSWDMISMATCH_MSG		"464 %s :Invalid password"
-#define ERR_CHANNELISFULL_MSG		"471 %s %s :Cannot join channel (+l)"
-#define ERR_SECURECHANNEL_MSG		"471 %s %s :Cannot join channel (+z)"
-#define ERR_OPONLYCHANNEL_MSG		"471 %s %s :Cannot join channel (+O)"
-#define ERR_REGONLYCHANNEL_MSG		"471 %s %s :Cannot join channel (+R)"
+#define ERR_CHANNELISFULL_MSG		"471 %s %s :Cannot join channel (+l) -- Channel is too full, try later"
+#define ERR_SECURECHANNEL_MSG		"471 %s %s :Cannot join channel (+z) -- SSL connections only"
+#define ERR_OPONLYCHANNEL_MSG		"471 %s %s :Cannot join channel (+O) -- IRC opers only"
+#define ERR_REGONLYCHANNEL_MSG		"471 %s %s :Cannot join channel (+R) -- Registered users only"
 #define ERR_UNKNOWNMODE_MSG		"472 %s %c :is unknown mode char for %s"
-#define ERR_INVITEONLYCHAN_MSG		"473 %s %s :Cannot join channel (+i)"
-#define ERR_BANNEDFROMCHAN_MSG		"474 %s %s :Cannot join channel (+b)"
-#define ERR_BADCHANNELKEY_MSG		"475 %s %s :Cannot join channel (+k)"
+#define ERR_INVITEONLYCHAN_MSG		"473 %s %s :Cannot join channel (+i) -- Invited users only"
+#define ERR_BANNEDFROMCHAN_MSG		"474 %s %s :Cannot join channel (+b) -- You are banned"
+#define ERR_BADCHANNELKEY_MSG		"475 %s %s :Cannot join channel (+k) -- Wrong channel key"
 #define ERR_NOCHANMODES_MSG		"477 %s %s :Channel doesn't support modes"
 #define ERR_LISTFULL_MSG		"478 %s %s %s: Channel list is full (%d)"
 #define ERR_NOPRIVILEGES_MSG		"481 %s :Permission denied"
@@ -138,6 +141,7 @@
 #define ERR_CHANOPPRIVTOLOW_MSG		"482 %s %s :Your privileges are to low"
 #define ERR_CANTKILLSERVER_MSG		"483 %s :You can't kill a server!"
 #define ERR_RESTRICTED_MSG		"484 %s :Your connection is restricted"
+#define ERR_NICKREGISTER_MSG		"484 %s :Cannot modify user mode (+R) -- Use IRC services"
 #define ERR_NOOPERHOST_MSG		"491 %s :Not configured for your host"
 #define ERR_NOTONSAMECHANNEL_MSG	"493 %s :You must share a common channel with %s"
 
diff --git a/src/ngircd/pam.c b/src/ngircd/pam.c
index 6382c594..88872c47 100644
--- a/src/ngircd/pam.c
+++ b/src/ngircd/pam.c
@@ -102,8 +102,8 @@ PAM_Authenticate(CLIENT *Client) {
 	/* Set supplied client password */
 	if (password)
 		free(password);
-	password = strdup(Client_Password(Client));
-	conv.appdata_ptr = Client_Password(Client);
+	password = strdup(Conn_Password(Client_Conn(Client)));
+	conv.appdata_ptr = Conn_Password(Client_Conn(Client));
 
 	/* Initialize PAM */
 	retval = pam_start("ngircd", Client_OrigUser(Client), &conv, &pam);
diff --git a/src/tool/tool.c b/src/tool/tool.c
index 31c6fb41..eb6c131e 100644
--- a/src/tool/tool.c
+++ b/src/tool/tool.c
@@ -135,24 +135,20 @@ ngt_TrimLastChr( char *String, const char Chr)
  * Fill a String with random chars
  */
 GLOBAL char *
-ngt_RandomStr( char *String, const size_t len)
+ngt_RandomStr(char *String, const size_t len)
 {
-	assert(String != NULL);
+	static const char chars[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!\"#$&'()*+,-./:;<=>?@[\\]^_`";
+	struct timeval t;
+	size_t i;
 
-	static const char chars[] = 
-		"0123456789ABCDEFGHIJKLMNO"
-		"PQRSTUVWXYZabcdefghijklmn"
-		"opqrstuvwxyz!\"#$&'()*+,-"
-		"./:;<=>?@[\\]^_`";
+	assert(String != NULL);
 
-	struct timeval t;
 	gettimeofday(&t, NULL);
-	srand(t.tv_usec * t.tv_sec);
+	srand((unsigned)(t.tv_usec * t.tv_sec));
 
-	for (size_t i = 0; i < len; ++i) {
+	for (i = 0; i < len; ++i) {
 		String[i] = chars[rand() % (sizeof(chars) - 1)];
 	}
-
 	String[len] = '\0';
 
 	return String;