diff --git a/src/sbbs3/answer.cpp b/src/sbbs3/answer.cpp
index 4da4569825d40da29ad74b791ed0b05fc69e7b9b..9049256e1e546bdb623bb0459d54e67297ffd2d4 100644
--- a/src/sbbs3/answer.cpp
+++ b/src/sbbs3/answer.cpp
@@ -25,6 +25,20 @@
 
 extern "C" void client_on(SOCKET sock, client_t* client, BOOL update);
 
+bool
+sbbs_t::set_authresponse(bool activate_ssh)
+{
+	int status;
+
+	lprintf(LOG_DEBUG, "%04d SSH Setting attribute: SESSINFO_AUTHRESPONSE", client_socket);
+	status = cryptSetAttribute(ssh_session, CRYPT_SESSINFO_AUTHRESPONSE, activate_ssh);
+	if(cryptStatusError(status)) {
+		log_crypt_error_status_sock(status, "setting auth response");
+		return false;
+	}
+	return true;
+}
+
 bool sbbs_t::answer()
 {
 	char	str[MAX_PATH+1],str2[MAX_PATH+1],c;
@@ -177,29 +191,47 @@ bool sbbs_t::answer()
 	}
 #ifdef USE_CRYPTLIB
 	if(sys_status&SS_SSH) {
+		int  ssh_failed=0;
+		bool activate_ssh = false;
+
 		tmp[0]=0;
 		pthread_mutex_lock(&ssh_mutex);
-		ctmp = get_crypt_attribute(ssh_session, CRYPT_SESSINFO_USERNAME);
-		if (ctmp) {
-			SAFECOPY(rlogin_name, parse_login(ctmp));
-			free_crypt_attrstr(ctmp);
-			ctmp = get_crypt_attribute(ssh_session, CRYPT_SESSINFO_PASSWORD);
+		for(ssh_failed=0; ssh_failed < 3; ssh_failed++) {
+			lprintf(LOG_DEBUG, "%04d SSH Setting attribute: SESSINFO_ACTIVE", client_socket);
+			if(cryptStatusError(i=cryptSetAttribute(ssh_session, CRYPT_SESSINFO_ACTIVE, 1))) {
+				log_crypt_error_status_sock(i, "setting session active");
+				activate_ssh = false;
+				// TODO: Add private key here...
+				if(i != CRYPT_ENVELOPE_RESOURCE) {
+					break;
+				}
+			}
+			else {
+				break;
+			}
+			ctmp = get_crypt_attribute(ssh_session, CRYPT_SESSINFO_USERNAME);
 			if (ctmp) {
-				SAFECOPY(tmp, ctmp);
+				SAFECOPY(rlogin_name, parse_login(ctmp));
 				free_crypt_attrstr(ctmp);
+				ctmp = get_crypt_attribute(ssh_session, CRYPT_SESSINFO_PASSWORD);
+				if (ctmp) {
+					SAFECOPY(tmp, ctmp);
+					free_crypt_attrstr(ctmp);
+				}
+				lprintf(LOG_DEBUG,"SSH login: '%s'", rlogin_name);
 			}
-			pthread_mutex_unlock(&ssh_mutex);
-			lprintf(LOG_DEBUG,"SSH login: '%s'", rlogin_name);
-		}
-		else {
-			rlogin_name[0] = 0;
-			pthread_mutex_unlock(&ssh_mutex);
-		}
-		useron.number = find_login_id(&cfg, rlogin_name);
-		if(useron.number) {
-			getuserdat(&cfg,&useron);
-			for(i=0;i<3 && online;i++) {
-				if(stricmp(tmp,useron.pass)) {
+			else {
+				rlogin_name[0] = 0;
+				continue;
+			}
+			useron.number = find_login_id(&cfg, rlogin_name);
+			if(useron.number) {
+				getuserdat(&cfg,&useron);
+				if (stricmp(tmp, useron.pass) == 0) {
+					SAFECOPY(rlogin_pass, tmp);
+					activate_ssh = set_authresponse(true);
+				}
+				else if(ssh_failed) {
 					if(cfg.sys_misc&SM_ECHO_PW)
 						safe_snprintf(str,sizeof(str),"(%04u)  %-25s  FAILED Password attempt: '%s'"
 							,useron.number,useron.alias,tmp);
@@ -208,53 +240,68 @@ bool sbbs_t::answer()
 							,useron.number,useron.alias);
 					logline(LOG_NOTICE,"+!",str);
 					badlogin(useron.alias, tmp);
-					rioctl(IOFI);       /* flush input buffer */
-					bputs(text[InvalidLogon]);
-					bputs(text[PasswordPrompt]);
-					console|=CON_R_ECHOX;
-					getstr(tmp,LEN_PASS*2,K_UPPER|K_LOWPRIO|K_TAB);
-					console&=~(CON_R_ECHOX|CON_L_ECHOX);
-				}
-				else {
-					SAFECOPY(rlogin_pass, tmp);
-					if(REALSYSOP && (cfg.sys_misc&SM_SYSPASSLOGIN) && (cfg.sys_misc&SM_R_SYSOP)) {
-						rioctl(IOFI);       /* flush input buffer */
-						if(!chksyspass())
-							bputs(text[InvalidLogon]);
-						else {
-							i=0;
-							break;
-						}
-					}
-					else {
-						i = 0;
-						break;
-					}
+					useron.number=0;
 				}
 			}
-			if(i) {
-				if(stricmp(tmp,useron.pass)) {
-					if(cfg.sys_misc&SM_ECHO_PW)
-						safe_snprintf(str,sizeof(str),"(%04u)  %-25s  FAILED Password attempt: '%s'"
-							,useron.number,useron.alias,tmp);
+			else {
+				if(cfg.sys_misc&SM_ECHO_PW)
+					lprintf(LOG_NOTICE, "SSH !UNKNOWN USER: '%s' (password: %s)", rlogin_name, truncsp(tmp));
+				else
+					lprintf(LOG_NOTICE, "SSH !UNKNOWN USER: '%s'", rlogin_name);
+				badlogin(rlogin_name, tmp);
+				// Enable SSH so we can create a new user...
+				activate_ssh = set_authresponse(true);
+			}
+		}
+		if (activate_ssh) {
+			int cid;
+			char tname[1024];
+			int tnamelen;
+
+			ssh_failed=0;
+			// Check the channel ID and name...
+			if (cryptStatusOK(i=cryptGetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, &cid))) {
+				if (i == CRYPT_OK) {
+					tnamelen = 0;
+					i=cryptGetAttributeString(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_TYPE, tname, &tnamelen);
+					log_crypt_error_status_sock(i, "getting channel type");
+					if (tnamelen != 7 || strnicmp(tname, "session", 7)) {
+						lprintf(LOG_NOTICE, "%04d SSH [%s] active channel '%.*s' is not 'session', disconnecting.", client_socket, client_ipaddr, tnamelen, tname);
+						badlogin(/* user: */NULL, /* passwd: */NULL, "SSH", &client_addr, /* delay: */false);
+						// Fail because there's no session.
+						activate_ssh = false;
+					}
 					else
-						safe_snprintf(str,sizeof(str),"(%04u)  %-25s  FAILED Password attempt"
-							,useron.number,useron.alias);
-					logline(LOG_NOTICE,"+!",str);
-					badlogin(useron.alias, tmp);
-					bputs(text[InvalidLogon]);
+						session_channel = cid;
 				}
-				useron.number=0;
-				hangup();
+			}
+			else {
+				log_crypt_error_status_sock(i, "getting channel id");
+				if (i == CRYPT_ERROR_PERMISSION)
+					lprintf(LOG_CRIT, "!Your cryptlib build is obsolete, please update");
 			}
 		}
-		else {
-			if(cfg.sys_misc&SM_ECHO_PW)
-				lprintf(LOG_NOTICE, "SSH !UNKNOWN USER: '%s' (password: %s)", rlogin_name, truncsp(tmp));
-			else
-				lprintf(LOG_NOTICE, "SSH !UNKNOWN USER: '%s'", rlogin_name);
-			badlogin(rlogin_name, tmp);
+		if (activate_ssh) {
+			if(cryptStatusError(i=cryptSetAttribute(ssh_session, CRYPT_PROPERTY_OWNER, CRYPT_UNUSED))) {
+				log_crypt_error_status_sock(i, "clearing owner");
+				activate_ssh = false;
+			}
+		}
+		if(!activate_ssh) {
+			int status;
+			lprintf(LOG_NOTICE, "%04d SSH [%s] session establishment failed", client_socket, client_ipaddr);
+			if (cryptStatusError(status = cryptDestroySession(ssh_session))) {
+				lprintf(LOG_ERR, "%04d SSH ERROR %d destroying Cryptlib Session %d from %s line %d"
+					, client_socket, status, ssh_session, __FILE__, __LINE__);
+			}
+			ssh_mode = false;
+			pthread_mutex_unlock(&ssh_mutex);
+			close_socket(client_socket);
+			useron.number = 0;
+			return false;
 		}
+		SetEvent(ssh_active);
+
 		if (cryptStatusOK(cryptGetAttribute(ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_WIDTH, &l)) && l > 0) {
 			cols = l;
 			lprintf(LOG_DEBUG, "%04d SSH [%s] height %d", client_socket, client.addr, cols);
@@ -271,6 +318,7 @@ bool sbbs_t::answer()
 				terminal[sizeof(terminal)-1] = 0;
 			lprintf(LOG_DEBUG, "%04d SSH [%s] term: %s", client_socket, client.addr, terminal);
 		}
+		pthread_mutex_unlock(&ssh_mutex);
 	}
 #endif
 
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index c6302f9c1a7bd36e6640573753f6a96f8a356435..d4b698ecd85788798a60243f6e210b9ac501616d 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -274,6 +274,20 @@ int lprintf(int level, const char *fmt, ...)
 	return(lputs(level,sbuf));
 }
 
+void
+sbbs_t::log_crypt_error_status_sock(int status, const char *action)
+{
+	char *estr;
+	int level;
+	get_crypt_error_string(status, ssh_session, &estr, action, &level);
+	if (estr) {
+		if (level < startup->ssh_error_level)
+			level = startup->ssh_error_level;
+		lprintf(level, "%04d SSH %s", client_socket, estr);
+		free_crypt_attrstr(estr);
+	}
+}
+
 /* Picks the right log callback function (event or term) based on the sbbs->cfg.node_num value */
 /* Prepends the current node number and user alias (if applicable) */
 int sbbs_t::lputs(int level, const char* str)
@@ -1929,7 +1943,7 @@ static int crypt_pop_channel_data(sbbs_t *sbbs, char *inbuf, int want, int *got)
 					continue;
 				if (cid != sbbs->session_channel) {
 					if (cryptStatusError(status = cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, cid))) {
-						GCESS(status, sbbs->client_socket, sbbs->ssh_session, "setting channel");
+						sbbs->log_crypt_error_status_sock(status, "setting channel");
 						return status;
 					}
 					cname = get_crypt_attribute(sbbs->ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_TYPE);
@@ -1939,7 +1953,7 @@ static int crypt_pop_channel_data(sbbs_t *sbbs, char *inbuf, int want, int *got)
 						free_crypt_attrstr(cname);
 					closing_channel = cid;
 					if (cryptStatusError(status = cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_ACTIVE, 0))) {
-						GCESS(status, sbbs->client_socket, sbbs->ssh_session, "closing channel");
+						sbbs->log_crypt_error_status_sock(status, "closing channel");
 						return status;
 					}
 					continue;
@@ -1951,7 +1965,7 @@ static int crypt_pop_channel_data(sbbs_t *sbbs, char *inbuf, int want, int *got)
 				 * and it was destroyed, so it's no longer possible to get the channel id.
 				 */
 				if (status != CRYPT_ERROR_NOTFOUND)
-					GCESS(status, sbbs->client_socket, sbbs->ssh_session, "getting channel id");
+					sbbs->log_crypt_error_status_sock(status, "getting channel id");
 				closing_channel = -1;
 			}
 		}
