diff --git a/src/sbbs3/GNUmakefile b/src/sbbs3/GNUmakefile
index f97a2a5eeb535a072c34511f4703ffa18fc8b8f9..c1e097f004e4ca08bb3242c2a850053c081ae1df 100644
--- a/src/sbbs3/GNUmakefile
+++ b/src/sbbs3/GNUmakefile
@@ -35,6 +35,11 @@ ifeq ($(os),qnx)
  LDFLAGS += -lsocket
 endif
 
+ifdef USE_CRYPTLIB
+ CFLAGS	+=	-DUSE_CRYPTLIB
+ SBBS_LIBS	+=	-lcl
+endif
+
 ifdef PREFIX
  CFLAGS += -DPREFIX=$(PREFIX)
 endif
@@ -122,12 +127,12 @@ LDFLAGS +=	$(UIFC-MT_LDFLAGS) $(XPDEV-MT_LDFLAGS) $(SMBLIB_LDFLAGS) $(CIOLIB-MT_
 # Monolithic Synchronet executable Build Rule
 $(SBBSMONO): $(MONO_OBJS) $(OBJS)
 	@echo Linking $@
-	$(QUIET)$(CXX) -o $@ $(LDFLAGS) $(MT_LDFLAGS) $(MONO_OBJS) $(OBJS) $(SMBLIB_LIBS) $(XPDEV-MT_LIBS)
+	$(QUIET)$(CXX) -o $@ $(LDFLAGS) $(MT_LDFLAGS) $(MONO_OBJS) $(OBJS) $(SBBS_LIBS) $(SMBLIB_LIBS) $(XPDEV-MT_LIBS)
 
 # Synchronet BBS library Link Rule
 $(SBBS): $(OBJS) $(LIBS)
 	@echo Linking $@
-	$(QUIET)$(MKSHPPLIB) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(SHLIBOPTS)
+	$(QUIET)$(MKSHPPLIB) $(LDFLAGS) -o $@ $(OBJS) $(SBBS_LIBS) $(LIBS) $(SHLIBOPTS)
 
 # FTP Server Link Rule
 $(FTPSRVR): $(MTOBJODIR)/ftpsrvr.o
diff --git a/src/sbbs3/answer.cpp b/src/sbbs3/answer.cpp
index 89b2b0c7c7df44f43617e4b27e8bbb98fed6ec39..1416f9404f6cda8f1c2417a8c08b22952c2a2ae0 100644
--- a/src/sbbs3/answer.cpp
+++ b/src/sbbs3/answer.cpp
@@ -178,6 +178,71 @@ bool sbbs_t::answer()
 		/* Retrieve terminal type from telnet client --RS */
 		request_telnet_opt(TELNET_DO,TELNET_TERM_TYPE);
 	}
