upstream commit

Add a new authorized_keys option "restrict" that
 includes all current and future key restrictions (no-*-forwarding, etc). Also
 add permissive versions of the existing restrictions, e.g. "no-pty" -> "pty".
 This simplifies the task of setting up restricted keys and ensures they are
 maximally-restricted, regardless of any permissions we might implement in the
 future.

Example:

restrict,pty,command="nethack" ssh-ed25519 AAAAC3NzaC1lZDI1...

Idea from Jann Horn; ok markus@

Upstream-ID: 04ceb9d448e46e67e13887a7ae5ea45b4f1719d0
diff --git a/auth-options.c b/auth-options.c
index e387697..cb68802 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.68 2015/07/03 03:43:18 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.69 2015/11/16 00:30:02 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -88,6 +88,36 @@
 }
 
 /*
+ * Match flag 'opt' in *optsp, and if allow_negate is set then also match
+ * 'no-opt'. Returns -1 if option not matched, 1 if option matches or 0
+ * if negated option matches. 
+ * If the option or negated option matches, then *optsp is updated to
+ * point to the first character after the option and, if 'msg' is not NULL
+ * then a message based on it added via auth_debug_add().
+ */
+static int
+match_flag(const char *opt, int allow_negate, char **optsp, const char *msg)
+{
+	size_t opt_len = strlen(opt);
+	char *opts = *optsp;
+	int negate = 0;
+
+	if (allow_negate && strncasecmp(opts, "no-", 3) == 0) {
+		opts += 3;
+		negate = 1;
+	}
+	if (strncasecmp(opts, opt, opt_len) == 0) {
+		*optsp = opts + opt_len;
+		if (msg != NULL) {
+			auth_debug_add("%s %s.", msg,
+			    negate ? "disabled" : "enabled");
+		}
+		return negate ? 0 : 1;
+	}
+	return -1;
+}
+
+/*
  * return 1 if access is granted, 0 if not.
  * side effect: sets key option flags
  */
@@ -95,7 +125,7 @@
 auth_parse_options(struct passwd *pw, char *opts, char *file, u_long linenum)
 {
 	const char *cp;
-	int i;
+	int i, r;
 
 	/* reset options */
 	auth_clear_options();
@@ -104,45 +134,42 @@
 		return 1;
 
 	while (*opts && *opts != ' ' && *opts != '\t') {
-		cp = "cert-authority";
-		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-			key_is_cert_authority = 1;
-			opts += strlen(cp);
+		if ((r = match_flag("cert-authority", 0, &opts, NULL)) != -1) {
+			key_is_cert_authority = r;
 			goto next_option;
 		}
-		cp = "no-port-forwarding";
-		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-			auth_debug_add("Port forwarding disabled.");
+		if ((r = match_flag("restrict", 0, &opts, NULL)) != -1) {
+			auth_debug_add("Key is restricted.");
 			no_port_forwarding_flag = 1;
-			opts += strlen(cp);
-			goto next_option;
-		}
-		cp = "no-agent-forwarding";
-		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-			auth_debug_add("Agent forwarding disabled.");
 			no_agent_forwarding_flag = 1;
-			opts += strlen(cp);
-			goto next_option;
-		}
-		cp = "no-X11-forwarding";
-		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-			auth_debug_add("X11 forwarding disabled.");
 			no_x11_forwarding_flag = 1;
-			opts += strlen(cp);
-			goto next_option;
-		}
-		cp = "no-pty";
-		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-			auth_debug_add("Pty allocation disabled.");
 			no_pty_flag = 1;
-			opts += strlen(cp);
+			no_user_rc = 1;
 			goto next_option;
 		}
-		cp = "no-user-rc";
-		if (strncasecmp(opts, cp, strlen(cp)) == 0) {
-			auth_debug_add("User rc file execution disabled.");
-			no_user_rc = 1;
-			opts += strlen(cp);
+		if ((r = match_flag("port-forwarding", 1, &opts,
+		    "Port forwarding")) != -1) {
+			no_port_forwarding_flag = r != 1;
+			goto next_option;
+		}
+		if ((r = match_flag("agent-forwarding", 1, &opts,
+		    "Agent forwarding")) != -1) {
+			no_agent_forwarding_flag = r != 1;
+			goto next_option;
+		}
+		if ((r = match_flag("x11-forwarding", 1, &opts,
+		    "X11 forwarding")) != -1) {
+			no_x11_forwarding_flag = r != 1;
+			goto next_option;
+		}
+		if ((r = match_flag("pty", 1, &opts,
+		    "PTY allocation")) != -1) {
+			no_pty_flag = r != 1;
+			goto next_option;
+		}
+		if ((r = match_flag("user-rc", 1, &opts,
+		    "User rc execution")) != -1) {
+			no_user_rc = r != 1;
 			goto next_option;
 		}
 		cp = "command=\"";