patch for TIS (skey/opie) *and* passwd auth via PAM

Hein Roehrig hein at acm.org
Mon Aug 28 03:37:14 EST 2000


Hello,

appended is a patch that makes it possible to use PAM both for
password authentication and TIS (i.e. s/key or opie or any other
interactive challenge/response scheme). I have developed this starting
from the patch at http://www.debian.org/Bugs/db/61/61906.html on
Debian with openssh-2.1.1p4-3. After configuring ssh with
--with-pam-tis, there are two PAM services, "sshd" and "sshd-tis"
(resp. "ssh" and "ssh-tis" on Debian); /etc/pam.d/ssh-tis could
contain for example
------------
#%PAM-1.0
auth       required     pam_nologin.so
auth       required     pam_opie.so
auth       required     pam_env.so # [1]

account    required     pam_unix.so

session    required     pam_unix.so
session    optional     pam_lastlog.so # [1]
session    optional     pam_motd.so # [1]
session    optional     pam_mail.so standard # [1]

password   required     pam_unix.so
------------
I.e, the only change to the default /etc/pam.d/ssh is unix -> opie in
line 3.

I hope this patch will allow using ssh with OPIE on Debian; I am
looking forward to your comments. If in principle this approach is ok,
what changes are needed to get this patch into the development tree? I
know that my C indenting is not the same as in the rest of the source,
where do I find the official indentation style?

Thanks,
Hein

diff -urN -x *~ openssh-2.1.1p4/acconfig.h openssh-2.1.1p4-hein/acconfig.h
--- openssh-2.1.1p4/acconfig.h	Sat Jul 15 06:59:14 2000
+++ openssh-2.1.1p4-hein/acconfig.h	Sun Aug 27 12:13:36 2000
@@ -30,6 +30,9 @@
 /* Define if you want to disable PAM support */
 #undef DISABLE_PAM
 
+/* Define if you want TIS authentication through PAM */
+#undef PAM_TIS
+
 /* Define if you want to enable AIX4's authenticate function */
 #undef WITH_AIXAUTHENTICATE
 
diff -urN -x *~ openssh-2.1.1p4/auth-pam.c openssh-2.1.1p4-hein/auth-pam.c
--- openssh-2.1.1p4/auth-pam.c	Sun Jul  9 14:42:33 2000
+++ openssh-2.1.1p4-hein/auth-pam.c	Sun Aug 27 18:05:44 2000
@@ -33,12 +33,15 @@
 #include "ssh.h"
 #include "xmalloc.h"
 #include "servconf.h"
+#include "packet.h"
 
 RCSID("$Id: auth-pam.c,v 1.11 2000/07/09 12:42:33 djm Exp $");
 
 #define NEW_AUTHTOK_MSG \
 	"Warning: You password has expired, please change it now"
 
+static void start_pam2(struct passwd *pw, int auth_type);
+
 /* Callbacks */
 static int pamconv(int num_msg, const struct pam_message **msg,
 	  struct pam_response **resp, void *appdata_ptr);
@@ -53,6 +56,7 @@
 static struct pam_handle_t *pamh = NULL;
 static const char *pampasswd = NULL;
 static char *pam_msg = NULL;
+static int current_auth_type=-1;
 
 /* PAM conversation function. This is really a kludge to get the password */
 /* into PAM and to pick up any messages generated by PAM into pamconv_msg */