+#ifdef USE_CRYPTLIB
+	if(sys_status&SS_SSH) {
+		cryptGetAttributeString(ssh_session, CRYPT_SESSINFO_USERNAME, rlogin_name, &i);
+		rlogin_name[i]=0;
+		cryptGetAttributeString(ssh_session, CRYPT_SESSINFO_PASSWORD, rlogin_pass, &i);
+		rlogin_pass[i]=0;
+		lprintf(LOG_DEBUG,"Node %d SSH: '%.*s' / '%.*s'"
+			,cfg.node_num
+			,LEN_ALIAS*2,rlogin_name
+			,LEN_ALIAS*2,rlogin_pass);
+		useron.number=userdatdupe(0, U_ALIAS, LEN_ALIAS, rlogin_name, 0);
+		if(useron.number) {
+			getuserdat(&cfg,&useron);
+			useron.misc&=~(ANSI|COLOR|RIP|WIP);
+			SAFECOPY(tmp
+				,rlogin_pass);
+			for(i=0;i<3;i++) {
+				if(stricmp(tmp,useron.pass)) {
+					rioctl(IOFI);       /* flush input buffer */
+					bputs(text[InvalidLogon]);
+					if(cfg.sys_misc&SM_ECHO_PW)
+						sprintf(str,"(%04u)  %-25s  FAILED Password attempt: '%s'"
+							,0,useron.alias,tmp);
+					else
+						sprintf(str,"(%04u)  %-25s  FAILED Password attempt"
+							,0,useron.alias);
+						logline("+!",str);
+					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 {
+					if(REALSYSOP) {
+						rioctl(IOFI);       /* flush input buffer */
+						if(!chksyspass())
+							bputs(text[InvalidLogon]);
+						else {
+							i=0;
+							break;
+						}
+					}
+					else
+						break;
+				}
+			}
+			if(i) {
+				if(stricmp(tmp,useron.pass)) {
+					bputs(text[InvalidLogon]);
+					if(cfg.sys_misc&SM_ECHO_PW)
+						sprintf(str,"(%04u)  %-25s  FAILED Password attempt: '%s'"
+							,0,useron.alias,tmp);
+					else
+						sprintf(str,"(%04u)  %-25s  FAILED Password attempt"
+							,0,useron.alias);
+						logline("+!",str);
+				}
+				useron.number=0;
+				hangup();
+			}
+		}
+		else
+			lprintf(LOG_DEBUG,"Node %d RLogin: Unknown user: %s",cfg.node_num,rlogin_name);
+	}
+#endif
 
 	/* Detect terminal type */
     mswait(200);
diff --git a/src/sbbs3/main.cpp b/src/sbbs3/main.cpp
index 4f91223817815cbf83b2210844821e88e7fefff6..a59ddbeaf1324b32a02025646d46581ab9ef63b1 100644
--- a/src/sbbs3/main.cpp
+++ b/src/sbbs3/main.cpp
@@ -82,6 +82,9 @@ SOCKET	uspy_socket[MAX_NODES];	  /* UNIX domain spy sockets */
 SOCKET	node_socket[MAX_NODES];
 static	SOCKET telnet_socket=INVALID_SOCKET;
 static	SOCKET rlogin_socket=INVALID_SOCKET;
+#ifdef USE_CRYPTLIB
+static	SOCKET ssh_socket=INVALID_SOCKET;
+#endif
 static	sbbs_t*	sbbs=NULL;
 static	scfg_t	scfg;
 static	char *	text[TOTAL_TEXT];
@@ -1341,6 +1344,15 @@ void input_thread(void *arg)
 	    if(rd > (int)sizeof(inbuf))
         	rd=sizeof(inbuf);
 
+#ifdef USE_CRYPTLIB
+		if(sbbs->ssh_mode && sock==sbbs->client_socket) {
+			if(!cryptStatusOK(cryptPopData(sbbs->ssh_session, (char*)inbuf, rd, &i)))
+				rd=-1;
+			else
+				rd=i;
+		}
+		else
+#endif
     	rd = recv(sock, (char*)inbuf, rd, 0);
 
 		if(pthread_mutex_unlock(&sbbs->input_thread_mutex)!=0)
@@ -1566,6 +1578,15 @@ void output_thread(void* arg)
 			continue;
 		}
 
