[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: wish list for rsh



>>>>> "Leif" == Leif Johansson <leifj@it.su.se> writes:

    >> Then again, I rather like the idea behind SASL, so may try
    >> implementing that, even if it does mean breaking the ssh
    >> standard ;-) I don't think Kerberos 5 has been standardized for
    >> ssh anyway.

    Leif> I have had the same thoughts myself. Please do!

Anyone willing to look at my patch?

This applies to openssh 1.2.1pre24, Debian version. Watch the
non-standard directory name!

The server side is implemented (as far as I can tell), but more work
needs to be done on client side authentication, mainly in auth-sasl.c,
especially with regard to handling errors, handling callbacks and
interactive responses, obtaining required information for all plugins
(eg serverFQDN). In addition, there might be protocol mismatches
between the server and client, and some things could simply be done
"better".

I think I might need a seperate sasldebug and saslfail for both server
and client, this is why I haven't handled client errors properly yet.

Also, I hope I haven't / won't break any of the design principles ssh
is currently based around. Need to be careful with the multiple data
transfers required for SASL (I think this is OK) and prompting user
for extra details, eg password.

On the plus side, I think I have modified the code so that both the
client and server support a "sasl" authentication type - this required
changing lots of code in lots of different places, but I don't think I
missed anything.

Of course, I haven't put the code anywhere near gcc yet, and dread the
moment.

This is the first time I have tried anything this extensive, so it
probably contains more bugs then Windows ;-).

Improvements welcome!

Final working version even better ;-)

diff -rcN openssh-1.2.1pre24/acconfig.h openssh-1.2.1pre24.new/acconfig.h
*** openssh-1.2.1pre24/acconfig.h	Fri Dec 31 09:55:34 1999
--- openssh-1.2.1pre24.new/acconfig.h	Thu Jan 27 16:09:30 2000
***************
*** 79,84 ****
--- 79,87 ----
  /* Define if you want Kerberos 4 support */
  #undef KRB4
  
+ /* Define if you want SASL support */
+ #undef SASL
+ 
  /* Define if you want AFS support */
  #undef AFS
  