@@ -2090,6 +2104,10 @@ void input_thread(void *arg)
 #ifdef USE_CRYPTLIB
 		if(sbbs->ssh_mode && sock==sbbs->client_socket) {
 			int err;
+			if (WaitForEvent(sbbs->ssh_active, 1000) == WAIT_TIMEOUT) {
+				pthread_mutex_unlock(&sbbs->input_thread_mutex);
+				continue;
+			}
 			pthread_mutex_lock(&sbbs->ssh_mutex);
 			if(cryptStatusError((err=crypt_pop_channel_data(sbbs, (char*)inbuf, rd, &i)))) {
 				pthread_mutex_unlock(&sbbs->ssh_mutex);
@@ -3661,6 +3679,7 @@ bool sbbs_t::init()
 #ifdef USE_CRYPTLIB
 	pthread_mutex_init(&ssh_mutex,NULL);
 	ssh_mutex_created = true;
+	ssh_active = CreateEvent(NULL, TRUE, FALSE, (void *)"ssh_active");
 #endif
 	pthread_mutex_init(&input_thread_mutex,NULL);
 	input_thread_mutex_created = true;
@@ -3779,6 +3798,12 @@ sbbs_t::~sbbs_t()
 #ifdef USE_CRYPTLIB
 	while(ssh_mutex_created && pthread_mutex_destroy(&ssh_mutex)==EBUSY)
 		mswait(1);
+	if (ssh_active) {
+		SetEvent(ssh_active);
+		while ((!CloseEvent(ssh_active)) && errno == EBUSY)
+			mswait(1);
+		ssh_active = nullptr;
+	}
 #endif
 	while(input_thread_mutex_created && pthread_mutex_destroy(&input_thread_mutex)==EBUSY)
 		mswait(1);
@@ -5389,7 +5414,6 @@ NO_SSH:
 		/* Do SSH stuff here */
 #ifdef USE_CRYPTLIB
 		if(ssh) {
-			int	ssh_failed=0;
 			BOOL nodelay = TRUE;
 			ulong nb = 0;
 
@@ -5403,10 +5427,10 @@ NO_SSH:
 			sbbs->ssh_mode = true;
 
 			if(cryptStatusError(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_OPTION_NET_CONNECTTIMEOUT, startup->ssh_connect_timeout)))
-				GCESS(i, client_socket, sbbs->ssh_session, "setting connect timeout");
+				sbbs->log_crypt_error_status_sock(i, "setting connect timeout");
 
 			if(cryptStatusError(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_PRIVATEKEY, ssh_context))) {
-				GCESS(i, client_socket, sbbs->ssh_session, "setting private key");
+				sbbs->log_crypt_error_status_sock(i, "setting private key");
 				SSH_END(client_socket);
 				close_socket(client_socket);
 				continue;
@@ -5414,81 +5438,22 @@ NO_SSH:
 			setsockopt(client_socket,IPPROTO_TCP,TCP_NODELAY,(char*)&nodelay,sizeof(nodelay));
 			ioctlsocket(client_socket,FIONBIO,&nb);
 			if(cryptStatusError(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_NETWORKSOCKET, client_socket))) {
-				GCESS(i, client_socket, sbbs->ssh_session, "setting network socket");
-				SSH_END(client_socket);
-				close_socket(client_socket);
-				continue;
-			}
-			for(ssh_failed=0; ssh_failed < 2; ssh_failed++) {
-				/* Accept any credentials */
-				lprintf(LOG_DEBUG, "%04d SSH Setting attribute: SESSINFO_AUTHRESPONSE", client_socket);
-				if(cryptStatusError(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_AUTHRESPONSE, 1))) {
-					GCESS(i, client_socket, sbbs->ssh_session, "setting auth response");
-					ssh_failed=1;
-					break;
-				}
-				lprintf(LOG_DEBUG, "%04d SSH Setting attribute: SESSINFO_ACTIVE", client_socket);
-				if(cryptStatusError(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_ACTIVE, 1))) {
-					GCESS(i, client_socket, sbbs->ssh_session, "setting session active");
-					if(i != CRYPT_ENVELOPE_RESOURCE) {
-						ssh_failed=2;
-						break;
-					}
-				}
-				else {
-					int cid;
-					char tname[1024];
-					int tnamelen;
-
-					ssh_failed=0;
-					// Check the channel ID and name...
-					if (cryptStatusOK(i=cryptGetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_SSH_CHANNEL, &cid))) {
-						if (i == CRYPT_OK) {
-							tnamelen = 0;
-							i=cryptGetAttributeString(sbbs->ssh_session, CRYPT_SESSINFO_SSH_CHANNEL_TYPE, tname, &tnamelen);
-							GCESS(i, client_socket, sbbs->ssh_session, "getting channel type");
-							if (tnamelen != 7 || strnicmp(tname, "session", 7)) {
-								lprintf(LOG_NOTICE, "%04d SSH [%s] active channel '%.*s' is not 'session', disconnecting.", client_socket, host_ip, tnamelen, tname);
-								sbbs->badlogin(/* user: */NULL, /* passwd: */NULL, "SSH", &client_addr, /* delay: */false);
-								// Fail because there's no session.
-								ssh_failed = 3;
-							}
-							else
-								sbbs->session_channel = cid;
-						}
-					}
-					else {
-						GCESS(i, client_socket, sbbs->ssh_session, "getting channel id");
-						if (i == CRYPT_ERROR_PERMISSION)
-							lprintf(LOG_CRIT, "!Your cryptlib build is obsolete, please update");
-					}
-					break;
-				}
-			}
-			if (!ssh_failed) {
-				if(cryptStatusError(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_PROPERTY_OWNER, CRYPT_UNUSED))) {
-					GCESS(i, client_socket, sbbs->ssh_session, "clearing owner");
-					ssh_failed = 2;
-				}
-			}
-			if(ssh_failed) {
-				lprintf(LOG_NOTICE, "%04d SSH [%s] session establishment failed", client_socket, host_ip);
+				sbbs->log_crypt_error_status_sock(i, "setting network socket");
 				SSH_END(client_socket);
 				close_socket(client_socket);
 				continue;
 			}
 			if(cryptStatusError(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_OPTION_NET_READTIMEOUT, 0)))