+#if USE_CRYPTLIB
+		if(sbbs->ssh_mode) {
+			if(!cryptStatusOK(cryptPushData(sbbs->ssh_session, (char*)buf+bufbot, buftop-bufbot, &i)))
+				i=-1;
+			else
+				cryptFlushData(sbbs->ssh_session);
+		}
+		else
+#endif
 		i=sendsocket(sbbs->client_socket, (char*)buf+bufbot, buftop-bufbot);
 		if(i==SOCKET_ERROR) {
         	if(ERROR_VALUE == ENOTSOCK)
@@ -2340,6 +2361,10 @@ sbbs_t::sbbs_t(ushort node_num, DWORD addr, char* name, SOCKET sd,
 
 	/* Init some important variables */
 
+#ifdef USE_CRYPTLIB
+	ssh_mode=false;
+#endif
+
 	rio_abortable=false;
 
 	console = 0;
@@ -3711,6 +3736,12 @@ static void cleanup(int code)
 		close_socket(rlogin_socket);
 		rlogin_socket=INVALID_SOCKET;
 	}
+#ifdef USE_CRYPTLIB
+	if(ssh_socket!=INVALID_SOCKET) {
+		close_socket(ssh_socket);
+		ssh_socket=INVALID_SOCKET;
+	}
+#endif
 
 
 #ifdef _WINSOCKAPI_
@@ -3783,6 +3814,9 @@ void DLLCALL bbs_thread(void* arg)
 	struct sockaddr_un uspy_addr;
 	socklen_t		uspy_addr_len;
 #endif
+#ifdef USE_CRYPTLIB
+	CRYPT_CONTEXT	ssh_context;
+#endif
 
     if(startup==NULL) {
     	sbbs_beep(100,500);
@@ -3806,6 +3840,9 @@ void DLLCALL bbs_thread(void* arg)
 	/* Setup intelligent defaults */
 	if(startup->telnet_port==0)				startup->telnet_port=IPPORT_TELNET;
 	if(startup->rlogin_port==0)				startup->rlogin_port=513;
+#ifdef USE_CRYPTLIB
+	if(startup->ssh_port==0)				startup->ssh_port=22;
+#endif
 	if(startup->outbuf_drain_timeout==0)	startup->outbuf_drain_timeout=10;
 	if(startup->sem_chk_freq==0)			startup->sem_chk_freq=2;
 	if(startup->temp_dir[0])				backslash(startup->temp_dir);
@@ -4058,6 +4095,93 @@ void DLLCALL bbs_thread(void* arg)
 		lprintf(LOG_INFO,"RLogin server listening on port %d",startup->rlogin_port);
 	}
 
+#ifdef USE_CRYPTLIB
+	if(startup->options&BBS_OPT_ALLOW_SSH) {
+		bool			loaded_key=false;
+
+		CRYPT_KEYSET	ssh_keyset;
+
+		cryptInit();
+		cryptAddRandom(NULL,CRYPT_RANDOM_SLOWPOLL);
+		/* Get the private key... first try loading it from a file... */
+		sprintf(str,"%s%s",scfg.ctrl_dir,"cryptlib.key");
+		if(cryptStatusOK(cryptKeysetOpen(&ssh_keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, str, CRYPT_KEYOPT_NONE))) {
+			if(cryptStatusOK(cryptGetPrivateKey(ssh_keyset, &ssh_context, CRYPT_KEYID_NAME, "ssh_server", scfg.sys_pass)))
+				loaded_key=true;
+			cryptKeysetClose(ssh_keyset);
+			/* Failed to load the key... delete the keyfile and create a new one */
+			if(!loaded_key)
+				remove(str);
+		}
+
+		if(!loaded_key) {
+			/* Couldn't do that... create a new context and use the key from there... */
+
+			if(!cryptStatusOK(i=cryptCreateContext(&ssh_context, CRYPT_UNUSED, CRYPT_ALGO_RSA))) {
+				lprintf(LOG_ERR,"Cryptlib error %d creating context",i);
+				goto NO_SSH;
+			}
+			if(!cryptStatusOK(i=cryptSetAttributeString(ssh_context, CRYPT_CTXINFO_LABEL, "ssh_server", 10))) {
+				lprintf(LOG_ERR,"Cryptlib error %d setting key label",i);
+				goto NO_SSH;
+			}
+			if(!cryptStatusOK(i=cryptGenerateKey(ssh_context))) {
+				lprintf(LOG_ERR,"Cryptlib error %d generating key",i);
+				goto NO_SSH;
+			}
+
+			/* Ok, now try saving this one... use the syspass to enctrpy it. */
+			if(cryptStatusOK(cryptKeysetOpen(&ssh_keyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE, str, CRYPT_KEYOPT_CREATE))) {
+				cryptAddPrivateKey(ssh_keyset, ssh_context, scfg.sys_pass);
+				cryptKeysetClose(ssh_keyset);
+			}
+		}
+
+		/* open a socket and wait for a client */
+
+		ssh_socket = open_socket(SOCK_STREAM, "ssh");
+
+		if(ssh_socket == INVALID_SOCKET) {
+			lprintf(LOG_ERR,"!ERROR %d creating SSH socket", ERROR_VALUE);
+			cleanup(1);
+			return;
+		}
+
+		lprintf(LOG_INFO,"SSH socket %d opened",ssh_socket);
+
+		/*****************************/
+		/* Listen for incoming calls */
+		/*****************************/
+		memset(&server_addr, 0, sizeof(server_addr));
+
+		server_addr.sin_addr.s_addr = htonl(startup->ssh_interface);
+		server_addr.sin_family = AF_INET;
+		server_addr.sin_port   = htons(startup->ssh_port);
+
+		if(startup->seteuid!=NULL)
+			startup->seteuid(FALSE);
+		result = retry_bind(ssh_socket,(struct sockaddr *)&server_addr,sizeof(server_addr)
+			,startup->bind_retry_count,startup->bind_retry_delay,"SSH Server",lprintf);
+		if(startup->seteuid!=NULL)
+			startup->seteuid(TRUE);
+		if(result != 0) {
+			lprintf(LOG_NOTICE,"%s",BIND_FAILURE_HELP);
+			cleanup(1);
+			return;
+		}
+
+		result = listen(ssh_socket, 1);
+
+		if(result != 0) {
+			lprintf(LOG_ERR,"!ERROR %d (%d) listening on SSH socket", result, ERROR_VALUE);
+			cleanup(1);
+			return;
+		}
+		lprintf(LOG_INFO,"SSH server listening on port %d",startup->ssh_port);
+	}
+NO_SSH:
+#endif
+
 	sbbs = new sbbs_t(0, server_addr.sin_addr.s_addr
 		,"BBS System", telnet_socket, &scfg, text, NULL);
     sbbs->online = 0;
@@ -4249,6 +4373,14 @@ void DLLCALL bbs_thread(void* arg)
 			if(rlogin_socket+1>high_socket_set)
 				high_socket_set=rlogin_socket+1;
 		}
