Blob Blame History Raw
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