vishalmishra434 / rpms / openssh

Forked from rpms/openssh a month ago
Clone
Petr Lautrbach d9e618
diff -up openssh-5.9p1/auth.c.required-authentication openssh-5.9p1/auth.c
Petr Lautrbach 420ff0
--- openssh-5.9p1/auth.c.required-authentication	2012-07-27 12:21:41.181601972 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/auth.c	2012-07-27 12:21:41.203602020 +0200
Petr Lautrbach d9e618
@@ -251,7 +251,8 @@ allowed_user(struct passwd * pw)
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 void
Petr Lautrbach d9e618
-auth_log(Authctxt *authctxt, int authenticated, char *method, char *info)
Petr Lautrbach d9e618
+auth_log(Authctxt *authctxt, int authenticated, const char *method,
Petr Lautrbach d9e618
+    const char *submethod, const char *info)
Petr Lautrbach d9e618
 {
Petr Lautrbach d9e618
 	void (*authlog) (const char *fmt,...) = verbose;
Petr Lautrbach d9e618
 	char *authmsg;
Petr Lautrbach d9e618
@@ -271,9 +272,10 @@ auth_log(Authctxt *authctxt, int authent
Petr Lautrbach d9e618
 	else
Petr Lautrbach d9e618
 		authmsg = authenticated ? "Accepted" : "Failed";
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
-	authlog("%s %s for %s%.100s from %.200s port %d%s",
Petr Lautrbach d9e618
+	authlog("%s %s%s%s for %s%.100s from %.200s port %d%s",
Petr Lautrbach d9e618
 	    authmsg,
Petr Lautrbach d9e618
 	    method,
Petr Lautrbach d9e618
+	    submethod == NULL ? "" : "/", submethod == NULL ? "" : submethod,
Petr Lautrbach d9e618
 	    authctxt->valid ? "" : "invalid user ",
Petr Lautrbach d9e618
 	    authctxt->user,
Petr Lautrbach d9e618
 	    get_remote_ipaddr(),
Petr Lautrbach d9e618
@@ -303,7 +305,7 @@ auth_log(Authctxt *authctxt, int authent
Petr Lautrbach d9e618
  * Check whether root logins are disallowed.
Petr Lautrbach d9e618
  */
Petr Lautrbach d9e618
 int
Petr Lautrbach d9e618
-auth_root_allowed(char *method)
Petr Lautrbach d9e618
+auth_root_allowed(const char *method)
Petr Lautrbach d9e618
 {
Petr Lautrbach d9e618
 	switch (options.permit_root_login) {
Petr Lautrbach d9e618
 	case PERMIT_YES:
Petr Lautrbach d9e618
@@ -694,3 +696,57 @@ fakepw(void)
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	return (&fake);
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+int
Petr Lautrbach d9e618
+auth_method_in_list(const char *list, const char *method)
Petr Lautrbach d9e618
+{
Petr Lautrbach d9e618
+	char *cp;
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	cp = match_list(method, list, NULL);
Petr Lautrbach d9e618
+	if (cp != NULL) {
Petr Lautrbach d9e618
+		xfree(cp);
Petr Lautrbach d9e618
+		return 1;
Petr Lautrbach d9e618
+	}
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	return 0;
Petr Lautrbach d9e618
+}
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+#define	DELIM	","
Petr Lautrbach d9e618
+int
Petr Lautrbach d9e618
+auth_remove_from_list(char **list, const char *method)
Petr Lautrbach d9e618
+{
Petr Lautrbach d9e618
+	char *oldlist, *cp, *newlist = NULL;
Petr Lautrbach d9e618
+	u_int len = 0, ret = 0;
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	if (list == NULL || *list == NULL)
Petr Lautrbach d9e618
+		return (0);
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	oldlist = *list;
Petr Lautrbach d9e618
+	len = strlen(oldlist) + 1;
Petr Lautrbach d9e618
+	newlist = xmalloc(len);
Petr Lautrbach d9e618
+	memset(newlist, '\0', len);
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	/* Remove method from list, if present */
Petr Lautrbach d9e618
+	for (;;) {
Petr Lautrbach d9e618
+		if ((cp = strsep(&oldlist, DELIM)) == NULL)
Petr Lautrbach d9e618
+			break;
Petr Lautrbach d9e618
+		if (*cp == '\0')
Petr Lautrbach d9e618
+			continue;
Petr Lautrbach d9e618
+		if (strcmp(cp, method) != 0) {
Petr Lautrbach d9e618
+			if (*newlist != '\0')
Petr Lautrbach d9e618
+				strlcat(newlist, DELIM, len);
Petr Lautrbach d9e618
+			strlcat(newlist, cp, len);
Petr Lautrbach d9e618
+		} else
Petr Lautrbach d9e618
+			ret++;
Petr Lautrbach d9e618
+	}
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	/* Return NULL instead of empty list */
Petr Lautrbach d9e618
+	if (*newlist == '\0') {
Petr Lautrbach d9e618
+		xfree(newlist);
Petr Lautrbach d9e618
+		newlist = NULL;
Petr Lautrbach d9e618
+	}
Petr Lautrbach d9e618
+	xfree(*list);
Petr Lautrbach d9e618
+	*list = newlist;
Petr Lautrbach d9e618
+	
Petr Lautrbach d9e618
+	return (ret);
Petr Lautrbach d9e618
+}
Petr Lautrbach d9e618
diff -up openssh-5.9p1/auth.h.required-authentication openssh-5.9p1/auth.h
Petr Lautrbach d9e618
--- openssh-5.9p1/auth.h.required-authentication	2011-05-29 13:39:38.000000000 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/auth.h	2012-07-27 12:21:41.204602022 +0200
Petr Lautrbach d9e618
@@ -142,10 +142,11 @@ void disable_forwarding(void);
Petr Lautrbach d9e618
 void	do_authentication(Authctxt *);
Petr Lautrbach d9e618
 void	do_authentication2(Authctxt *);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
-void	auth_log(Authctxt *, int, char *, char *);
Petr Lautrbach d9e618
-void	userauth_finish(Authctxt *, int, char *);
Petr Lautrbach d9e618
+void	auth_log(Authctxt *, int, const char *, const char *, const char *);
Petr Lautrbach d9e618
+void	userauth_finish(Authctxt *, int, const char *, const char *);
Petr Lautrbach d9e618
+int	auth_root_allowed(const char *);
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
 void	userauth_send_banner(const char *);
Petr Lautrbach d9e618
-int	auth_root_allowed(char *);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 char	*auth2_read_banner(void);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
@@ -192,6 +193,11 @@ void	 auth_debug_send(void);
Petr Lautrbach d9e618
 void	 auth_debug_reset(void);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 struct passwd *fakepw(void);
Petr Lautrbach d9e618
+int	 auth_method_in_list(const char *, const char *);
Petr Lautrbach d9e618
+int	 auth_remove_from_list(char **, const char *);
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+int	 auth1_check_required(const char *);
Petr Lautrbach d9e618
+int	 auth2_check_required(const char *);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 int	 sys_auth_passwd(Authctxt *, const char *);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
diff -up openssh-5.9p1/auth1.c.required-authentication openssh-5.9p1/auth1.c
Petr Lautrbach d9e618
--- openssh-5.9p1/auth1.c.required-authentication	2010-08-31 14:36:39.000000000 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/auth1.c	2012-07-27 12:50:50.708706675 +0200
Petr Lautrbach 420ff0
@@ -98,6 +98,55 @@ static const struct AuthMethod1
Petr Lautrbach d9e618
 	return (NULL);
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
+static const struct AuthMethod1 *
Petr Lautrbach d9e618
+lookup_authmethod1_by_name(const char *name)
Petr Lautrbach d9e618
+{
Petr Lautrbach d9e618
+	int i;
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	for (i = 0; auth1_methods[i].name != NULL; i++)
Petr Lautrbach d9e618
+		if (strcmp(auth1_methods[i].name, name) == 0)
Petr Lautrbach d9e618
+			return (&(auth1_methods[i]));
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	return NULL;
Petr Lautrbach d9e618
+}
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+#define	DELIM	","
Petr Lautrbach d9e618
+int
Petr Lautrbach d9e618
+auth1_check_required(const char *list)
Petr Lautrbach d9e618
+{
Petr Lautrbach d9e618
+	char *orig_methods, *methods, *cp;
Petr Lautrbach d9e618
+	static const struct AuthMethod1 *m;
Petr Lautrbach d9e618
+	int ret = 0;
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	orig_methods = methods = xstrdup(list);
Petr Lautrbach d9e618
+	for(;;) { /* XXX maybe: while ((cp = ...) != NULL) ? */
Petr Lautrbach d9e618
+		if ((cp = strsep(&methods, DELIM)) == NULL)
Petr Lautrbach d9e618
+			break;
Petr Lautrbach d9e618
+		debug2("auth1_check_required: method \"%s\"", cp);
Petr Lautrbach d9e618
+		if (*cp == '\0') {
Petr Lautrbach d9e618
+			debug("auth1_check_required: empty method");
Petr Lautrbach d9e618
+			ret = -1;
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
+		if ((m = lookup_authmethod1_by_name(cp)) == NULL) {
Petr Lautrbach d9e618
+			debug("auth1_check_required: unknown method "
Petr Lautrbach d9e618
+			    "\"%s\"", cp);
Petr Lautrbach d9e618
+			ret = -1;
Petr Lautrbach 420ff0
+			break;
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
+		if (*(m->enabled) == 0) {
Petr Lautrbach d9e618
+			debug("auth1_check_required: method %s explicitly "
Petr Lautrbach d9e618
+			    "disabled", cp);
Petr Lautrbach d9e618
+			ret = -1;
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
+		/* Activate method if it isn't already */
Petr Lautrbach d9e618
+		if (*(m->enabled) == -1)
Petr Lautrbach d9e618
+			*(m->enabled) = 1;
Petr Lautrbach d9e618
+        }
Petr Lautrbach d9e618
+	xfree(orig_methods);
Petr Lautrbach d9e618
+	return (ret);
Petr Lautrbach d9e618
+}
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
 static char *
Petr Lautrbach d9e618
 get_authname(int type)
Petr Lautrbach d9e618
 {
Petr Lautrbach 420ff0
@@ -237,6 +286,7 @@ do_authloop(Authctxt *authctxt)
Petr Lautrbach d9e618
 {
Petr Lautrbach d9e618
 	int authenticated = 0;
Petr Lautrbach d9e618
 	char info[1024];
Petr Lautrbach d9e618
+	const char *meth_name;
Petr Lautrbach d9e618
 	int prev = 0, type = 0;
Petr Lautrbach d9e618
 	const struct AuthMethod1 *meth;
Petr Lautrbach d9e618
 
Petr Lautrbach 420ff0
@@ -244,7 +294,7 @@ do_authloop(Authctxt *authctxt)
Petr Lautrbach d9e618
 	    authctxt->valid ? "" : "invalid user ", authctxt->user);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	/* If the user has no password, accept authentication immediately. */
Petr Lautrbach d9e618
-	if (options.permit_empty_passwd && options.password_authentication &&
Petr Lautrbach d9e618
+	if (options.permit_empty_passwd && options.password_authentication && options.password_authentication &&
Petr Lautrbach d9e618
 #ifdef KRB5
Petr Lautrbach d9e618
 	    (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
Petr Lautrbach d9e618
 #endif
Petr Lautrbach 420ff0
@@ -253,7 +303,7 @@ do_authloop(Authctxt *authctxt)
Petr Lautrbach d9e618
 		if (options.use_pam && (PRIVSEP(do_pam_account())))
Petr Lautrbach d9e618
 #endif
Petr Lautrbach d9e618
 		{
Petr Lautrbach d9e618
-			auth_log(authctxt, 1, "without authentication", "");
Petr Lautrbach d9e618
+			auth_log(authctxt, 1, "without authentication", NULL, "");
Petr Lautrbach d9e618
 			return;
Petr Lautrbach d9e618
 		}
Petr Lautrbach d9e618
 	}
Petr Lautrbach 420ff0
@@ -272,6 +322,7 @@ do_authloop(Authctxt *authctxt)
Petr Lautrbach d9e618
 		/* Get a packet from the client. */
Petr Lautrbach d9e618
 		prev = type;
Petr Lautrbach d9e618
 		type = packet_read();
Petr Lautrbach d9e618
+		meth_name = get_authname(type);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 		/*
Petr Lautrbach d9e618
 		 * If we started challenge-response authentication but the
Petr Lautrbach 420ff0
@@ -287,8 +338,8 @@ do_authloop(Authctxt *authctxt)
Petr Lautrbach d9e618
 		if (authctxt->failures >= options.max_authtries)
Petr Lautrbach d9e618
 			goto skip;
Petr Lautrbach d9e618
 		if ((meth = lookup_authmethod1(type)) == NULL) {
Petr Lautrbach d9e618
-			logit("Unknown message during authentication: "
Petr Lautrbach d9e618
-			    "type %d", type);
Petr Lautrbach d9e618
+			logit("Unknown message during authentication: type %d",
Petr Lautrbach d9e618
+			    type);
Petr Lautrbach d9e618
 			goto skip;
Petr Lautrbach d9e618
 		}
Petr Lautrbach d9e618
 
Petr Lautrbach 420ff0
@@ -297,6 +348,17 @@ do_authloop(Authctxt *authctxt)
Petr Lautrbach d9e618
 			goto skip;
Petr Lautrbach d9e618
 		}
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
+		/*
Petr Lautrbach d9e618
+		 * Skip methods not in required list, until all the required
Petr Lautrbach d9e618
+		 * ones are done
Petr Lautrbach d9e618
+		 */
Petr Lautrbach d9e618
+		if (options.required_auth1 != NULL &&
Petr Lautrbach d9e618
+		    !auth_method_in_list(options.required_auth1, meth_name)) {
Petr Lautrbach d9e618
+			debug("Skipping method \"%s\" until required "
Petr Lautrbach d9e618
+			    "authentication completed", meth_name);
Petr Lautrbach d9e618
+			goto skip;
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
 		authenticated = meth->method(authctxt, info, sizeof(info));
Petr Lautrbach d9e618
 		if (authenticated == -1)
Petr Lautrbach d9e618
 			continue; /* "postponed" */
Petr Lautrbach 420ff0
@@ -352,7 +414,29 @@ do_authloop(Authctxt *authctxt)
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
  skip:
Petr Lautrbach d9e618
 		/* Log before sending the reply */
Petr Lautrbach d9e618
-		auth_log(authctxt, authenticated, get_authname(type), info);
Petr Lautrbach d9e618
+		auth_log(authctxt, authenticated, meth_name, NULL, info);
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+		/* Loop until the required authmethods are done */
Petr Lautrbach d9e618
+		if (authenticated && options.required_auth1 != NULL) {
Petr Lautrbach d9e618
+			if (auth_remove_from_list(&options.required_auth1,
Petr Lautrbach 420ff0
+			    meth_name) == 0)
Petr Lautrbach d9e618
+				fatal("INTERNAL ERROR: authenticated method "
Petr Lautrbach d9e618
+				    "\"%s\" not in required list \"%s\"",
Petr Lautrbach d9e618
+				    meth_name, options.required_auth1);
Petr Lautrbach d9e618
+			debug2("do_authloop: required list now: %s",
Petr Lautrbach d9e618
+			    options.required_auth1 == NULL ?
Petr Lautrbach d9e618
+			    "DONE" : options.required_auth1);
Petr Lautrbach d9e618
+			if (options.required_auth1 == NULL)
Petr Lautrbach d9e618
+				return;
Petr Lautrbach d9e618
+			authenticated = 0;
Petr Lautrbach d9e618
+			/*
Petr Lautrbach d9e618
+			 * Disable method so client can't authenticate with it
Petr Lautrbach d9e618
+			 * after the required authentications are complete.
Petr Lautrbach d9e618
+			 */
Petr Lautrbach d9e618
+			*(meth->enabled) = 0;
Petr Lautrbach d9e618
+			packet_send_debug("Further authentication required");
Petr Lautrbach d9e618
+			goto send_fail;
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 		if (client_user != NULL) {
Petr Lautrbach d9e618
 			xfree(client_user);
Petr Lautrbach 420ff0
@@ -368,6 +452,7 @@ do_authloop(Authctxt *authctxt)
Petr Lautrbach d9e618
 #endif
Petr Lautrbach d9e618
 			packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
Petr Lautrbach d9e618
 		}
Petr Lautrbach d9e618
+ send_fail:
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 		packet_start(SSH_SMSG_FAILURE);
Petr Lautrbach d9e618
 		packet_send();
Petr Lautrbach d9e618
diff -up openssh-5.9p1/auth2.c.required-authentication openssh-5.9p1/auth2.c
Petr Lautrbach d9e618
--- openssh-5.9p1/auth2.c.required-authentication	2011-05-05 06:04:11.000000000 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/auth2.c	2012-07-27 12:51:59.048241612 +0200
Petr Lautrbach d9e618
@@ -215,7 +215,7 @@ input_userauth_request(int type, u_int32
Petr Lautrbach d9e618
 {
Petr Lautrbach d9e618
 	Authctxt *authctxt = ctxt;
Petr Lautrbach d9e618
 	Authmethod *m = NULL;
Petr Lautrbach d9e618
-	char *user, *service, *method, *style = NULL;
Petr Lautrbach d9e618
+	char *user, *service, *method, *active_methods, *style = NULL;
Petr Lautrbach d9e618
 	int authenticated = 0;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	if (authctxt == NULL)
Petr Lautrbach d9e618
@@ -277,22 +277,31 @@ input_userauth_request(int type, u_int32
Petr Lautrbach d9e618
 	authctxt->server_caused_failure = 0;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	/* try to authenticate user */
Petr Lautrbach d9e618
-	m = authmethod_lookup(method);
Petr Lautrbach d9e618
-	if (m != NULL && authctxt->failures < options.max_authtries) {
Petr Lautrbach d9e618
-		debug2("input_userauth_request: try method %s", method);
Petr Lautrbach d9e618
-		authenticated =	m->userauth(authctxt);
Petr Lautrbach d9e618
-	}
Petr Lautrbach d9e618
-	userauth_finish(authctxt, authenticated, method);
Petr Lautrbach d9e618
+	active_methods = authmethods_get();
Petr Lautrbach d9e618
+	if (strcmp(method, "none") == 0 || 
Petr Lautrbach d9e618
+	    auth_method_in_list(active_methods, method)) {
Petr Lautrbach d9e618
+		m = authmethod_lookup(method);
Petr Lautrbach d9e618
+		if (m != NULL) {
Petr Lautrbach d9e618
+			debug2("input_userauth_request: try method %s", method);
Petr Lautrbach d9e618
+			authenticated =	m->userauth(authctxt);
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
+	}
Petr Lautrbach d9e618
+	xfree(active_methods);
Petr Lautrbach d9e618
+	userauth_finish(authctxt, authenticated, method, NULL);
Petr Lautrbach d9e618
+ 
Petr Lautrbach d9e618
 	xfree(service);
Petr Lautrbach d9e618
 	xfree(user);
Petr Lautrbach d9e618
 	xfree(method);
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 void
Petr Lautrbach d9e618
-userauth_finish(Authctxt *authctxt, int authenticated, char *method)
Petr Lautrbach d9e618
+userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
Petr Lautrbach d9e618
+    const char *submethod)
Petr Lautrbach d9e618
 {
Petr Lautrbach d9e618
 	char *methods;
Petr Lautrbach d9e618
+	Authmethod *m = NULL;
Petr Lautrbach d9e618
+	u_int partial = 0;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	if (!authctxt->valid && authenticated)
Petr Lautrbach d9e618
 		fatal("INTERNAL ERROR: authenticated invalid user %s",
Petr Lautrbach 420ff0
@@ -330,12 +339,42 @@ userauth_finish(Authctxt *authctxt, int
Petr Lautrbach d9e618
 #endif /* _UNICOS */
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	/* Log before sending the reply */
Petr Lautrbach d9e618
-	auth_log(authctxt, authenticated, method, " ssh2");
Petr Lautrbach d9e618
+	auth_log(authctxt, authenticated, method, submethod, " ssh2");
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	if (authctxt->postponed)
Petr Lautrbach d9e618
 		return;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
-	/* XXX todo: check if multiple auth methods are needed */
Petr Lautrbach d9e618
+	/* Handle RequiredAuthentications2: loop until required methods done */
Petr Lautrbach d9e618
+	if (authenticated && options.required_auth2 != NULL) {
Petr Lautrbach d9e618
+		if ((m = authmethod_lookup(method)) == NULL)
Petr Lautrbach d9e618
+			fatal("INTERNAL ERROR: authenticated method "
Petr Lautrbach d9e618
+			    "\"%s\" unknown", method);
Petr Lautrbach 420ff0
+		if (auth_remove_from_list(&options.required_auth2, method) == 0)
Petr Lautrbach d9e618
+			fatal("INTERNAL ERROR: authenticated method "
Petr Lautrbach d9e618
+			    "\"%s\" not in required list \"%s\"", 
Petr Lautrbach d9e618
+			    method, options.required_auth2);
Petr Lautrbach d9e618
+		debug2("userauth_finish: required list now: %s",
Petr Lautrbach d9e618
+		    options.required_auth2 == NULL ?
Petr Lautrbach d9e618
+		    "DONE" : options.required_auth2);
Petr Lautrbach d9e618
+		/*
Petr Lautrbach d9e618
+		 * if authenticated and no more required methods 
Petr Lautrbach d9e618
+		 * then declare success
Petr Lautrbach d9e618
+		 */
Petr Lautrbach d9e618
+		if ( authenticated && options.required_auth2 == NULL ) {
Petr Lautrbach d9e618
+			debug2("userauth_finish: authenticated and no more required methods");
Petr Lautrbach d9e618
+		} else {
Petr Lautrbach d9e618
+			/*
Petr Lautrbach d9e618
+			 * Disable method so client can't authenticate with it after
Petr Lautrbach d9e618
+			 * the required authentications are complete.
Petr Lautrbach d9e618
+			 */
Petr Lautrbach d9e618
+			if (m->enabled != NULL)
Petr Lautrbach d9e618
+			*(m->enabled) = 0;
Petr Lautrbach d9e618
+			authenticated = 0;
Petr Lautrbach d9e618
+			partial = 1;
Petr Lautrbach d9e618
+			goto send_fail;
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
+	}
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
 	if (authenticated == 1) {
Petr Lautrbach d9e618
 		/* turn off userauth */
Petr Lautrbach d9e618
 		dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
Petr Lautrbach 420ff0
@@ -345,7 +384,6 @@ userauth_finish(Authctxt *authctxt, int
Petr Lautrbach d9e618
 		/* now we can break out */
Petr Lautrbach d9e618
 		authctxt->success = 1;
Petr Lautrbach d9e618
 	} else {
Petr Lautrbach d9e618
-
Petr Lautrbach d9e618
 		/* Allow initial try of "none" auth without failure penalty */
Petr Lautrbach d9e618
 		if (!authctxt->server_caused_failure &&
Petr Lautrbach d9e618
 		    (authctxt->attempt > 1 || strcmp(method, "none") != 0))
Petr Lautrbach 420ff0
@@ -356,10 +394,11 @@ userauth_finish(Authctxt *authctxt, int
Petr Lautrbach d9e618
 #endif
Petr Lautrbach d9e618
 			packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
Petr Lautrbach d9e618
 		}
Petr Lautrbach d9e618
+ send_fail:
Petr Lautrbach d9e618
 		methods = authmethods_get();
Petr Lautrbach d9e618
 		packet_start(SSH2_MSG_USERAUTH_FAILURE);
Petr Lautrbach d9e618
 		packet_put_cstring(methods);
Petr Lautrbach d9e618
-		packet_put_char(0);	/* XXX partial success, unused */
Petr Lautrbach d9e618
+		packet_put_char(partial);
Petr Lautrbach d9e618
 		packet_send();
Petr Lautrbach d9e618
 		packet_write_wait();
Petr Lautrbach d9e618
 		xfree(methods);
Petr Lautrbach d9e618
@@ -373,6 +412,9 @@ authmethods_get(void)
Petr Lautrbach d9e618
 	char *list;
Petr Lautrbach d9e618
 	int i;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
+	if (options.required_auth2 != NULL)
Petr Lautrbach d9e618
+		return xstrdup(options.required_auth2);
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
 	buffer_init(&b);
Petr Lautrbach d9e618
 	for (i = 0; authmethods[i] != NULL; i++) {
Petr Lautrbach d9e618
 		if (strcmp(authmethods[i]->name, "none") == 0)
Petr Lautrbach d9e618
@@ -407,3 +449,43 @@ authmethod_lookup(const char *name)
Petr Lautrbach d9e618
 	return NULL;
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
+#define DELIM ","
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+int
Petr Lautrbach d9e618
+auth2_check_required(const char *list)
Petr Lautrbach d9e618
+{
Petr Lautrbach d9e618
+	char *orig_methods, *methods, *cp;
Petr Lautrbach d9e618
+	struct Authmethod *m;
Petr Lautrbach d9e618
+	int i, ret = 0;
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	orig_methods = methods = xstrdup(list);
Petr Lautrbach d9e618
+	for(;;) {
Petr Lautrbach d9e618
+		if ((cp = strsep(&methods, DELIM)) == NULL)
Petr Lautrbach d9e618
+			break;
Petr Lautrbach d9e618
+		debug2("auth2_check_required: method \"%s\"", cp);
Petr Lautrbach d9e618
+		if (*cp == '\0') {
Petr Lautrbach d9e618
+			debug("auth2_check_required: empty method");
Petr Lautrbach d9e618
+			ret = -1;
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
+		for (i = 0; authmethods[i] != NULL; i++)
Petr Lautrbach d9e618
+			if (strcmp(cp, authmethods[i]->name) == 0)
Petr Lautrbach d9e618
+				break;
Petr Lautrbach d9e618
+		if ((m = authmethods[i]) == NULL) {
Petr Lautrbach d9e618
+			debug("auth2_check_required: unknown method "
Petr Lautrbach d9e618
+			    "\"%s\"", cp);
Petr Lautrbach d9e618
+			ret = -1;
Petr Lautrbach d9e618
+			break;
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
+		if (m->enabled == NULL || *(m->enabled) == 0) {
Petr Lautrbach d9e618
+			debug("auth2_check_required: method %s explicitly "
Petr Lautrbach d9e618
+			    "disabled", cp);
Petr Lautrbach d9e618
+			ret = -1;
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
+		/* Activate method if it isn't already */
Petr Lautrbach 5bad1d
+		if (m->enabled != NULL && *(m->enabled) == -1)
Petr Lautrbach d9e618
+			*(m->enabled) = 1;
Petr Lautrbach d9e618
+	}
Petr Lautrbach d9e618
+	xfree(orig_methods);
Petr Lautrbach d9e618
+	return (ret);
Petr Lautrbach d9e618
+}
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
diff -up openssh-5.9p1/auth2-gss.c.required-authentication openssh-5.9p1/auth2-gss.c
Petr Lautrbach d9e618
--- openssh-5.9p1/auth2-gss.c.required-authentication	2011-05-05 06:04:11.000000000 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/auth2-gss.c	2012-07-27 12:21:41.206602026 +0200
Petr Lautrbach d9e618
@@ -163,7 +163,7 @@ input_gssapi_token(int type, u_int32_t p
Petr Lautrbach d9e618
 		}
Petr Lautrbach d9e618
 		authctxt->postponed = 0;
Petr Lautrbach d9e618
 		dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
Petr Lautrbach d9e618
-		userauth_finish(authctxt, 0, "gssapi-with-mic");
Petr Lautrbach d9e618
+		userauth_finish(authctxt, 0, "gssapi-with-mic", NULL);
Petr Lautrbach d9e618
 	} else {
Petr Lautrbach d9e618
 		if (send_tok.length != 0) {
Petr Lautrbach d9e618
 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
Petr Lautrbach d9e618
@@ -251,7 +251,7 @@ input_gssapi_exchange_complete(int type,
Petr Lautrbach d9e618
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
Petr Lautrbach d9e618
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
Petr Lautrbach d9e618
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
Petr Lautrbach d9e618
-	userauth_finish(authctxt, authenticated, "gssapi-with-mic");
Petr Lautrbach d9e618
+	userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 static void
Petr Lautrbach d9e618
@@ -291,7 +291,7 @@ input_gssapi_mic(int type, u_int32_t ple
Petr Lautrbach d9e618
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
Petr Lautrbach d9e618
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
Petr Lautrbach d9e618
 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
Petr Lautrbach d9e618
-	userauth_finish(authctxt, authenticated, "gssapi-with-mic");
Petr Lautrbach d9e618
+	userauth_finish(authctxt, authenticated, "gssapi-with-mic", NULL);
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 Authmethod method_gssapi = {
Petr Lautrbach d9e618
diff -up openssh-5.9p1/auth2-chall.c.required-authentication openssh-5.9p1/auth2-chall.c
Petr Lautrbach d9e618
--- openssh-5.9p1/auth2-chall.c.required-authentication	2009-01-28 06:13:39.000000000 +0100
Petr Lautrbach 420ff0
+++ openssh-5.9p1/auth2-chall.c	2012-07-27 12:21:41.206602026 +0200
Petr Lautrbach 5bad1d
@@ -341,7 +341,8 @@ input_userauth_info_response(int type, u
Petr Lautrbach d9e618
 			auth2_challenge_start(authctxt);
Petr Lautrbach d9e618
 		}
Petr Lautrbach d9e618
 	}
Petr Lautrbach d9e618
-	userauth_finish(authctxt, authenticated, method);
Petr Lautrbach d9e618
+	userauth_finish(authctxt, authenticated, "keyboard-interactive",
Petr Lautrbach 5bad1d
+	    authctxt->kbdintctxt?kbdintctxt->device->name:NULL);
Petr Lautrbach 5bad1d
 	xfree(method);
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
diff -up openssh-5.9p1/auth2-none.c.required-authentication openssh-5.9p1/auth2-none.c
Petr Lautrbach d9e618
--- openssh-5.9p1/auth2-none.c.required-authentication	2010-06-26 02:01:33.000000000 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/auth2-none.c	2012-07-27 12:21:41.207602028 +0200
Petr Lautrbach d9e618
@@ -61,7 +61,7 @@ userauth_none(Authctxt *authctxt)
Petr Lautrbach d9e618
 {
Petr Lautrbach d9e618
 	none_enabled = 0;
Petr Lautrbach d9e618
 	packet_check_eom();
Petr Lautrbach d9e618
-	if (options.permit_empty_passwd && options.password_authentication)
Petr Lautrbach d9e618
+	if (options.permit_empty_passwd && options.password_authentication && options.required_auth2 == NULL)
Petr Lautrbach d9e618
 		return (PRIVSEP(auth_password(authctxt, "")));
Petr Lautrbach d9e618
 	return (0);
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
diff -up openssh-5.9p1/monitor.c.required-authentication openssh-5.9p1/monitor.c
Petr Lautrbach 420ff0
--- openssh-5.9p1/monitor.c.required-authentication	2012-07-27 12:21:41.161601930 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/monitor.c	2012-07-27 12:51:18.884927066 +0200
Petr Lautrbach d9e618
@@ -199,6 +199,7 @@ static int key_blobtype = MM_NOKEY;
Petr Lautrbach d9e618
 static char *hostbased_cuser = NULL;
Petr Lautrbach d9e618
 static char *hostbased_chost = NULL;
Petr Lautrbach d9e618
 static char *auth_method = "unknown";
Petr Lautrbach d9e618
+static char *auth_submethod = NULL;
Petr Lautrbach d9e618
 static u_int session_id2_len = 0;
Petr Lautrbach d9e618
 static u_char *session_id2 = NULL;
Petr Lautrbach d9e618
 static pid_t monitor_child_pid;
Petr Lautrbach 420ff0
@@ -353,6 +354,7 @@ monitor_child_preauth(Authctxt *_authctx
Petr Lautrbach d9e618
 {
Petr Lautrbach d9e618
 	struct mon_table *ent;
Petr Lautrbach 420ff0
 	int authenticated = 0;
Petr Lautrbach d9e618
+	char **req_auth;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	debug3("preauth child monitor started");
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
@@ -367,12 +369,14 @@ monitor_child_preauth(Authctxt *_authctx
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	if (compat20) {
Petr Lautrbach d9e618
 		mon_dispatch = mon_dispatch_proto20;
Petr Lautrbach d9e618
+		req_auth = &options.required_auth2;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 		/* Permit requests for moduli and signatures */
Petr Lautrbach d9e618
 		monitor_permit(mon_dispatch, MONITOR_REQ_MODULI, 1);
Petr Lautrbach d9e618
 		monitor_permit(mon_dispatch, MONITOR_REQ_SIGN, 1);
Petr Lautrbach d9e618
 	} else {
Petr Lautrbach d9e618
 		mon_dispatch = mon_dispatch_proto15;
Petr Lautrbach d9e618
+		req_auth = &options.required_auth1;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 		monitor_permit(mon_dispatch, MONITOR_REQ_SESSKEY, 1);
Petr Lautrbach d9e618
 	}
Petr Lautrbach 420ff0
@@ -380,6 +384,7 @@ monitor_child_preauth(Authctxt *_authctx
Petr Lautrbach d9e618
 	/* The first few requests do not require asynchronous access */
Petr Lautrbach d9e618
 	while (!authenticated) {
Petr Lautrbach d9e618
 		auth_method = "unknown";
Petr Lautrbach d9e618
+		auth_submethod = NULL;
Petr Lautrbach d9e618
 		authenticated = (monitor_read(pmonitor, mon_dispatch, &ent) == 1);
Petr Lautrbach d9e618
 		if (authenticated) {
Petr Lautrbach d9e618
 			if (!(ent->flags & MON_AUTHDECIDE))
Petr Lautrbach 420ff0
@@ -401,10 +406,19 @@ monitor_child_preauth(Authctxt *_authctx
Petr Lautrbach d9e618
 			}
Petr Lautrbach d9e618
 #endif
Petr Lautrbach d9e618
 		}
Petr Lautrbach d9e618
+		/* Loop until the required authmethods are done */
Petr Lautrbach d9e618
+		if (authenticated && *req_auth != NULL) {
Petr Lautrbach 420ff0
+			if (auth_remove_from_list(req_auth, auth_method) == 0)
Petr Lautrbach d9e618
+				fatal("INTERNAL ERROR: authenticated method "
Petr Lautrbach d9e618
+				    "\"%s\" not in required list \"%s\"",
Petr Lautrbach d9e618
+				    auth_method, *req_auth);
Petr Lautrbach d9e618
+			debug2("monitor_child_preauth: required list now: %s",
Petr Lautrbach d9e618
+			    *req_auth == NULL ? "DONE" : *req_auth);
Petr Lautrbach d9e618
+		}
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 		if (ent->flags & (MON_AUTHDECIDE|MON_ALOG)) {
Petr Lautrbach d9e618
 			auth_log(authctxt, authenticated, auth_method,
Petr Lautrbach d9e618
-			    compat20 ? " ssh2" : "");
Petr Lautrbach d9e618
+				 auth_submethod, compat20 ? " ssh2" : "");
Petr Lautrbach 420ff0
 			if (!authenticated)
Petr Lautrbach d9e618
 				authctxt->failures++;
Petr Lautrbach d9e618
 		}
Petr Lautrbach 420ff0
@@ -417,6 +431,8 @@ monitor_child_preauth(Authctxt *_authctx
Petr Lautrbach 420ff0
 			}
Petr Lautrbach 420ff0
 		}
Petr Lautrbach 420ff0
 #endif
Petr Lautrbach 420ff0
+		if (*req_auth != NULL)
Petr Lautrbach 420ff0
+			authenticated = 0;
Petr Lautrbach 420ff0
 	}
Petr Lautrbach 420ff0
 
Petr Lautrbach 420ff0
 	/* Drain any buffered messages from the child */
Petr Lautrbach 420ff0
@@ -862,6 +878,7 @@ mm_answer_authpassword(int sock, Buffer
Petr Lautrbach d9e618
 		auth_method = "none";
Petr Lautrbach d9e618
 	else
Petr Lautrbach d9e618
 		auth_method = "password";
Petr Lautrbach d9e618
+	auth_submethod = NULL;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	/* Causes monitor loop to terminate if authenticated */
Petr Lautrbach d9e618
 	return (authenticated);
Petr Lautrbach 420ff0
@@ -921,6 +938,7 @@ mm_answer_bsdauthrespond(int sock, Buffe
Petr Lautrbach d9e618
 	mm_request_send(sock, MONITOR_ANS_BSDAUTHRESPOND, m);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	auth_method = "bsdauth";
Petr Lautrbach d9e618
+	auth_submethod = NULL;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	return (authok != 0);
Petr Lautrbach d9e618
 }
Petr Lautrbach 420ff0
@@ -970,6 +988,7 @@ mm_answer_skeyrespond(int sock, Buffer *
Petr Lautrbach d9e618
 	mm_request_send(sock, MONITOR_ANS_SKEYRESPOND, m);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	auth_method = "skey";
Petr Lautrbach d9e618
+	auth_submethod = NULL;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	return (authok != 0);
Petr Lautrbach d9e618
 }
Petr Lautrbach 420ff0
@@ -1059,7 +1078,8 @@ mm_answer_pam_query(int sock, Buffer *m)
Petr Lautrbach d9e618
 		xfree(prompts);
Petr Lautrbach d9e618
 	if (echo_on != NULL)
Petr Lautrbach d9e618
 		xfree(echo_on);
Petr Lautrbach d9e618
-	auth_method = "keyboard-interactive/pam";
Petr Lautrbach d9e618
+	auth_method = "keyboard-interactive";
Petr Lautrbach d9e618
+	auth_submethod = "pam";
Petr Lautrbach d9e618
 	mm_request_send(sock, MONITOR_ANS_PAM_QUERY, m);
Petr Lautrbach d9e618
 	return (0);
Petr Lautrbach d9e618
 }
Petr Lautrbach 420ff0
@@ -1088,7 +1108,8 @@ mm_answer_pam_respond(int sock, Buffer *
Petr Lautrbach d9e618
 	buffer_clear(m);
Petr Lautrbach d9e618
 	buffer_put_int(m, ret);
Petr Lautrbach d9e618
 	mm_request_send(sock, MONITOR_ANS_PAM_RESPOND, m);
Petr Lautrbach d9e618
-	auth_method = "keyboard-interactive/pam";
Petr Lautrbach d9e618
+	auth_method = "keyboard-interactive";
Petr Lautrbach d9e618
+	auth_submethod = "pam";
Petr Lautrbach d9e618
 	if (ret == 0)
Petr Lautrbach d9e618
 		sshpam_authok = sshpam_ctxt;
Petr Lautrbach d9e618
 	return (0);
Petr Lautrbach 420ff0
@@ -1102,7 +1123,8 @@ mm_answer_pam_free_ctx(int sock, Buffer
Petr Lautrbach d9e618
 	(sshpam_device.free_ctx)(sshpam_ctxt);
Petr Lautrbach d9e618
 	buffer_clear(m);
Petr Lautrbach d9e618
 	mm_request_send(sock, MONITOR_ANS_PAM_FREE_CTX, m);
Petr Lautrbach d9e618
-	auth_method = "keyboard-interactive/pam";
Petr Lautrbach d9e618
+	auth_method = "keyboard-interactive";
Petr Lautrbach d9e618
+	auth_submethod = "pam";
Petr Lautrbach d9e618
 	return (sshpam_authok == sshpam_ctxt);
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
 #endif
Petr Lautrbach 420ff0
@@ -1138,6 +1160,7 @@ mm_answer_keyallowed(int sock, Buffer *m
Petr Lautrbach d9e618
 			allowed = options.pubkey_authentication &&
Petr Lautrbach d9e618
 			    user_key_allowed(authctxt->pw, key);
Petr Lautrbach d9e618
 			auth_method = "publickey";
Petr Lautrbach d9e618
+			auth_submethod = NULL;
Petr Lautrbach d9e618
 			if (options.pubkey_authentication && allowed != 1)
Petr Lautrbach d9e618
 				auth_clear_options();
Petr Lautrbach d9e618
 			break;
Petr Lautrbach 420ff0
@@ -1146,6 +1169,7 @@ mm_answer_keyallowed(int sock, Buffer *m
Petr Lautrbach d9e618
 			    hostbased_key_allowed(authctxt->pw,
Petr Lautrbach d9e618
 			    cuser, chost, key);
Petr Lautrbach d9e618
 			auth_method = "hostbased";
Petr Lautrbach d9e618
+			auth_submethod = NULL;
Petr Lautrbach d9e618
 			break;
Petr Lautrbach d9e618
 		case MM_RSAHOSTKEY:
Petr Lautrbach d9e618
 			key->type = KEY_RSA1; /* XXX */
Petr Lautrbach 420ff0
@@ -1155,6 +1179,7 @@ mm_answer_keyallowed(int sock, Buffer *m
Petr Lautrbach d9e618
 			if (options.rhosts_rsa_authentication && allowed != 1)
Petr Lautrbach d9e618
 				auth_clear_options();
Petr Lautrbach d9e618
 			auth_method = "rsa";
Petr Lautrbach d9e618
+			auth_submethod = NULL;
Petr Lautrbach d9e618
 			break;
Petr Lautrbach d9e618
 		default:
Petr Lautrbach d9e618
 			fatal("%s: unknown key type %d", __func__, type);
Petr Lautrbach 420ff0
@@ -1180,7 +1205,8 @@ mm_answer_keyallowed(int sock, Buffer *m
Petr Lautrbach d9e618
 		hostbased_chost = chost;
Petr Lautrbach d9e618
 	} else {
Petr Lautrbach d9e618
 		/* Log failed attempt */
Petr Lautrbach d9e618
-		auth_log(authctxt, 0, auth_method, compat20 ? " ssh2" : "");
Petr Lautrbach d9e618
+		auth_log(authctxt, 0, auth_method, auth_submethod,
Petr Lautrbach d9e618
+		    compat20 ? " ssh2" : "");
Petr Lautrbach d9e618
 		xfree(blob);
Petr Lautrbach d9e618
 		xfree(cuser);
Petr Lautrbach d9e618
 		xfree(chost);
Petr Lautrbach 420ff0
@@ -1356,6 +1382,7 @@ mm_answer_keyverify(int sock, Buffer *m)
Petr Lautrbach d9e618
 	xfree(data);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	auth_method = key_blobtype == MM_USERKEY ? "publickey" : "hostbased";
Petr Lautrbach d9e618
+	auth_submethod = NULL;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	monitor_reset_key_state();
Petr Lautrbach d9e618
 
Petr Lautrbach 420ff0
@@ -1545,6 +1572,7 @@ mm_answer_rsa_keyallowed(int sock, Buffe
Petr Lautrbach d9e618
 	debug3("%s entering", __func__);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	auth_method = "rsa";
Petr Lautrbach d9e618
+	auth_submethod = NULL;
Petr Lautrbach d9e618
 	if (options.rsa_authentication && authctxt->valid) {
Petr Lautrbach d9e618
 		if ((client_n = BN_new()) == NULL)
Petr Lautrbach d9e618
 			fatal("%s: BN_new", __func__);
Petr Lautrbach 420ff0
@@ -1650,6 +1678,7 @@ mm_answer_rsa_response(int sock, Buffer
Petr Lautrbach d9e618
 	xfree(response);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	auth_method = key_blobtype == MM_RSAUSERKEY ? "rsa" : "rhosts-rsa";
Petr Lautrbach d9e618
+	auth_submethod = NULL;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	/* reset state */
Petr Lautrbach d9e618
 	BN_clear_free(ssh1_challenge);
Petr Lautrbach 420ff0
@@ -2099,6 +2128,7 @@ mm_answer_gss_userok(int sock, Buffer *m
Petr Lautrbach d9e618
 	mm_request_send(sock, MONITOR_ANS_GSSUSEROK, m);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	auth_method = "gssapi-with-mic";
Petr Lautrbach d9e618
+	auth_submethod = NULL;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	/* Monitor loop will terminate if authenticated */
Petr Lautrbach d9e618
 	return (authenticated);
Petr Lautrbach 420ff0
@@ -2303,6 +2333,7 @@ mm_answer_jpake_check_confirm(int sock,
Petr Lautrbach d9e618
 	monitor_permit(mon_dispatch, MONITOR_REQ_JPAKE_STEP1, 1);
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	auth_method = "jpake-01@openssh.com";
Petr Lautrbach d9e618
+	auth_submethod = NULL;
Petr Lautrbach d9e618
 	return authenticated;
Petr Lautrbach d9e618
 }
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
diff -up openssh-5.9p1/servconf.c.required-authentication openssh-5.9p1/servconf.c
Petr Lautrbach 420ff0
--- openssh-5.9p1/servconf.c.required-authentication	2012-07-27 12:21:41.167601942 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/servconf.c	2012-07-27 12:21:41.209602032 +0200
Petr Lautrbach d9e618
@@ -42,6 +42,8 @@
Petr Lautrbach d9e618
 #include "key.h"
Petr Lautrbach d9e618
 #include "kex.h"
Petr Lautrbach d9e618
 #include "mac.h"
Petr Lautrbach d9e618
+#include "hostfile.h"
Petr Lautrbach d9e618
+#include "auth.h"
Petr Lautrbach d9e618
 #include "match.h"
Petr Lautrbach d9e618
 #include "channels.h"
Petr Lautrbach d9e618
 #include "groupaccess.h"
Petr Lautrbach 420ff0
@@ -129,6 +131,8 @@ initialize_server_options(ServerOptions
Petr Lautrbach d9e618
 	options->num_authkeys_files = 0;
Petr Lautrbach d9e618
 	options->num_accept_env = 0;
Petr Lautrbach d9e618
 	options->permit_tun = -1;
Petr Lautrbach d9e618
+	options->required_auth1 = NULL;
Petr Lautrbach d9e618
+	options->required_auth2 = NULL;
Petr Lautrbach d9e618
 	options->num_permitted_opens = -1;
Petr Lautrbach d9e618
 	options->adm_forced_command = NULL;
Petr Lautrbach d9e618
 	options->chroot_directory = NULL;
Petr Lautrbach d9e618
@@ -319,6 +323,7 @@ typedef enum {
Petr Lautrbach d9e618
 	sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
Petr Lautrbach d9e618
 	sClientAliveCountMax, sAuthorizedKeysFile,
Petr Lautrbach d9e618
 	sGssAuthentication, sGssCleanupCreds, sAcceptEnv, sPermitTunnel,
Petr Lautrbach d9e618
+	sRequiredAuthentications1, sRequiredAuthentications2,
Petr Lautrbach d9e618
 	sMatch, sPermitOpen, sForceCommand, sChrootDirectory,
Petr Lautrbach d9e618
 	sUsePrivilegeSeparation, sAllowAgentForwarding,
Petr Lautrbach d9e618
 	sZeroKnowledgePasswordAuthentication, sHostCertificate,
Petr Lautrbach d9e618
@@ -447,6 +452,8 @@ static struct {
Petr Lautrbach d9e618
 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
Petr Lautrbach d9e618
 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
Petr Lautrbach d9e618
 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
Petr Lautrbach d9e618
+	{ "requiredauthentications1", sRequiredAuthentications1, SSHCFG_ALL },
Petr Lautrbach d9e618
+	{ "requiredauthentications2", sRequiredAuthentications2, SSHCFG_ALL },
Petr Lautrbach d9e618
 	{ "ipqos", sIPQoS, SSHCFG_ALL },
Petr Lautrbach d9e618
 	{ NULL, sBadOption, 0 }
Petr Lautrbach d9e618
 };
Petr Lautrbach d9e618
@@ -1220,6 +1227,33 @@ process_server_config_line(ServerOptions
Petr Lautrbach d9e618
 			options->max_startups = options->max_startups_begin;
Petr Lautrbach d9e618
 		break;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	case sRequiredAuthentications1:
Petr Lautrbach d9e618
+		charptr = &options->required_auth1;
Petr Lautrbach d9e618
+		arg = strdelim(&cp;;
Petr Lautrbach d9e618
+		if (!arg || *arg == '\0')
Petr Lautrbach d9e618
+			fatal("%.200s line %d: Missing argument.",
Petr Lautrbach d9e618
+			    filename, linenum);
Petr Lautrbach 5bad1d
+		if (auth1_check_required(arg) != 0)
Petr Lautrbach 5bad1d
+			fatal("%.200s line %d: Invalid required authentication "
Petr Lautrbach 5bad1d
+			    "list", filename, linenum);
Petr Lautrbach d9e618
+		if (*charptr == NULL)
Petr Lautrbach d9e618
+			*charptr = xstrdup(arg);
Petr Lautrbach d9e618
+		break;
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+	case sRequiredAuthentications2:
Petr Lautrbach d9e618
+		charptr = &options->required_auth2;
Petr Lautrbach d9e618
+		arg = strdelim(&cp;;
Petr Lautrbach d9e618
+		if (!arg || *arg == '\0')
Petr Lautrbach d9e618
+			fatal("%.200s line %d: Missing argument.",
Petr Lautrbach d9e618
+			    filename, linenum);
Petr Lautrbach 5bad1d
+		if (auth2_check_required(arg) != 0)
Petr Lautrbach 5bad1d
+			fatal("%.200s line %d: Invalid required authentication "
Petr Lautrbach 5bad1d
+			    "list", filename, linenum);
Petr Lautrbach d9e618
+		if (*charptr == NULL)
Petr Lautrbach d9e618
+			*charptr = xstrdup(arg);
Petr Lautrbach d9e618
+		break;
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
 	case sMaxAuthTries:
Petr Lautrbach d9e618
 		intptr = &options->max_authtries;
Petr Lautrbach d9e618
 		goto parse_int;
Petr Lautrbach d9e618
diff -up openssh-5.9p1/servconf.h.required-authentication openssh-5.9p1/servconf.h
Petr Lautrbach d9e618
--- openssh-5.9p1/servconf.h.required-authentication	2011-06-23 00:30:03.000000000 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/servconf.h	2012-07-27 12:21:41.210602035 +0200
Petr Lautrbach d9e618
@@ -154,6 +154,9 @@ typedef struct {
Petr Lautrbach d9e618
 	u_int num_authkeys_files;	/* Files containing public keys */
Petr Lautrbach d9e618
 	char   *authorized_keys_files[MAX_AUTHKEYS_FILES];
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
+	char   *required_auth1; /* Required, but not sufficient */
Petr Lautrbach d9e618
+	char   *required_auth2;
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
 	char   *adm_forced_command;
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
 	int	use_pam;		/* Enable auth via PAM */
Petr Lautrbach d9e618
diff -up openssh-5.9p1/sshd_config.5.required-authentication openssh-5.9p1/sshd_config.5
Petr Lautrbach d9e618
--- openssh-5.9p1/sshd_config.5.required-authentication	2011-08-05 22:17:33.000000000 +0200
Petr Lautrbach 420ff0
+++ openssh-5.9p1/sshd_config.5	2012-07-27 12:38:47.607222070 +0200
Petr Lautrbach d9e618
@@ -723,6 +723,8 @@ Available keywords are
Petr Lautrbach d9e618
 .Cm PermitOpen ,
Petr Lautrbach d9e618
 .Cm PermitRootLogin ,
Petr Lautrbach d9e618
 .Cm PermitTunnel ,
Petr Lautrbach d9e618
+.Cm RequiredAuthentications1,
Petr Lautrbach d9e618
+.Cm RequiredAuthentications2,
Petr Lautrbach d9e618
 .Cm PubkeyAuthentication ,
Petr Lautrbach d9e618
 .Cm RhostsRSAAuthentication ,
Petr Lautrbach d9e618
 .Cm RSAAuthentication ,
Petr Lautrbach 5bad1d
@@ -920,6 +922,21 @@ Specifies a list of revoked public keys.
Petr Lautrbach d9e618
 Keys listed in this file will be refused for public key authentication.
Petr Lautrbach d9e618
 Note that if this file is not readable, then public key authentication will
Petr Lautrbach d9e618
 be refused for all users.
Petr Lautrbach d9e618
+.It Cm RequiredAuthentications[12]
Petr Lautrbach 420ff0
+ Specifies required methods of authentications that has to succeed before authorizing the connection.
Petr Lautrbach d9e618
+ (RequiredAuthentication1 for Protocol version 1, and RequiredAuthentication2 for v2)
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+ RequiredAuthentications1 method[,method...] 
Petr Lautrbach d9e618
+ RequiredAuthentications2 method[,method...]
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+.Pp
Petr Lautrbach d9e618
+Example 1:
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+ RequiredAuthentications2 password,hostbased
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
+Example 2:
Petr Lautrbach d9e618
+ RequiredAuthentications2 publickey,password
Petr Lautrbach d9e618
+
Petr Lautrbach d9e618
 .It Cm RhostsRSAAuthentication
Petr Lautrbach d9e618
 Specifies whether rhosts or /etc/hosts.equiv authentication together
Petr Lautrbach d9e618
 with successful RSA host authentication is allowed.