+#ifdef USE_CRYPTLIB
+		if(startup->options&BBS_OPT_ALLOW_SSH
+			&& ssh_socket!=INVALID_SOCKET) {
+			FD_SET(ssh_socket,&socket_set);
+			if(ssh_socket+1>high_socket_set)
+				high_socket_set=ssh_socket+1;
+		}
+#endif
 #ifdef __unix__
 		for(i=first_node;i<=last_node;i++)  {
 			if(uspy_listen_socket[i-1]!=INVALID_SOCKET)  {
@@ -4286,6 +4418,9 @@ void DLLCALL bbs_thread(void* arg)
 		client_addr_len = sizeof(client_addr);
 
 		bool rlogin = false;
+#ifdef USE_CRYPTLIB
+		bool ssh = false;
+#endif
 
 		is_client=FALSE;
 		if(telnet_socket!=INVALID_SOCKET 
@@ -4299,6 +4434,46 @@ void DLLCALL bbs_thread(void* arg)
 	        	,&client_addr_len);
 			rlogin = true;
 			is_client=TRUE;
+#ifdef USE_CRYPTLIB
+		} else if(ssh_socket!=INVALID_SOCKET 
+			&& FD_ISSET(ssh_socket,&socket_set)) {
+			client_socket = accept_socket(ssh_socket, (struct sockaddr *)&client_addr
+	        	,&client_addr_len);
+			if(!cryptStatusOK(i=cryptCreateSession(&sbbs->ssh_session, CRYPT_UNUSED, CRYPT_SESSION_SSH_SERVER))) {
+				lprintf(LOG_ERR,"Cryptlib error %d creating session",i);
+				close_socket(client_socket);
+				continue;
+			}
+			if(!cryptStatusOK(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_PRIVATEKEY, ssh_context))) {
+				lprintf(LOG_ERR,"Cryptlib error %d setting private key",i);
+				cryptDestroySession(sbbs->ssh_session);
+				close_socket(client_socket);
+				continue;
+			}
+			/* Accept any credentials */
+			if(!cryptStatusOK(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_AUTHRESPONSE, 1))) {
+				lprintf(LOG_ERR,"Cryptlib error %d setting AUTHRESPONSE",i);
+				cryptDestroySession(sbbs->ssh_session);
+				close_socket(client_socket);
+				continue;
+			}
+			if(!cryptStatusOK(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_NETWORKSOCKET, client_socket))) {
+				lprintf(LOG_ERR,"Cryptlib error %d setting socket",i);
+				cryptDestroySession(sbbs->ssh_session);
+				close_socket(client_socket);
+				continue;
+			}
+			if(!cryptStatusOK(i=cryptSetAttribute(sbbs->ssh_session, CRYPT_SESSINFO_ACTIVE, 1))) {
+				lprintf(LOG_ERR,"Cryptlib error %d setting session active",i);
+				cryptDestroySession(sbbs->ssh_session);
+				close_socket(client_socket);
+				continue;
+			}
+			cryptPopData(sbbs->ssh_session, str, sizeof(str), &i);
+			ssh = true;
+			is_client=TRUE;
+			sbbs->ssh_mode=true;
+#endif
 		} else {
 #ifdef __unix__
 			for(i=first_node;i<=last_node;i++)  {
@@ -4364,13 +4539,24 @@ void DLLCALL bbs_thread(void* arg)
 		strcpy(host_ip,inet_ntoa(client_addr.sin_addr));
 
 		if(trashcan(&scfg,host_ip,"ip-silent")) {
+#ifdef USE_CRYPTLIB
+			if(ssh) {
+				cryptDestroySession(sbbs->ssh_session);
+				sbbs->ssh_mode=false;
+			}
+#endif
 			close_socket(client_socket);
 			continue;
 		}
 
 		lprintf(LOG_INFO,"%04d %s connection accepted from: %s port %u"
 			,client_socket
-			,rlogin ? "RLogin" : "Telnet", host_ip, ntohs(client_addr.sin_port));
+#ifdef USE_CRYPTLIB
+			,rlogin ? "RLogin" : (ssh ? "SSH" : "Telnet")
+#else
+			,rlogin ? "RLogin" : "Telnet"
+#endif
+			, host_ip, ntohs(client_addr.sin_port));
 
 #ifdef _WIN32
 		if(startup->answer_sound[0] && !(startup->options&BBS_OPT_MUTE)) 
@@ -4381,6 +4567,12 @@ void DLLCALL bbs_thread(void* arg)
         sbbs->online=ON_REMOTE;
 
 		if(sbbs->trashcan(host_ip,"ip")) {
+#ifdef USE_CRYPTLIB
+			if(ssh) {
+				cryptDestroySession(sbbs->ssh_session);
+				sbbs->ssh_mode=false;
+			}
+#endif
 			close_socket(client_socket);
 			lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in ip.can"
 				,client_socket);
@@ -4419,6 +4611,12 @@ void DLLCALL bbs_thread(void* arg)
 		}
 
 		if(sbbs->trashcan(host_name,"host")) {
+#ifdef USE_CRYPTLIB
+			if(ssh) {
+				cryptDestroySession(sbbs->ssh_session);
+				sbbs->ssh_mode=false;
+			}
+#endif
 			close_socket(client_socket);
 			lprintf(LOG_NOTICE,"%04d !CLIENT BLOCKED in host.can",client_socket);
 			sprintf(logstr, "Blocked Hostname: %s",host_name);
@@ -4445,7 +4643,11 @@ void DLLCALL bbs_thread(void* arg)
 		SAFECOPY(client.addr,host_ip);
 		SAFECOPY(client.host,host_name);
 		client.port=ntohs(client_addr.sin_port);
+#ifdef USE_CRYPTLIB
+		client.protocol=rlogin ? "RLogin":(ssh ? "SSH" : "Telnet");
+#else
 		client.protocol=rlogin ? "RLogin":"Telnet";
+#endif
 		client.user="<unknown>";
 		client_on(client_socket,&client,FALSE /* update */);
 
@@ -4473,6 +4675,12 @@ void DLLCALL bbs_thread(void* arg)
 			}
 			mswait(3000);
 			client_off(client_socket);