diff -rcN openssh-1.2.1pre24/auth-sasl.c openssh-1.2.1pre24.new/auth-sasl.c
*** openssh-1.2.1pre24/auth-sasl.c	Thu Jan  1 10:00:00 1970
--- openssh-1.2.1pre24.new/auth-sasl.c	Thu Jan 27 16:22:50 2000
***************
*** 0 ****
--- 1,267 ----
+ /*
+  *    Dug Song <dugsong@UMICH.EDU>
+  *    Kerberos v4 authentication and ticket-passing routines.
+  */
+ 
+ #include "includes.h"
+ #include "packet.h"
+ #include "xmalloc.h"
+ #include "ssh.h"
+ #include "servconf.h"
+ 
+ #ifdef SASL
+ #include <sasl.h>
+ #include <saslutil.h>
+ 
+ int 
+ auth_sasl_client()
+ {
+ 	int result;
+ 	sasl_conn_t *conn;
+ 	sasl_interact_t *client_interact=NULL;
+ 	unsigned serverinlen;
+ 	const char *serverin;
+ 	unsigned result_len;
+ 	char *result_string;
+ 
+ 	result=sasl_client_init(callbacks);
+  	if (result!=SASL_OK)
+ 
+ 	result=sasl_client_new("imap",     /* The service we are using */
+ 				serverFQDN,/* The fully qualified domain
+ 					      name of the server we're
+ 					      connecting to */
+ 				NULL,
+ 				0,
+ 				&conn);     /* allocated on success */
+ 	if (result!=SASL_OK)
+ 	
+ 	do {
+ 		result=sasl_client_start(
+ 			conn,      /* the same context from above */
+ 			mechlist,  /* the list of mechanisms from the server */
+ 			NULL,
+ 			&client_interact, /* filled in if an interaction
+ 					     	is needed */
+ 			&result_string,      /* filled in on success */
+ 			&result_len,   /* filled in on success */
+ 			&mechusing);
+ 
+ 		if (result==SASL_INTERACT)
+ 		{
+ 
+ 		}
+ 	} while (result==SASL_INTERACT); 
+ 
+ 	if (result != SASL_OK)
+ 	
+ 	packet_start(SSH_AUTH_SASL);
+ 	packet_put_string("", 0);
+ 	packet_send();
+ 	packet_write_wait();
+ 
+ 	packet_read_expect(&plen, SSH_SMSG_AUTH_SASL_RESPONSE);
+ 	serverin = packet_get_string(&serverinlen);
+ 	while (1)
+ 	{
+ 		do
+ 		{
+ 			result=sasl_client_step(
+ 				conn,  /* our context */
+ 				serverin, /* the data from the server */
+ 				serverinlen, /* it's length */
+ 				&client_interact,  /* this should be unal
+ 						      located and NULL */
+ 				&out,  /* filled in on success */
+ 				&outlen); /* filled in on success */
+ 
+ 			if (result==SASL_INTERACT)
+ 			{
+ 			}
+ 
+ 		} while (result==SASL_INTERACT);
+ 	}
+ 	sasl_dispose(&conn);
+ 	sasl_done();
+ 	return 1;
+ }
+ 
+ static sasl_callback_t server_callbacks[] = {
+     {
+ 	SASL_CB_LOG, &sasl_my_log, NULL
+     }, /* {
+ 	SASL_CB_GETPATH, &getpath, NULL
+     }, */ {
+ 	SASL_CB_LIST_END, NULL, NULL
+     }
+ };
+ 
+ static int
+ sasl_my_log(void *context __attribute__((unused)),
+ 	int priority,
+ 	const char *message) 
+ {
+ 	const char *label;
+ 
+ 	assert(message);
+ 	switch (priority) {
+ 	case SASL_LOG_ERR:
+ 		label = "Error";
+ 		break;
+ 	case SASL_LOG_WARNING:
+ 		label = "Warning";
+ 		break;
+ 	case SASL_LOG_INFO:
+ 		label = "Info";
+ 		break;
+ 	default:
+ 		assert(0);
+ 	}
+ 							  }
+ 
+ 	log("%s: %s", label, message);
+ }
+ 
+ static void
+ sasldebug(int why, const char *what, const char *errstr)
+ {
+     if (errstr)
+ 	  packet_send_debug("%s: %s: %s (%s)",
+ 		progname,
+ 		what,
+ 		sasl_errstring(why, NULL, NULL), errstr);
+     else
+ 	  packet_send_debug("%s: %s: %s",
+ 		progname,
+ 		what,
+ 		sasl_errstring(why, NULL, NULL));
+ }
+ 
+ static void
+ saslfail(int why, const char *what, const char *errstr)
+ {
+ 	sasldebug(why, what, errstr);
+ 	exit(EXIT_FAILURE);
+ }
+ 
+ int 
+ auth_sasl_server(const char *server_user, char **ppszUser)
+ {
+ 	int result;
+ 	const char *errstr = NULL;
+ 	unsigned clientinlen;
+ 	const char *clientin = packet_get_string(&clientinlen);
+ 	unsigned result_len;
+ 	char *result_string;
+ 	
+ 	result = sasl_server_init(
+ 			server_callbacks,	/* Callbacks supported */
+ 			"ssh");		/* Name of the application */
+ 
+ 	if (result != SASL_OK)
+ 	{
+ 		saslfail(result, "Initializing libsasl", NULL);
+ 		return(-1);
+ 	}
+ 
+ 	result = sasl_server_new("ssh",
+ 			NULL,	/* my fully qualified domain name;
+ 				   NULL says use gethostname() */
+ 			NULL,	/* The user realm used for password
+ 				   lookups; NULL means default to serverFQDN
+ 				   Note: This does not affect Kerberos */
+ 			NULL,	/* Callbacks supported only for this
+ 				   connection */
+ 			0,	/* I support encryption layers;
+ 				   otherwise pass 0 */
+ 			&conn);
+ 
+ 	if (result != SASL_OK)
+ 	{
+ 		saslfail(result, "Allocating sasl connection state", NULL);
+ 		return(-1);
+ 	}
+ 	
+ 
+ 	result=sasl_listmech(
+ 			conn,  /* The context for this connection */
+ 			NULL,  /* not supported */
+ 			"{",   /* What to prepend the string with */
+ 			", ",  /* What to seperate mechanisms with */
+ 			"}",   /* What to append to the string */
+ 			&result_string, /* The produced string. Allocated
+ 					   by library */
+ 			&string_length, /* length of the string */
+ 			&number_of_mechanisms); /* Number of mechanisms in the
+ 						   string */
+ 
+ 
+ 	if (result != SASL_OK)
+ 	{
+ 		saslfail(result, "Generating client mechanism list", NULL);
+ 		return(-1);
+ 	}
+ 
+ 	packet_start(SSH_SMSG_AUTH_SASL_RESPONSE);
+ 	packet_put_string(result_string, result_length);
+ 	packet_send();
+ 	packet_write_wait();
+ 
+ 	packet_read_expect(&plen, SSH_AUTH_SASL);
+ 	clientin = packet_get_string(&clientinlen);
+ 
+ 	result=sasl_server_start(
+ 			conn, /* context */
+ 			mechanism_client_chose,
+ 			clientin,    /* the optional string the client
+ 					gave us */
+ 			clientinlen, /* and it's length */
+ 			&out, /* allocated by library on success. Might
+ 				 not be NULL terminated */
+ 			&outlen,
+ 			&errstr); /* error string filled in on failure */
+         if ((result!=SASL_OK) && (result!=SASL_CONTINUE))
+ 	{
+ 		saslfail(result, "Starting SASL negotiation", errstr);
+ 		return(-1);
+ 	}
+ 			    
+ 	while (result == SASL_CONTINUE) {
+ 	{
+ 		assert(data != NULL);
+ 		packet_start(SSH_SMSG_AUTH_SASL_RESPONSE);
+ 		packet_put_string(result_string, result_length);
+ 		packet_send();
+ 		packet_write_wait();
+ 
+ 		packet_read_expect(&plen, SSH_AUTH_SASL);
+ 		clientin = packet_get_string(&clientinlen);
+ 
+ 		result=sasl_server_step(conn,
+ 			clientin,      /* what the client gave */
+ 			clientinlen,   /* it's length */
+ 			&result_string,/* allocated by library on success.
+ 					Might not be NULL terminated */
+ 			&result_length,
+ 			&errstr);      /* error string sometimes filled in
+ 					  on failure */
+ 	}
+ 
+         if ((result!=SASL_OK) && (result!=SASL_CONTINUE))
+ 	{
+ 		saslfail(result, "Performing SASL negotiation", errstr);
+ 		return(-1);
+ 	}
+ 
+ 	result = sasl_getprop(conn, SASL_USERNAME, ppszUser);
+         if (result!=SASL_OK)
+ 	{
+ 		saslfail(result, "username", NULL);
+ 		return(-1);
+ 	}
+ 
+ 	sasl_dispose(&conn);
+ 	sasl_done();
+ 	return 1;
+ }
+ #endif /* SASL */
diff -rcN openssh-1.2.1pre24/configure.in openssh-1.2.1pre24.new/configure.in
*** openssh-1.2.1pre24/configure.in	Fri Dec 31 09:55:34 1999
--- openssh-1.2.1pre24.new/configure.in	Thu Jan 27 16:08:26 2000
***************
*** 410,415 ****
--- 410,427 ----
  	]
  )
  