-				GCESS(i, sbbs->client_socket, sbbs->ssh_session, "setting read timeout");
+				sbbs->log_crypt_error_status_sock(i, "setting read timeout");
 			// READ = WRITE TIMEOUT HACK... REMOVE WHEN FIXED
 			if(cryptStatusError(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_OPTION_NET_WRITETIMEOUT, 0)))
-				GCESS(i, sbbs->client_socket, sbbs->ssh_session, "setting write timeout");
+				sbbs->log_crypt_error_status_sock(i, "setting write timeout");
 #if 0
 			if(cryptStatusError(err=crypt_pop_channel_data(sbbs, str, sizeof(str), &i))) {
 				GCES(i, sbbs->cfg.node_num, sbbs->ssh_session, "popping data");
 				i=0;
 			}
 #endif
-			sbbs->online=ON_REMOTE;
 		}
 #endif
 
@@ -5780,6 +5745,7 @@ NO_SSH:
 				new_node->sys_status|=SS_SSH;
 				new_node->telnet_mode|=TELNET_MODE_OFF; // SSH does not use Telnet commands
 				new_node->ssh_session=sbbs->ssh_session;
+				new_node->online = ON_REMOTE;
 			}
 			/* Wait for pending data to be sent then turn off ssh_mode for uber-output */
 			while(sbbs->output_thread_running && RingBufFull(&sbbs->outbuf))
