diff -up openssh-5.9p1/auth.h.2auth openssh-5.9p1/auth.h --- openssh-5.9p1/auth.h.2auth 2011-05-29 13:39:38.000000000 +0200 +++ openssh-5.9p1/auth.h 2011-09-13 20:25:22.250474950 +0200 @@ -149,6 +149,8 @@ int auth_root_allowed(char *); char *auth2_read_banner(void); +void userauth_restart(const char *); + void privsep_challenge_enable(void); int auth2_challenge(Authctxt *, char *); diff -up openssh-5.9p1/auth2.c.2auth openssh-5.9p1/auth2.c --- openssh-5.9p1/auth2.c.2auth 2011-05-05 06:04:11.000000000 +0200 +++ openssh-5.9p1/auth2.c 2011-09-13 20:25:22.348458588 +0200 @@ -290,6 +290,23 @@ input_userauth_request(int type, u_int32 } void +userauth_restart(const char *method) +{ + options.two_factor_authentication = 0; + + options.pubkey_authentication = options.second_pubkey_authentication && strcmp(method, method_pubkey.name); +#ifdef GSSAPI + options.gss_authentication = options.second_gss_authentication && strcmp(method, method_gssapi.name); +#endif +#ifdef JPAKE + options.zero_knowledge_password_authentication = options.second_zero_knowledge_password_authentication && strcmp(method, method_jpake.name); +#endif + options.password_authentication = options.second_password_authentication && strcmp(method, method_passwd.name); + options.kbd_interactive_authentication = options.second_kbd_interactive_authentication && strcmp(method, method_kbdint.name); + options.hostbased_authentication = options.second_hostbased_authentication && strcmp(method, method_hostbased.name); +} + +void userauth_finish(Authctxt *authctxt, int authenticated, char *method) { char *methods; @@ -337,6 +354,15 @@ userauth_finish(Authctxt *authctxt, int /* XXX todo: check if multiple auth methods are needed */ if (authenticated == 1) { + if (options.two_factor_authentication) { + userauth_restart(method); + if (use_privsep) + PRIVSEP(userauth_restart(method)); + + debug("1st factor authentication done go to 2nd factor"); + goto ask_methods; + } + /* turn off userauth */ dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); packet_start(SSH2_MSG_USERAUTH_SUCCESS); @@ -356,6 +382,7 @@ userauth_finish(Authctxt *authctxt, int #endif packet_disconnect(AUTH_FAIL_MSG, authctxt->user); } +ask_methods: methods = authmethods_get(); packet_start(SSH2_MSG_USERAUTH_FAILURE); packet_put_cstring(methods); diff -up openssh-5.9p1/monitor.c.2auth openssh-5.9p1/monitor.c --- openssh-5.9p1/monitor.c.2auth 2011-09-13 20:25:18.031458843 +0200 +++ openssh-5.9p1/monitor.c 2011-09-13 20:53:29.345644462 +0200 @@ -165,6 +165,7 @@ int mm_answer_jpake_step1(int, Buffer *) int mm_answer_jpake_step2(int, Buffer *); int mm_answer_jpake_key_confirm(int, Buffer *); int mm_answer_jpake_check_confirm(int, Buffer *); +int mm_answer_userauth_restart(int, Buffer *); #ifdef USE_PAM int mm_answer_pam_start(int, Buffer *); @@ -259,6 +260,7 @@ struct mon_table mon_dispatch_proto20[] {MONITOR_REQ_JPAKE_KEY_CONFIRM, MON_ONCE, mm_answer_jpake_key_confirm}, {MONITOR_REQ_JPAKE_CHECK_CONFIRM, MON_AUTH, mm_answer_jpake_check_confirm}, #endif + {MONITOR_REQ_USERAUTH_RESTART, MON_PERMIT, mm_answer_userauth_restart}, {0, 0, NULL} }; @@ -378,7 +380,7 @@ monitor_child_preauth(Authctxt *_authctx } /* The first few requests do not require asynchronous access */ - while (!authenticated) { + while (!authenticated || options.two_factor_authentication) { auth_method = "unknown"; authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1); if (authenticated) { @@ -390,7 +392,7 @@ monitor_child_preauth(Authctxt *_authctx authenticated = 0; #ifdef USE_PAM /* PAM needs to perform account checks after auth */ - if (options.use_pam && authenticated) { + if (options.use_pam && authenticated && !options.two_factor_authentication) { Buffer m; buffer_init(&m); @@ -2001,6 +2003,24 @@ monitor_reinit(struct monitor *mon) monitor_openfds(mon, 0); } +int +mm_answer_userauth_restart(int sock, Buffer *m) +{ + char *method; + u_int method_len; + + method = buffer_get_string(m, &method_len); + + userauth_restart(method); + + xfree(method); + buffer_clear(m); + + mm_request_send(sock, MONITOR_ANS_USERAUTH_RESTART, m); + + return (0); +} + #ifdef GSSAPI int mm_answer_gss_setup_ctx(int sock, Buffer *m) diff -up openssh-5.9p1/monitor.h.2auth openssh-5.9p1/monitor.h --- openssh-5.9p1/monitor.h.2auth 2011-06-20 06:42:23.000000000 +0200 +++ openssh-5.9p1/monitor.h 2011-09-13 20:25:22.615458574 +0200 @@ -66,6 +66,7 @@ enum monitor_reqtype { MONITOR_REQ_JPAKE_STEP2, MONITOR_ANS_JPAKE_STEP2, MONITOR_REQ_JPAKE_KEY_CONFIRM, MONITOR_ANS_JPAKE_KEY_CONFIRM, MONITOR_REQ_JPAKE_CHECK_CONFIRM, MONITOR_ANS_JPAKE_CHECK_CONFIRM, + MONITOR_REQ_USERAUTH_RESTART, MONITOR_ANS_USERAUTH_RESTART, }; struct mm_master; diff -up openssh-5.9p1/monitor_wrap.c.2auth openssh-5.9p1/monitor_wrap.c --- openssh-5.9p1/monitor_wrap.c.2auth 2011-06-20 06:42:23.000000000 +0200 +++ openssh-5.9p1/monitor_wrap.c 2011-09-13 20:25:22.735468462 +0200 @@ -1173,6 +1173,26 @@ mm_auth_rsa_verify_response(Key *key, BI return (success); } +void +mm_userauth_restart(const char *monitor) +{ + Buffer m; + + debug3("%s entering", __func__); + + buffer_init(&m); + + buffer_put_cstring(&m, monitor); + + mm_request_send(pmonitor->m_recvfd, + MONITOR_REQ_USERAUTH_RESTART, &m); + debug3("%s: waiting for MONITOR_ANS_USERAUTH_RESTART", __func__); + mm_request_receive_expect(pmonitor->m_recvfd, + MONITOR_ANS_USERAUTH_RESTART, &m); + + buffer_free(&m); +} + #ifdef SSH_AUDIT_EVENTS void mm_audit_event(ssh_audit_event_t event) diff -up openssh-5.9p1/monitor_wrap.h.2auth openssh-5.9p1/monitor_wrap.h --- openssh-5.9p1/monitor_wrap.h.2auth 2011-06-20 06:42:23.000000000 +0200 +++ openssh-5.9p1/monitor_wrap.h 2011-09-13 20:25:22.847457505 +0200 @@ -53,6 +53,7 @@ int mm_key_verify(Key *, u_char *, u_int int mm_auth_rsa_key_allowed(struct passwd *, BIGNUM *, Key **); int mm_auth_rsa_verify_response(Key *, BIGNUM *, u_char *); BIGNUM *mm_auth_rsa_generate_challenge(Key *); +void mm_userauth_restart(const char *); #ifdef GSSAPI OM_uint32 mm_ssh_gssapi_server_ctx(Gssctxt **, gss_OID); diff -up openssh-5.9p1/servconf.c.2auth openssh-5.9p1/servconf.c --- openssh-5.9p1/servconf.c.2auth 2011-09-13 20:25:18.836495701 +0200 +++ openssh-5.9p1/servconf.c 2011-09-13 20:25:22.994584169 +0200 @@ -92,6 +92,13 @@ initialize_server_options(ServerOptions options->hostbased_uses_name_from_packet_only = -1; options->rsa_authentication = -1; options->pubkey_authentication = -1; + options->two_factor_authentication = -1; + options->second_pubkey_authentication = -1; + options->second_gss_authentication = -1; + options->second_password_authentication = -1; + options->second_kbd_interactive_authentication = -1; + options->second_zero_knowledge_password_authentication = -1; + options->second_hostbased_authentication = -1; options->kerberos_authentication = -1; options->kerberos_or_local_passwd = -1; options->kerberos_ticket_cleanup = -1; @@ -237,6 +244,20 @@ fill_default_server_options(ServerOption options->permit_empty_passwd = 0; if (options->permit_user_env == -1) options->permit_user_env = 0; + if (options->two_factor_authentication == -1) + options->two_factor_authentication = 0; + if (options->second_pubkey_authentication == -1) + options->second_pubkey_authentication = 1; + if (options->second_gss_authentication == -1) + options->second_gss_authentication = 0; + if (options->second_password_authentication == -1) + options->second_password_authentication = 1; + if (options->second_kbd_interactive_authentication == -1) + options->second_kbd_interactive_authentication = 0; + if (options->second_zero_knowledge_password_authentication == -1) + options->second_zero_knowledge_password_authentication = 0; + if (options->second_hostbased_authentication == -1) + options->second_hostbased_authentication = 0; if (options->use_login == -1) options->use_login = 0; if (options->compression == -1) @@ -316,8 +337,11 @@ typedef enum { sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, sMaxStartups, sMaxAuthTries, sMaxSessions, sBanner, sUseDNS, sHostbasedAuthentication, - sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, - sClientAliveCountMax, sAuthorizedKeysFile, + sHostbasedUsesNameFromPacketOnly, sTwoFactorAuthentication, + sSecondPubkeyAuthentication, sSecondGssAuthentication, + sSecondPasswordAuthentication, sSecondKbdInteractiveAuthentication, + sSecondZeroKnowledgePasswordAuthentication, sSecondHostbasedAuthentication, + sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile, sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel, sMatch, sPermitOpen, sForceCommand, sChrootDirectory, sUsePrivilegeSeparation, sAllowAgentForwarding, @@ -395,6 +419,21 @@ static struct { #else { "zeroknowledgepasswordauthentication", sUnsupported, SSHCFG_ALL }, #endif + { "twofactorauthentication", sTwoFactorAuthentication, SSHCFG_ALL }, + { "secondpubkeyauthentication", sSecondPubkeyAuthentication, SSHCFG_ALL }, +#ifdef GSSAPI + { "secondgssapiauthentication", sSecondGssAuthentication, SSHCFG_ALL }, +#else + { "secondgssapiauthentication", sUnsupported, SSHCFG_ALL }, +#endif + { "secondpasswordauthentication", sSecondPasswordAuthentication, SSHCFG_ALL }, + { "secondkbdinteractiveauthentication", sSecondKbdInteractiveAuthentication, SSHCFG_ALL }, +#ifdef JPAKE + { "secondzeroknowledgepasswordauthentication", sSecondZeroKnowledgePasswordAuthentication, SSHCFG_ALL }, +#else + { "secondzeroknowledgepasswordauthentication", sUnsupported, SSHCFG_ALL }, +#endif + { "secondhostbasedauthentication", sSecondHostbasedAuthentication, SSHCFG_ALL }, { "checkmail", sDeprecated, SSHCFG_GLOBAL }, { "listenaddress", sListenAddress, SSHCFG_GLOBAL }, { "addressfamily", sAddressFamily, SSHCFG_GLOBAL }, @@ -982,6 +1021,34 @@ process_server_config_line(ServerOptions intptr = &options->challenge_response_authentication; goto parse_flag; + case sTwoFactorAuthentication: + intptr = &options->two_factor_authentication; + goto parse_flag; + + case sSecondPubkeyAuthentication: + intptr = &options->second_pubkey_authentication; + goto parse_flag; + + case sSecondGssAuthentication: + intptr = &options->second_gss_authentication; + goto parse_flag; + + case sSecondPasswordAuthentication: + intptr = &options->second_password_authentication; + goto parse_flag; + + case sSecondKbdInteractiveAuthentication: + intptr = &options->second_kbd_interactive_authentication; + goto parse_flag; + + case sSecondZeroKnowledgePasswordAuthentication: + intptr = &options->second_zero_knowledge_password_authentication; + goto parse_flag; + + case sSecondHostbasedAuthentication: + intptr = &options->second_hostbased_authentication; + goto parse_flag; + case sPrintMotd: intptr = &options->print_motd; goto parse_flag; @@ -1491,14 +1558,21 @@ void copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) { M_CP_INTOPT(password_authentication); + M_CP_INTOPT(second_password_authentication); M_CP_INTOPT(gss_authentication); + M_CP_INTOPT(second_gss_authentication); M_CP_INTOPT(rsa_authentication); M_CP_INTOPT(pubkey_authentication); + M_CP_INTOPT(second_pubkey_authentication); M_CP_INTOPT(kerberos_authentication); M_CP_INTOPT(hostbased_authentication); + M_CP_INTOPT(second_hostbased_authentication); M_CP_INTOPT(hostbased_uses_name_from_packet_only); M_CP_INTOPT(kbd_interactive_authentication); + M_CP_INTOPT(second_kbd_interactive_authentication); M_CP_INTOPT(zero_knowledge_password_authentication); + M_CP_INTOPT(second_zero_knowledge_password_authentication); + M_CP_INTOPT(two_factor_authentication); M_CP_INTOPT(permit_root_login); M_CP_INTOPT(permit_empty_passwd); @@ -1720,17 +1794,24 @@ dump_config(ServerOptions *o) #endif #ifdef GSSAPI dump_cfg_fmtint(sGssAuthentication, o->gss_authentication); + dump_cfg_fmtint(sSecondGssAuthentication, o->second_gss_authentication); dump_cfg_fmtint(sGssCleanupCreds, o->gss_cleanup_creds); #endif #ifdef JPAKE dump_cfg_fmtint(sZeroKnowledgePasswordAuthentication, o->zero_knowledge_password_authentication); + dump_cfg_fmtint(sSecondZeroKnowledgePasswordAuthentication, + o->second_zero_knowledge_password_authentication); #endif dump_cfg_fmtint(sPasswordAuthentication, o->password_authentication); + dump_cfg_fmtint(sSecondPasswordAuthentication, o->second_password_authentication); dump_cfg_fmtint(sKbdInteractiveAuthentication, o->kbd_interactive_authentication); + dump_cfg_fmtint(sSecondKbdInteractiveAuthentication, + o->second_kbd_interactive_authentication); dump_cfg_fmtint(sChallengeResponseAuthentication, o->challenge_response_authentication); + dump_cfg_fmtint(sTwoFactorAuthentication, o->two_factor_authentication); dump_cfg_fmtint(sPrintMotd, o->print_motd); dump_cfg_fmtint(sPrintLastLog, o->print_lastlog); dump_cfg_fmtint(sX11Forwarding, o->x11_forwarding); diff -up openssh-5.9p1/servconf.h.2auth openssh-5.9p1/servconf.h --- openssh-5.9p1/servconf.h.2auth 2011-06-23 00:30:03.000000000 +0200 +++ openssh-5.9p1/servconf.h 2011-09-13 20:25:23.103459846 +0200 @@ -112,6 +112,14 @@ typedef struct { /* If true, permit jpake auth */ int permit_empty_passwd; /* If false, do not permit empty * passwords. */ + int two_factor_authentication; /* If true, the first sucessful authentication + * will be followed by the second one from anorher set */ + int second_pubkey_authentication; /* second set of authentications */ + int second_gss_authentication; + int second_password_authentication; + int second_kbd_interactive_authentication; + int second_zero_knowledge_password_authentication; + int second_hostbased_authentication; int permit_user_env; /* If true, read ~/.ssh/environment */ int use_login; /* If true, login(1) is used */ int compression; /* If true, compression is allowed */ diff -up openssh-5.9p1/sshd_config.2auth openssh-5.9p1/sshd_config --- openssh-5.9p1/sshd_config.2auth 2011-05-29 13:39:39.000000000 +0200 +++ openssh-5.9p1/sshd_config 2011-09-13 20:25:23.221458447 +0200 @@ -87,6 +87,13 @@ AuthorizedKeysFile .ssh/authorized_keys # and ChallengeResponseAuthentication to 'no'. #UsePAM no +#TwoFactorAuthentication no +#SecondPubkeyAuthentication yes +#SecondHostbasedAuthentication no +#SecondPasswordAuthentication yes +#SecondChallengeResponseAuthentication yes +#SecondGSSAPIAuthentication no + #AllowAgentForwarding yes #AllowTcpForwarding yes #GatewayPorts no diff -up openssh-5.9p1/sshd_config.5.2auth openssh-5.9p1/sshd_config.5 --- openssh-5.9p1/sshd_config.5.2auth 2011-08-05 22:17:33.000000000 +0200 +++ openssh-5.9p1/sshd_config.5 2011-09-13 20:25:23.416458539 +0200 @@ -726,6 +726,12 @@ Available keywords are .Cm PubkeyAuthentication , .Cm RhostsRSAAuthentication , .Cm RSAAuthentication , +.Cm SecondGSSAPIAuthentication , +.Cm SecondHostbasedAuthentication , +.Cm SecondKbdInteractiveAuthentication , +.Cm SecondPasswordAuthentication , +.Cm SecondPubkeyAuthentication , +.Cm TwoFactorAuthentication , .Cm X11DisplayOffset , .Cm X11Forwarding and @@ -931,6 +937,41 @@ Specifies whether pure RSA authenticatio The default is .Dq yes . This option applies to protocol version 1 only. +.It Cm SecondGSSAPIAuthentication +Specifies whether the +.Cm GSSAPIAuthentication +may be used on the second authentication while +.Cm TwoFactorAuthentication +is set. +The argument must be “yes” or “no”. The default is “no”. +.It Cm SecondHostbasedAuthentication +Specifies whether the +.Cm HostbasedAuthentication +may be used on the second authentication while +.Cm TwoFactorAuthentication +is set. +The argument must be “yes” or “no”. The default is “no”. +.It Cm SecondKbdInteractiveAuthentication +Specifies whether the +.Cm KbdInteractiveAuthentication +may be used on the second authentication while +.Cm TwoFactorAuthentication +is set. +The argument must be “yes” or “no”. The default is “no”. +.It Cm SecondPasswordAuthentication +Specifies whether the +.Cm PasswordAuthentication +may be used on the second authentication while +.Cm TwoFactorAuthentication +is set. +The argument must be “yes” or “no”. The default is “yes”. +.It Cm SecondPubkeyAuthentication +Specifies whether the +.Cm PubkeyAuthentication +may be used on the second authentication while +.Cm TwoFactorAuthentication +is set. +The argument must be “yes” or “no”. The default is “yes”. .It Cm ServerKeyBits Defines the number of bits in the ephemeral protocol version 1 server key. The minimum value is 512, and the default is 1024. @@ -1011,6 +1052,22 @@ For more details on certificates, see th .Sx CERTIFICATES section in .Xr ssh-keygen 1 . +.It Cm TwoFactorAuthentication +Specifies whether for a successful login is necessary to meet two independent authentications. +If select the first method is selected from the set of allowed methods from +.Cm GSSAPIAuthentication , +.Cm HostbasedAuthentication , +.Cm KbdInteractiveAuthentication , +.Cm PasswordAuthentication , +.Cm PubkeyAuthentication . +And the second method is selected from the set of allowed methods from +.Cm SecondGSSAPIAuthentication , +.Cm SecondHostbasedAuthentication , +.Cm SecondKbdInteractiveAuthentication , +.Cm SecondPasswordAuthentication , +.Cm SecondPubkeyAuthentication +without the method used for the first authentication. +The argument must be “yes” or “no”. The default is “no”. .It Cm UseDNS Specifies whether .Xr sshd 8