@@ -61,6 +65,7 @@
 {
 	struct pam_response *reply;
 	int count;
+        int dlen, plen, type;
 
 	/* PAM will free this later */
 	reply = malloc(num_msg * sizeof(*reply));
@@ -70,13 +75,58 @@
 	for(count = 0; count < num_msg; count++) {
 		switch (msg[count]->msg_style) {
 			case PAM_PROMPT_ECHO_OFF:
-				if (pampasswd == NULL) {
-					free(reply);
-					return PAM_CONV_ERR;
+                            if (current_auth_type==SSH_CMSG_AUTH_TIS && pampasswd==NULL) {
+                                /* TIS */
+                                int prompt_len;
+                                char *prompt;
+                                debug("send SSH_SMSG_AUTH_TIS_CHALLENGE in PAM");
+                                /* send all previous PAM_TEXT_INFO messages plus
+                                   the current prompt */
+                                prompt_len=((pam_msg!=NULL)?strlen(pam_msg):0) +
+                                    strlen(msg[count]->msg);
+                                prompt=xmalloc(prompt_len + 1);
+                                if (pam_msg!=NULL) {
+                                    strcpy(prompt, pam_msg);
+                                    xfree(pam_msg);
+                                    pam_msg=NULL;
+                                } else
+                                    *prompt='\0';
+                                strcat(prompt, msg[count]->msg);
+                                /* cut off Response: from the prompt because the
+                                   SSH client already prints this */
+                                if (prompt_len >= sizeof("Response: ") - 1 &&
+                                    0==strcasecmp(prompt + prompt_len - sizeof("\nResponse: ") + 1,
+                                                  "\nResponse: ")) {
+                                    prompt[prompt_len - sizeof("\nResponse: ") + 1]='\0';
+                                }
+                                packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
+                                packet_put_string(prompt, prompt_len);
+                                xfree(prompt);
+                                packet_send();
+                                packet_write_wait();
+                                type = packet_read(&plen);
+                                if (type == SSH_CMSG_AUTH_TIS_RESPONSE) {
+                                    debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE in PAM");
+                                    pampasswd = packet_get_string(&dlen);
+                                    packet_integrity_check(plen, 4 + dlen, type);
+                                } else {
+                                    free(reply);
+                                    return PAM_CONV_ERR;
+                                }
+                                reply[count].resp_retcode = PAM_SUCCESS;
+                                reply[count].resp = xstrdup(pampasswd);
+                                xfree((void*)pampasswd);
+                                pampasswd=NULL;
+                            } else {
+                                /* password or second TIS attempt */
+                                if (pampasswd == NULL) {
+                                    free(reply);
+                                    return PAM_CONV_ERR;
 				}
 				reply[count].resp_retcode = PAM_SUCCESS;
 				reply[count].resp = xstrdup(pampasswd);
-				break;
+                            }
+                            break;
 			case PAM_TEXT_INFO:
 				reply[count].resp_retcode = PAM_SUCCESS;
 				reply[count].resp = xstrdup("");
@@ -123,29 +173,34 @@
 	}
 }
 
-/* Attempt password authentation using PAM */
-int auth_pam_password(struct passwd *pw, const char *password)
+/* Attempt authentication using PAM */
+int auth_pam_password(struct passwd *pw, const char *password, int auth_type)
 {
 	extern ServerOptions options;
 	int pam_retval;
 
+        if (auth_type != current_auth_type) {
+            finish_pam();
+            start_pam2(pw, auth_type);
+        }
+        
 	/* deny if no user. */
 	if (pw == NULL)
 		return 0;
 	if (pw->pw_uid == 0 && options.permit_root_login == 2)
 		return 0;
-	if (*password == '\0' && options.permit_empty_passwd == 0)
+	if (password!=NULL && *password == '\0' && options.permit_empty_passwd == 0)
 		return 0;
 
 	pampasswd = password;
 	
 	pam_retval = pam_authenticate((pam_handle_t *)pamh, 0);
 	if (pam_retval == PAM_SUCCESS) {
-		debug("PAM Password authentication accepted for user \"%.100s\"", 
+		debug("PAM authentication accepted for user \"%.100s\"", 
 			pw->pw_name);
 		return 1;
 	} else {
-		debug("PAM Password authentication for \"%.100s\" failed: %s", 
+		debug("PAM authentication for \"%.100s\" failed: %s", 
 			pw->pw_name, PAM_STRERROR((pam_handle_t *)pamh, pam_retval));
 		return 0;
 	}
@@ -234,11 +289,34 @@
 /* Start PAM authentication for specified account */
 void start_pam(struct passwd *pw)
 {
+    start_pam2(pw, SSH_CMSG_AUTH_PASSWORD);
+}
+
+
+/* Start PAM authentication for specified account */
+static void start_pam2(struct passwd *pw, int auth_type)
+{
 	int pam_retval;
+        const char *service=NULL;
 
-	debug("Starting up PAM with username \"%.200s\"", pw->pw_name);
+        switch (auth_type) {
+        case SSH_CMSG_AUTH_PASSWORD :
+            service=SSHD_PAM_SERVICE;
+            break;
+        case SSH_CMSG_AUTH_TIS :
+            service=SSHD_PAM_TIS_SERVICE;
+            break;
+        default:
+            fatal("PAM attempted for unsupported authentication type\n");
+        }
+
+        current_auth_type=auth_type;
+        
+	debug("Starting up PAM service %.200s with username \"%.200s\"",
+              service,
+              pw->pw_name);
 
-	pam_retval = pam_start(SSHD_PAM_SERVICE, pw->pw_name, &conv, 
+	pam_retval = pam_start(service, pw->pw_name, &conv, 
 		(pam_handle_t**)&pamh);
 
 	if (pam_retval != PAM_SUCCESS) {
diff -urN -x *~ openssh-2.1.1p4/auth-pam.h openssh-2.1.1p4-hein/auth-pam.h
--- openssh-2.1.1p4/auth-pam.h	Thu Jan 27 00:55:38 2000
+++ openssh-2.1.1p4-hein/auth-pam.h	Sun Aug 27 17:27:46 2000
@@ -5,7 +5,7 @@
 
 void start_pam(struct passwd *pw);
 void finish_pam(void);
-int auth_pam_password(struct passwd *pw, const char *password);
+int auth_pam_password(struct passwd *pw, const char *password, int auth_type);
 char **fetch_pam_environment(void);
 int do_pam_account(char *username, char *remote_user);
 void do_pam_session(char *username, const char *ttyname);
diff -urN -x *~ openssh-2.1.1p4/auth1.c openssh-2.1.1p4-hein/auth1.c
--- openssh-2.1.1p4/auth1.c	Sat Jul  8 02:44:14 2000
+++ openssh-2.1.1p4-hein/auth1.c	Sun Aug 27 17:27:53 2000
@@ -40,7 +40,11 @@
 	static char buf[1024];
 	switch (type) {
 	case SSH_CMSG_AUTH_PASSWORD:
+#ifdef USE_PAM
+		return "pam-password";
+#else
 		return "password";
+#endif
 	case SSH_CMSG_AUTH_RSA:
 		return "rsa";
 	case SSH_CMSG_AUTH_RHOSTS_RSA:
@@ -55,6 +59,11 @@
 	case SSH_CMSG_AUTH_TIS_RESPONSE:
 		return "s/key";
 #endif
+#ifdef PAM_TIS
+	case SSH_CMSG_AUTH_TIS:
+	case SSH_CMSG_AUTH_TIS_RESPONSE:
+		return "pam-tis";
+#endif
 	}
 	snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
 	return buf;
@@ -307,7 +316,7 @@
 
 #ifdef USE_PAM
 			/* Do PAM auth with password */
-			authenticated = auth_pam_password(pw, password);
+			authenticated = auth_pam_password(pw, password, SSH_CMSG_AUTH_PASSWORD);
 #elif defined(HAVE_OSF_SIA)
 			/* Do SIA auth with password */
 			if (sia_validate_user(NULL, saved_argc, saved_argv, 
@@ -355,6 +364,26 @@
 				xfree(response);
 			}
 			break;
+#elif defined(PAM_TIS)
+		case SSH_CMSG_AUTH_TIS:
+			debug("rcvd SSH_CMSG_AUTH_TIS");
+			if (!options.tis_authentication) {
+				verbose("TIS authentication disabled.");
+				break;
+			}
+                        authenticated = auth_pam_password(pw, NULL, SSH_CMSG_AUTH_TIS);
+                        break;
+		case SSH_CMSG_AUTH_TIS_RESPONSE:
+			debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
+			if (!options.tis_authentication) {
+				verbose("TIS authentication disabled.");
+				break;
+			} else {
+                            char *response = packet_get_string(&dlen);
+                            authenticated = auth_pam_password(pw, response, SSH_CMSG_AUTH_TIS);
+                            xfree(response);
+                        }
+                        break;
 #else
 		case SSH_CMSG_AUTH_TIS:
 			/* TIS Authentication is unsupported */
@@ -503,7 +532,7 @@
 	    (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
 #endif /* KRB4 */
 #ifdef USE_PAM
-	    auth_pam_password(pw, "")) {
+	    auth_pam_password(pw, "", SSH_CMSG_AUTH_PASSWORD)) {
 #elif defined(HAVE_OSF_SIA)
 	    (sia_validate_user(NULL, saved_argc, saved_argv, 
 	    get_canonical_hostname(), pw->pw_name, NULL, 0, NULL, 
diff -urN -x *~ openssh-2.1.1p4/auth2.c openssh-2.1.1p4-hein/auth2.c
--- openssh-2.1.1p4/auth2.c	Tue Jul 11 09:31:38 2000
+++ openssh-2.1.1p4-hein/auth2.c	Sun Aug 27 17:39:22 2000
@@ -102,6 +102,9 @@
 #ifdef SKEY
 	options.skey_authentication = 0;
 #endif
+#ifdef PAM_TIS
+        options.tis_authentication = 0;
+#endif
 #ifdef KRB4
 	options.kerberos_authentication = 0;
 #endif
@@ -257,7 +260,7 @@
 	packet_done();
 
 #ifdef USE_PAM
-	return auth_pam_password(pw, "");
+	return auth_pam_password(pw, "", SSH_CMSG_AUTH_PASSWORD);
 #elif defined(HAVE_OSF_SIA)
 	return(sia_validate_user(NULL, saved_argc, saved_argv, 
 		get_canonical_hostname(), pw->pw_name, NULL, 0, NULL, 
@@ -284,7 +287,7 @@
 	packet_done();
 	if (options.password_authentication &&
 #ifdef USE_PAM
-	    auth_pam_password(pw, password) == 1)
+	    auth_pam_password(pw, password, SSH_CMSG_AUTH_PASSWORD) == 1)
 #elif defined(HAVE_OSF_SIA)
 	    sia_validate_user(NULL, saved_argc, saved_argv, 
 		 	get_canonical_hostname(), pw->pw_name, NULL, 0, 
diff -urN -x *~ openssh-2.1.1p4/configure.in openssh-2.1.1p4-hein/configure.in
--- openssh-2.1.1p4/configure.in	Sat Jul 15 06:59:14 2000
+++ openssh-2.1.1p4-hein/configure.in	Sun Aug 27 12:31:26 2000
@@ -306,6 +306,18 @@
 	) 
 fi
 
+PAM_TIS_MSG="no"
+AC_ARG_WITH(pam-tis,
+	[  --with-pam-tis           Enable PAM for TIS support ],
+	[
+		if test "x$withval" = "xyes" ; then
+			pam_tis=1
+			AC_DEFINE(PAM_TIS)
+			PAM_TIS_MSG="yes"
+		fi
+	]
+)
+
 # The big search for OpenSSL
 AC_ARG_WITH(ssl-dir,
 	[  --with-ssl-dir=PATH     Specify path to OpenSSL installation ],
@@ -1365,6 +1377,7 @@
 echo "            KerberosIV support: $KRB4_MSG"
 echo "                   AFS support: $AFS_MSG"
 echo "                 S/KEY support: $SKEY_MSG"
+echo "           TIS via PAM support: $PAM_TIS_MSG"
 echo "          TCP Wrappers support: $TCPW_MSG"
 echo "          MD5 password support: $MD5_MSG"
 echo "   IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
diff -urN -x *~ openssh-2.1.1p4/debian/rules openssh-2.1.1p4-hein/debian/rules
--- openssh-2.1.1p4/debian/rules	Sun Aug 27 15:42:21 2000
+++ openssh-2.1.1p4-hein/debian/rules	Sun Aug 27 17:39:02 2000
@@ -14,8 +14,8 @@
 build: build-stamp
 build-stamp:
 	dh_testdir
-	./configure --prefix='' --exec_prefix='$${prefix}/usr' --sysconfdir='$${prefix}/etc/ssh' --libexecdir='$${exec_prefix}/lib' --mandir='$${prefix}/usr/share/man' --with-tcp-wrappers --with-xauth=/usr/bin/X11/xauth --with-rsh=/usr/bin/netkit-rsh
-	$(MAKE) OPT_FLAGS='-DLOGIN_PROGRAM=\"/bin/login\" -DSSHD_PAM_SERVICE=\"ssh\" -DFORWARD_AGENT_DEFAULT=0 -DFALLBACKTORSH_DEFAULT=0' ASKPASS_PROGRAM='/usr/bin/ssh-askpass'
+	./configure --prefix='' --exec_prefix='$${prefix}/usr' --sysconfdir='$${prefix}/etc/ssh' --libexecdir='$${exec_prefix}/lib' --mandir='$${prefix}/usr/share/man' --with-tcp-wrappers --with-xauth=/usr/bin/X11/xauth --with-rsh=/usr/bin/netkit-rsh --with-pam-tis
+	$(MAKE) OPT_FLAGS='-DLOGIN_PROGRAM=\"/bin/login\" -DSSHD_PAM_SERVICE=\"ssh\" -DSSHD_PAM_TIS_SERVICE=\"ssh-tis\" -DFORWARD_AGENT_DEFAULT=0 -DFALLBACKTORSH_DEFAULT=0' ASKPASS_PROGRAM='/usr/bin/ssh-askpass'
 	gcc -O2 `gnome-config --cflags gnome gnomeui` \
 	   contrib/gnome-ssh-askpass.c -o contrib/gnome-ssh-askpass \
 	   `gnome-config --libs gnome gnomeui`
diff -urN -x *~ openssh-2.1.1p4/servconf.c openssh-2.1.1p4-hein/servconf.c
--- openssh-2.1.1p4/servconf.c	Sun Aug 27 15:42:20 2000
+++ openssh-2.1.1p4-hein/servconf.c	Sun Aug 27 12:36:00 2000
@@ -67,6 +67,9 @@
 #ifdef SKEY
 	options->skey_authentication = -1;
 #endif
+#ifdef PAM_TIS
+	options->tis_authentication = -1;
+#endif
 	options->permit_empty_passwd = -1;
 	options->use_login = -1;
 	options->num_allow_users = 0;
@@ -155,6 +158,10 @@
 	if (options->skey_authentication == -1)
 		options->skey_authentication = 1;
 #endif
+#ifdef PAM_TIS
+	if (options->tis_authentication == -1)
+		options->tis_authentication = 1;
+#endif
 	if (options->permit_empty_passwd == -1)
 		options->permit_empty_passwd = 0;
 	if (options->use_login == -1)
@@ -182,6 +189,9 @@
 #ifdef SKEY
 	sSkeyAuthentication,
 #endif
+#ifdef PAM_TIS
+	sTISAuthentication,
+#endif
 	sPasswordAuthentication, sListenAddress,
 	sPrintMotd, sPrintLastLog, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
 	sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
@@ -222,6 +232,9 @@
 #ifdef SKEY
 	{ "skeyauthentication", sSkeyAuthentication },
 #endif
+#ifdef PAM_TIS
+	{ "tisauthentication", sTISAuthentication },
+#endif
 	{ "checkmail", sCheckMail },
 	{ "listenaddress", sListenAddress },
 	{ "printmotd", sPrintMotd },
@@ -504,6 +517,12 @@
 #ifdef SKEY
 		case sSkeyAuthentication:
 			intptr = &options->skey_authentication;
+			goto parse_flag;
+#endif
+
+#ifdef PAM_TIS
+		case sTISAuthentication:
+			intptr = &options->tis_authentication;
 			goto parse_flag;
 #endif
 
diff -urN -x *~ openssh-2.1.1p4/servconf.h openssh-2.1.1p4-hein/servconf.h
--- openssh-2.1.1p4/servconf.h	Sun Aug 27 15:42:20 2000
+++ openssh-2.1.1p4-hein/servconf.h	Sun Aug 27 12:34:52 2000
@@ -85,6 +85,10 @@
 	int     skey_authentication;	/* If true, permit s/key
 					 * authentication. */
 #endif
+#ifdef PAM_TIS
+	int     tis_authentication;	/* If true, permit TIS via PAM
+					 * authentication. */
+#endif
 	int     permit_empty_passwd;	/* If false, do not permit empty
 					 * passwords. */
 	int     use_login;	/* If true, login(1) is used */
diff -urN -x *~ openssh-2.1.1p4/ssh.h openssh-2.1.1p4-hein/ssh.h
--- openssh-2.1.1p4/ssh.h	Sun Aug 27 15:42:20 2000
+++ openssh-2.1.1p4-hein/ssh.h	Sun Aug 27 17:36:02 2000
@@ -80,6 +80,10 @@
 #define SSHD_PAM_SERVICE       "sshd"
 #endif
 
+#if defined(PAM_TIS) && ! defined(SSHD_PAM_TIS_SERVICE)
+#define SSHD_PAM_TIS_SERVICE       "sshd-tis"
+#endif
+
 #ifndef ETCDIR
 #define ETCDIR			"/etc"
 #endif /* ETCDIR */
diff -urN -x *~ openssh-2.1.1p4/sshd.c openssh-2.1.1p4-hein/sshd.c
--- openssh-2.1.1p4/sshd.c	Wed Jul 12 01:45:27 2000
+++ openssh-2.1.1p4-hein/sshd.c	Sun Aug 27 15:39:50 2000
@@ -1097,6 +1097,10 @@
 	if (options.skey_authentication == 1)
 		auth_mask |= 1 << SSH_AUTH_TIS;
 #endif
+#ifdef PAM_TIS
+	if (options.tis_authentication == 1)
+		auth_mask |= 1 << SSH_AUTH_TIS;
+#endif
 	if (options.password_authentication)
 		auth_mask |= 1 << SSH_AUTH_PASSWORD;
 	packet_put_int(auth_mask);







More information about the openssh-unix-dev mailing list