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);