+#ifdef USE_CRYPTLIB
+			if(ssh) {
+				cryptDestroySession(sbbs->ssh_session);
+				sbbs->ssh_mode=false;
+			}
+#endif
 			close_socket(client_socket);
 			continue;
 		}
@@ -4480,9 +4688,16 @@ void DLLCALL bbs_thread(void* arg)
         node_socket[i-1]=client_socket;
 
 		sbbs_t* new_node = new sbbs_t(i, client_addr.sin_addr.s_addr, host_name
-        	,client_socket, &scfg, text, &client);
+        	,client_socket
+			,&scfg, text, &client);
 
 		new_node->client=client;
+#ifdef USE_CRYPTLIB
+		if(ssh) {
+			new_node->ssh_session=sbbs->ssh_session;
+			new_node->ssh_mode=true;
+		}
+#endif
 
 		/* copy the IDENT response, if any */
 		if(identity!=NULL)
@@ -4503,6 +4718,12 @@ void DLLCALL bbs_thread(void* arg)
 			delete new_node;
 			node_socket[i-1]=INVALID_SOCKET;
 			client_off(client_socket);
+#ifdef USE_CRYPTLIB
+			if(ssh) {
+				cryptDestroySession(sbbs->ssh_session);
+				sbbs->ssh_mode=false;
+			}
+#endif
 			close_socket(client_socket);
 			continue;
 		}