+ dnl Check whether user wants Kerberos support
+ AC_ARG_WITH(sasl,
+ 	[  --with-sasl        Enable SASL support],
+ 	[
+ 		if test "x$withval" != "$xno" ; then
+ 			AC_DEFINE(SASL)
+ 			LIBS="$LIBS -lsasl"
+ 			CFLAGS="$CFLAGS"
+ 		fi
+ 	]
+ )
+ 
  dnl Check whether user wants AFS support
  AC_ARG_WITH(afs,
  	[  --with-afs              Enable AFS support],
diff -rcN openssh-1.2.1pre24/readconf.c openssh-1.2.1pre24.new/readconf.c
*** openssh-1.2.1pre24/readconf.c	Thu Jan 27 16:09:53 2000
--- openssh-1.2.1pre24.new/readconf.c	Thu Jan 27 16:03:34 2000
***************
*** 94,99 ****
--- 94,102 ----
  #ifdef KRB4
  	oKerberosAuthentication,
  #endif /* KRB4 */
+ #ifdef SASL
+ 	oSaslAuthentication,
+ #endif /* SASL */
  #ifdef AFS
  	oKerberosTgtPassing, oAFSTokenPassing,
  #endif
***************
*** 122,127 ****
--- 125,133 ----
  #ifdef KRB4
  	{ "kerberosauthentication", oKerberosAuthentication },
  #endif /* KRB4 */
+ #ifdef SASL
+ 	{ "saslauthentication", oSaslAuthentication },
+ #endif /* SASL */
  #ifdef AFS
  	{ "kerberostgtpassing", oKerberosTgtPassing },
  	{ "afstokenpassing", oAFSTokenPassing },
***************
*** 302,307 ****
--- 308,319 ----
  		goto parse_flag;
  #endif /* KRB4 */
  
+ #ifdef SASL
+ 	case oSaslAuthentication:
+ 		intptr = &options->sasl_authentication;
+ 		goto parse_flag;
+ #endif /* SASL */
+ 
  #ifdef AFS
  	case oKerberosTgtPassing:
  		intptr = &options->kerberos_tgt_passing;
***************
*** 597,602 ****
--- 609,617 ----
  #ifdef KRB4
  	options->kerberos_authentication = -1;
  #endif
+ #ifdef SASL
+ 	options->sasl_authentication = -1;
+ #endif
  #ifdef AFS
  	options->kerberos_tgt_passing = -1;
  	options->afs_token_passing = -1;
***************
*** 652,657 ****
--- 667,676 ----
  #ifdef KRB4
  	if (options->kerberos_authentication == -1)
  		options->kerberos_authentication = 1;
+ #endif /* KRB4 */
+ #ifdef SASL
+ 	if (options->sasl_authentication == -1)
+ 		options->sasl_authentication = 1;
  #endif /* KRB4 */
  #ifdef AFS
  	if (options->kerberos_tgt_passing == -1)
diff -rcN openssh-1.2.1pre24/readconf.h openssh-1.2.1pre24.new/readconf.h
*** openssh-1.2.1pre24/readconf.h	Thu Jan 27 16:09:53 2000
--- openssh-1.2.1pre24.new/readconf.h	Thu Jan 27 15:30:25 2000
***************
*** 41,46 ****
--- 41,50 ----
  	int     kerberos_authentication;	/* Try Kerberos
  						 * authentication. */
  #endif
+ #ifdef SASL
+ 	int     sasl_authentication;	/* Try SASL
+ 						 * authentication. */
+ #endif
  #ifdef AFS
  	int     kerberos_tgt_passing;	/* Try Kerberos tgt passing. */
  	int     afs_token_passing;	/* Try AFS token passing. */
diff -rcN openssh-1.2.1pre24/servconf.c openssh-1.2.1pre24.new/servconf.c
*** openssh-1.2.1pre24/servconf.c	Thu Nov 25 11:54:59 1999
--- openssh-1.2.1pre24.new/servconf.c	Thu Jan 27 16:06:45 2000
***************
*** 49,54 ****
--- 49,57 ----
  	options->kerberos_or_local_passwd = -1;
  	options->kerberos_ticket_cleanup = -1;
  #endif
+ #ifdef SASL
+ 	options->sasl_authentication = -1;
+ #endif
  #ifdef AFS
  	options->kerberos_tgt_passing = -1;
  	options->afs_token_passing = -1;
***************
*** 122,127 ****
--- 125,134 ----
  	if (options->kerberos_ticket_cleanup == -1)
  		options->kerberos_ticket_cleanup = 1;
  #endif /* KRB4 */
+ #ifdef SASL
+ 	if (options->sasl_authentication == -1)
+ 		options->sasl_authentication = 1;
+ #endif /* SASL */
  #ifdef AFS
  	if (options->kerberos_tgt_passing == -1)
  		options->kerberos_tgt_passing = 0;
***************
*** 151,156 ****
--- 158,166 ----
  #ifdef KRB4
  	sKerberosAuthentication, sKerberosOrLocalPasswd, sKerberosTicketCleanup,
  #endif
+ #ifdef SASL
+ 	sSaslAuthentication,
+ #endif
  #ifdef AFS
  	sKerberosTgtPassing, sAFSTokenPassing,
  #endif
***************
*** 185,190 ****
--- 195,203 ----
  	{ "kerberosorlocalpasswd", sKerberosOrLocalPasswd },
  	{ "kerberosticketcleanup", sKerberosTicketCleanup },
  #endif
+ #ifdef SASL
+ 	{ "saslauthentication", sSaslAuthentication },
+ #endif
  #ifdef AFS
  	{ "kerberostgtpassing", sKerberosTgtPassing },
  	{ "afstokenpassing", sAFSTokenPassing },
***************
*** 387,392 ****
--- 400,411 ----
  
  		case sKerberosTicketCleanup:
  			intptr = &options->kerberos_ticket_cleanup;
+ 			goto parse_flag;
+ #endif
+ 
+ #ifdef SASL
+ 		case sSaslAuthentication:
+ 			intptr = &options->sasl_authentication;
  			goto parse_flag;
  #endif
  
diff -rcN openssh-1.2.1pre24/servconf.h openssh-1.2.1pre24.new/servconf.h
*** openssh-1.2.1pre24/servconf.h	Thu Nov 25 11:54:59 1999
--- openssh-1.2.1pre24.new/servconf.h	Thu Jan 27 15:30:49 2000
***************
*** 61,66 ****
--- 61,69 ----
  	int     kerberos_ticket_cleanup;	/* If true, destroy ticket
  						 * file on logout. */
  #endif
+ #ifdef SASL
+ 	int     sasl_authentication;	/* If true, SASL authentication */
+ #endif
  #ifdef AFS
  	int     kerberos_tgt_passing;	/* If true, permit Kerberos tgt
  					 * passing. */
diff -rcN openssh-1.2.1pre24/ssh.h openssh-1.2.1pre24.new/ssh.h
*** openssh-1.2.1pre24/ssh.h	Thu Jan 27 16:09:53 2000
--- openssh-1.2.1pre24.new/ssh.h	Thu Jan 27 14:13:26 2000
***************
*** 212,217 ****
--- 212,218 ----
  #define SSH_PASS_KERBEROS_TGT	7
  				/* 8 to 15 are reserved */
  #define SSH_PASS_AFS_TOKEN	21
+ #define SSH_AUTH_SASL		22
  
  /* Protocol flags.  These are bit masks. */
  #define SSH_PROTOFLAG_SCREEN_NUMBER	1	/* X11 forwarding includes screen */
***************
*** 270,275 ****
--- 271,277 ----
  #define SSH_SMSG_AUTH_KERBEROS_RESPONSE		43	/* (KTEXT) */
  #define SSH_CMSG_HAVE_KERBEROS_TGT		44	/* credentials (s) */
  #define SSH_CMSG_HAVE_AFS_TOKEN			65	/* token (s) */
+ #define SSH_SMSG_AUTH_SASL_REPLY		66
  
  /*------------ definitions for login.c -------------*/
  
diff -rcN openssh-1.2.1pre24/sshconnect.c openssh-1.2.1pre24.new/sshconnect.c
*** openssh-1.2.1pre24/sshconnect.c	Tue Dec 21 20:57:20 1999
--- openssh-1.2.1pre24.new/sshconnect.c	Thu Jan 27 16:22:26 2000
***************
*** 1553,1558 ****
--- 1553,1568 ----
  	}
  #endif /* AFS */
  