@@ -5791,8 +5757,8 @@ NO_SSH:
 		}
 
 	    protected_uint32_adjust(&node_threads_running, 1);
-	    new_node->input_thread_running = true;
-		new_node->input_thread=(HANDLE)_beginthread(input_thread,0, new_node);
+		new_node->input_thread_running = true;
+		new_node->input_thread=(HANDLE)_beginthread(input_thread, 0, new_node);
 	    new_node->output_thread_running = true;
 		new_node->autoterm = sbbs->autoterm;
 		new_node->cols = sbbs->cols;
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index 58462a8f84a12c5450567c27a923a4073b696bcb..7a848b7237053f88f3268ebe55e4afb81f24c7e1 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -451,6 +451,7 @@ public:
 	bool	input_thread_mutex_created = false;
 	pthread_mutex_t	ssh_mutex;
 	bool	ssh_mutex_created = false;
+	xpevent_t ssh_active = nullptr;
 
 	#define OUTCOM_RETRY_DELAY		80		// milliseconds
 	#define OUTCOM_RETRY_ATTEMPTS	1000	// 80 seconds
@@ -1020,6 +1021,7 @@ public:
 	const char*	parse_login(const char*);
 
 	/* answer.cpp */
+	bool    set_authresponse(bool activate_ssh);
 	bool	answer(void);
 
 	/* logon.ccp */