@@ -4512,6 +4733,14 @@ void DLLCALL bbs_thread(void* arg)
 			new_node->sys_status|=SS_RLOGIN;
 			new_node->telnet_mode|=TELNET_MODE_OFF; // RLogin does not use Telnet commands
 		}
+#ifdef USE_CRYPTLIB
+		if(ssh) {
+			new_node->connection="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;
+		}
+#endif
 
 	    node_threads_running++;
 		new_node->input_thread=(HANDLE)_beginthread(input_thread,0, new_node);
diff --git a/src/sbbs3/newuser.cpp b/src/sbbs3/newuser.cpp
index 06e99dd72f1408a95375222d4d096b635c201d9d..20d5dd70834eb83504e629d163be947a7a158bdd 100644
--- a/src/sbbs3/newuser.cpp
+++ b/src/sbbs3/newuser.cpp
@@ -186,7 +186,11 @@ BOOL sbbs_t::newuser()
 		else
 			useron.misc&=~NO_EXASCII;
 
+#ifdef USE_CRYPTLIB
+		if((sys_status&SS_RLOGIN || sys_status&SS_SSH) && rlogin_name[0])
+#else
 		if(sys_status&SS_RLOGIN && rlogin_name[0])
+#endif
 			strcpy(useron.alias,rlogin_name);
 		else {
 			while(online) {
diff --git a/src/sbbs3/sbbs.h b/src/sbbs3/sbbs.h
index 79be76860f7f711dc1df70ecdf6f82fd5a64ddc2..a56afac354ec0b763f143a9abb451351defbdf29 100644
--- a/src/sbbs3/sbbs.h
+++ b/src/sbbs3/sbbs.h
@@ -109,6 +109,10 @@ extern int	thread_suid_broken;			/* NPTL is no longer broken */
 
 #endif
 
+#ifdef USE_CRYPTLIB
+#include <cryptlib.h>
+#endif
+
 /***********************/
 /* Synchronet-specific */
 /***********************/
@@ -169,6 +173,10 @@ public:
 	char	client_name[128];
 	char	client_ident[128];
 	DWORD	local_addr;
+#ifdef USE_CRYPTLIB
+	CRYPT_SESSION	ssh_session;
+	bool	ssh_mode;
+#endif
 
 	scfg_t	cfg;
 
diff --git a/src/sbbs3/sbbs_ini.c b/src/sbbs3/sbbs_ini.c
index 037a58683d1b33743ecdfc50c91ef331e1c8aaea..7c862b7e65a1197fbd33f71677f4a9d750628d53 100644
--- a/src/sbbs3/sbbs_ini.c
+++ b/src/sbbs3/sbbs_ini.c
@@ -296,6 +296,13 @@ void sbbs_read_ini(
 		bbs->rlogin_port
 			=iniGetShortInt(list,section,"RLoginPort",513);
 
+#ifdef USE_CRYPTLIB
+		bbs->ssh_interface
+			=iniGetIpAddress(list,section,"SSHInterface",global->interface_addr);
+		bbs->ssh_port
+			=iniGetShortInt(list,section,"SSHPort",22);
+#endif
+
 		bbs->first_node
 			=iniGetShortInt(list,section,"FirstNode",1);
 		bbs->last_node
@@ -729,9 +736,18 @@ BOOL sbbs_write_ini(
 			iniRemoveValue(lp,section,"RLoginInterface");
 		else if(!iniSetIpAddress(lp,section,"RLoginInterface",bbs->rlogin_interface,&style))
 			break;
-
 		if(!iniSetShortInt(lp,section,"RLoginPort",bbs->rlogin_port,&style))
 			break;
+
+#ifdef USE_CRYPTLIB
+		if(bbs->ssh_interface==global->interface_addr)
+			iniRemoveValue(lp,section,"SSHInterface");
+		else if(!iniSetIpAddress(lp,section,"SSHInterface",bbs->ssh_interface,&style))
+			break;
+		if(!iniSetShortInt(lp,section,"SSHPort",bbs->ssh_port,&style))
+			break;
+#endif
+
 		if(!iniSetShortInt(lp,section,"FirstNode",bbs->first_node,&style))
 			break;
 		if(!iniSetShortInt(lp,section,"LastNode",bbs->last_node,&style))
diff --git a/src/sbbs3/sbbscon.c b/src/sbbs3/sbbscon.c
index 5d2cb9c0468425291e303aa588e3853911ea607e..4c00094b768cbd4f0db29b722ade4039545f3b57 100644
--- a/src/sbbs3/sbbscon.c
+++ b/src/sbbs3/sbbscon.c
@@ -1640,7 +1640,12 @@ int main(int argc, char** argv)
 		if(!thread_suid_broken) {
  			if(bbs_startup.telnet_port < IPPORT_RESERVED
 				|| (bbs_startup.options & BBS_OPT_ALLOW_RLOGIN
-					&& bbs_startup.rlogin_port < IPPORT_RESERVED))
+					&& bbs_startup.rlogin_port < IPPORT_RESERVED)
+#ifdef USE_CRYPTLIB
+				|| (bbs_startup.options & BBS_OPT_ALLOW_SSH
+					&& bbs_startup.ssh_port < IPPORT_RESERVED)
+#endif
+				)
 				bbs_startup.options|=BBS_OPT_NO_RECYCLE;
 			if(ftp_startup.port < IPPORT_RESERVED)
 				ftp_startup.options|=FTP_OPT_NO_RECYCLE;
diff --git a/src/sbbs3/startup.h b/src/sbbs3/startup.h
index 8344dd25dd7f9fc6af367cda5e785781ad765f1b..d02dc89ce832393b6dc9182f503a4906811cdb87 100644
--- a/src/sbbs3/startup.h
+++ b/src/sbbs3/startup.h
@@ -75,12 +75,18 @@ typedef struct {
     WORD	last_node;
 	WORD	telnet_port;
 	WORD	rlogin_port;
+#ifdef USE_CRYPTLIB
+	WORD	ssh_port;
+#endif
 	WORD	outbuf_highwater_mark;	/* output block size control */
 	WORD	outbuf_drain_timeout;
 	WORD	sem_chk_freq;		/* semaphore file checking frequency (in seconds) */
     DWORD   telnet_interface;
     DWORD	options;			/* See BBS_OPT definitions */
     DWORD	rlogin_interface;
+#ifdef USE_CRYPTLIB
+	DWORD	ssh_interface;
+#endif
     RingBuf** node_spybuf;			/* Spy output buffer (each node)	*/
     RingBuf** node_inbuf;			/* User input buffer (each node)	*/
     sem_t**	node_spysem;			/* Spy output semaphore (each node)	*/
@@ -154,6 +160,9 @@ static struct init_field {
 #define BBS_OPT_NO_EVENTS			(1<<9)	/* Don't run event thread			*/
 #define BBS_OPT_NO_SPY_SOCKETS		(1<<10)	/* Don't create spy sockets			*/
 #define BBS_OPT_NO_HOST_LOOKUP		(1<<11)
+#ifdef USE_CRYPTLIB
+#define BBS_OPT_ALLOW_SSH		(1<<26)	/* Allow logins via BSD SSH		*/
+#endif
 #define BBS_OPT_NO_RECYCLE			(1<<27)	/* Disable recycling of server		*/
 #define BBS_OPT_GET_IDENT			(1<<28)	/* Get Identity (RFC 1413)			*/
 #define BBS_OPT_NO_JAVASCRIPT		(1<<29)	/* JavaScript disabled				*/
@@ -161,8 +170,13 @@ static struct init_field {
 #define BBS_OPT_MUTE				(1<<31)	/* Mute sounds						*/
 
 /* bbs_startup_t.options bits that require re-init/recycle when changed */
+#ifdef USE_CRYPTLIB
+#define BBS_INIT_OPTS	(BBS_OPT_ALLOW_RLOGIN|BBS_OPT_ALLOW_SSH|BBS_OPT_NO_EVENTS|BBS_OPT_NO_SPY_SOCKETS \
+						|BBS_OPT_NO_JAVASCRIPT|BBS_OPT_LOCAL_TIMEZONE)
+#else
 #define BBS_INIT_OPTS	(BBS_OPT_ALLOW_RLOGIN|BBS_OPT_NO_EVENTS|BBS_OPT_NO_SPY_SOCKETS \
 						|BBS_OPT_NO_JAVASCRIPT|BBS_OPT_LOCAL_TIMEZONE)
+#endif
 
 #if defined(STARTUP_INI_BITDESC_TABLES)
 static ini_bitdesc_t bbs_options[] = {
@@ -178,6 +192,9 @@ static ini_bitdesc_t bbs_options[] = {
 	{ BBS_OPT_NO_EVENTS				,"NO_EVENTS"			},
 	{ BBS_OPT_NO_HOST_LOOKUP		,"NO_HOST_LOOKUP"		},
 	{ BBS_OPT_NO_SPY_SOCKETS		,"NO_SPY_SOCKETS"		},
+#ifdef USE_CRYPTLIB
+	{ BBS_OPT_ALLOW_SSH			,"ALLOW_SSH"			},
+#endif
 	{ BBS_OPT_NO_RECYCLE			,"NO_RECYCLE"			},
 	{ BBS_OPT_GET_IDENT				,"GET_IDENT"			},
 	{ BBS_OPT_NO_JAVASCRIPT			,"NO_JAVASCRIPT"		},