+ #ifdef SASL
+ 	if ((supported_authentications & (1 << SSH_AUTH_SASL)) &&
+ 	    options.sasl_authentication) {
+ 		debug("Trying SASL authentication.");
+ 		if (auth_sasl_client()) {
+ 			return;
+ 		}
+ 	}
+ #endif /* SASL */
+ 
  #ifdef KRB4
  	if ((supported_authentications & (1 << SSH_AUTH_KERBEROS)) &&
  	    options.kerberos_authentication) {
diff -rcN openssh-1.2.1pre24/sshd.c openssh-1.2.1pre24.new/sshd.c
*** openssh-1.2.1pre24/sshd.c	Thu Dec 30 15:08:44 1999
--- openssh-1.2.1pre24.new/sshd.c	Thu Jan 27 15:05:57 2000
***************
*** 223,228 ****
--- 223,232 ----
  	case SSH_CMSG_AUTH_KERBEROS:
  		return "kerberos";
  #endif
+ #ifdef SASL
+ 	case SSH_CMSG_AUTH_KERBEROS:
+ 		return "kerberos";
+ #endif
  #ifdef SKEY
  	case SSH_CMSG_AUTH_TIS_RESPONSE:
  		return "s/key";
***************
*** 865,870 ****
--- 869,878 ----
  	if (options.kerberos_authentication)
  		auth_mask |= 1 << SSH_AUTH_KERBEROS;
  #endif
+ #ifdef SASL
+ 	if (options.sasl_authentication)
+ 		auth_mask |= 1 << SSH_AUTH_SASL;
+ #endif
  #ifdef AFS
  	if (options.kerberos_tgt_passing)
  		auth_mask |= 1 << SSH_PASS_KERBEROS_TGT;
***************
*** 1249,1254 ****
--- 1257,1278 ----
  			}
  			break;
  #endif /* KRB4 */
+ #ifdef SASL
+ 		case SSH_CMSG_AUTH_SASL:
+ 			if (!options.sasl_authentication) { 
+ 				/* packet_get_all(); */
+ 				verbose("Sasl authentication disabled.");
+ 				break;
+ 			} else {
+ 				char *pszUser;
+ 				authenticated = auth_sasl_server(pw->pw_name,&pszUser);
+ 				if (authenticated) {
+ 				{
+ 					snprintf(user, sizeof user, " sasl %s", pszUser);
+ 				}
+ 			}
+ 			break;
+ #endif /* SASL */
  
  		case SSH_CMSG_AUTH_RHOSTS:
  			if (!options.rhosts_authentication) {

-- 
Brian May <bmay@csse.monash.edu.au>