@@ -1066,6 +1068,7 @@ public:
 	int		getnodetopage(int all, int telegram);
 
 	/* main.cpp */
+	void    log_crypt_error_status_sock(int status, const char *action);
 	int		lputs(int level, const char* str);
 	int		lprintf(int level, const char *fmt, ...)
 #if defined(__GNUC__)   // Catch printf-format errors
diff --git a/src/sbbs3/ssl.c b/src/sbbs3/ssl.c
index e6b81825eeee3cb96702ee9d456e0c5beea5c213..2eb68917a0e391fcef0e2c97de38aca33efc3449 100644
--- a/src/sbbs3/ssl.c
+++ b/src/sbbs3/ssl.c
@@ -15,10 +15,12 @@ void free_crypt_attrstr(char *attr)
 
 char* get_crypt_attribute(CRYPT_HANDLE sess, C_IN CRYPT_ATTRIBUTE_TYPE attr)
 {
-	int		len = 0;
-	char	*estr = NULL;
+	int   len = 0;
+	char *estr = NULL;
+	int   status;
 
-	if (cryptStatusOK(cryptGetAttributeString(sess, attr, NULL, &len))) {
+	status = cryptGetAttributeString(sess, attr, NULL, &len);
+	if (cryptStatusOK(status)) {
 		estr = malloc(len + 1);
 		if (estr) {
 			if (cryptStatusError(cryptGetAttributeString(sess, attr, estr, &len))) {