[openssh-commits] [openssh] 02/04: upstream: permitlisten option for authorized_keys; ok markus@

git+noreply at mindrot.org git+noreply at mindrot.org
Thu Jun 7 04:27:31 AEST 2018


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit 93c06ab6b77514e0447fe4f1d822afcbb2a9be08
Author: djm at openbsd.org <djm at openbsd.org>
Date:   Wed Jun 6 18:23:32 2018 +0000

    upstream: permitlisten option for authorized_keys; ok markus@
    
    OpenBSD-Commit-ID: 8650883018d7aa893173d703379e4456a222c672
---
 auth-options.c | 140 ++++++++++++++++++++++++++++++++++++++-------------------
 auth-options.h |   6 ++-
 auth.c         |  15 +++++--
 servconf.c     |  32 ++++++-------
 servconf.h     |   9 ++--
 session.c      |  52 +++++++++++++--------
 6 files changed, 165 insertions(+), 89 deletions(-)

diff --git a/auth-options.c b/auth-options.c
index ef57ebf4..c55c3ed0 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.79 2018/04/06 04:15:45 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.80 2018/06/06 18:23:32 djm Exp $ */
 /*
  * Copyright (c) 2018 Damien Miller <djm at mindrot.org>
  *
@@ -283,6 +283,10 @@ sshauthopt_free(struct sshauthopt *opts)
 		free(opts->permitopen[i]);
 	free(opts->permitopen);
 
+	for (i = 0; i < opts->npermitlisten; i++)
+		free(opts->permitlisten[i]);
+	free(opts->permitlisten);
+
 	explicit_bzero(opts, sizeof(*opts));
 	free(opts);
 }
@@ -304,10 +308,70 @@ sshauthopt_new_with_keys_defaults(void)
 	return ret;
 }
 
+/*
+ * Parse and record a permitopen/permitlisten directive.
+ * Return 0 on success. Return -1 on failure and sets *errstrp to error reason.
+ */
+static int
+handle_permit(const char *opts, char ***permitsp, size_t *npermitsp,
+    const char **errstrp)
+{
+	char *opt, *tmp, *cp, *host, **permits = *permitsp;
+	size_t npermits = *npermitsp;
+	const char *errstr = "unknown error";
+
+	if (npermits > INT_MAX) {
+		*errstrp = "too many permission directives";
+		return -1;
+	}
+	if ((opt = opt_dequote(&opts, &errstr)) == NULL) {
+		return -1;
+	}
+	if ((tmp = strdup(opt)) == NULL) {
+		free(opt);
+		*errstrp = "memory allocation failed";
+		return -1;
+	}
+	cp = tmp;
+	/* validate syntax before recording it. */
+	host = hpdelim(&cp);
+	if (host == NULL || strlen(host) >= NI_MAXHOST) {
+		free(tmp);
+		free(opt);
+		*errstrp = "invalid permission hostname";
+		return -1;
+	}
+	/*
+	 * don't want to use permitopen_port to avoid
+	 * dependency on channels.[ch] here.
+	 */
+	if (cp == NULL ||
+	    (strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
+		free(tmp);
+		free(opt);
+		*errstrp = "invalid permission port";
+		return -1;
+	}
+	/* XXX - add streamlocal support */
+	free(tmp);
+	/* Record it */
+	if ((permits = recallocarray(permits, npermits, npermits + 1,
+	    sizeof(*permits))) == NULL) {
+		free(opt);
+		/* NB. don't update *permitsp if alloc fails */
+		*errstrp = "memory allocation failed";
+		return -1;
+	}
+	permits[npermits++] = opt;
+	*permitsp = permits;
+	*npermitsp = npermits;
+	return 0;
+}
+
 struct sshauthopt *
 sshauthopt_parse(const char *opts, const char **errstrp)
 {
-	char **oarray, *opt, *cp, *tmp, *host;
+	char **oarray, *opt, *cp, *tmp;
 	int r;
 	struct sshauthopt *ret = NULL;
 	const char *errstr = "unknown error";
@@ -410,48 +474,13 @@ sshauthopt_parse(const char *opts, const char **errstrp)
 			}
 			ret->env[ret->nenv++] = opt;
 		} else if (opt_match(&opts, "permitopen")) {
-			if (ret->npermitopen > INT_MAX) {
-				errstr = "too many permitopens";
+			if (handle_permit(opts, &ret->permitopen,
+			    &ret->npermitopen, &errstr) != 0)
 				goto fail;
-			}
-			if ((opt = opt_dequote(&opts, &errstr)) == NULL)
+		} else if (opt_match(&opts, "permitlisten")) {
+			if (handle_permit(opts, &ret->permitlisten,
+			    &ret->npermitlisten, &errstr) != 0)
 				goto fail;
-			if ((tmp = strdup(opt)) == NULL) {
-				free(opt);
-				goto alloc_fail;
-			}
-			cp = tmp;
-			/* validate syntax of permitopen before recording it. */
-			host = hpdelim(&cp);
-			if (host == NULL || strlen(host) >= NI_MAXHOST) {
-				free(tmp);
-				free(opt);
-				errstr = "invalid permitopen hostname";
-				goto fail;
-			}
-			/*
-			 * don't want to use permitopen_port to avoid
-			 * dependency on channels.[ch] here.
-			 */
-			if (cp == NULL ||
-			    (strcmp(cp, "*") != 0 && a2port(cp) <= 0)) {
-				free(tmp);
-				free(opt);
-				errstr = "invalid permitopen port";
-				goto fail;
-			}
-			/* XXX - add streamlocal support */
-			free(tmp);
-			/* Record it */
-			oarray = ret->permitopen;
-			if ((ret->permitopen = recallocarray(ret->permitopen,
-			    ret->npermitopen, ret->npermitopen + 1,
-			    sizeof(*ret->permitopen))) == NULL) {
-				free(opt);
-				ret->permitopen = oarray;
-				goto alloc_fail;
-			}
-			ret->permitopen[ret->npermitopen++] = opt;
 		} else if (opt_match(&opts, "tunnel")) {
 			if ((opt = opt_dequote(&opts, &errstr)) == NULL)
 				goto fail;
@@ -554,7 +583,10 @@ sshauthopt_merge(const struct sshauthopt *primary,
 	if (tmp != NULL && (ret->required_from_host_keys = strdup(tmp)) == NULL)
 		goto alloc_fail;
 
-	/* force_tun_device, permitopen and environment prefer the primary. */
+	/*
+	 * force_tun_device, permitopen/permitlisten and environment all
+	 * prefer the primary.
+	 */
 	ret->force_tun_device = primary->force_tun_device;
 	if (ret->force_tun_device == -1)
 		ret->force_tun_device = additional->force_tun_device;
@@ -577,6 +609,16 @@ sshauthopt_merge(const struct sshauthopt *primary,
 			goto alloc_fail;
 	}
 
+	if (primary->npermitlisten > 0) {
+		if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
+		    primary->permitlisten, primary->npermitlisten) != 0)
+			goto alloc_fail;
+	} else if (additional->npermitlisten > 0) {
+		if (dup_strings(&ret->permitlisten, &ret->npermitlisten,
+		    additional->permitlisten, additional->npermitlisten) != 0)
+			goto alloc_fail;
+	}
+
 	/* Flags are logical-AND (i.e. must be set in both for permission) */
 #define OPTFLAG(x) ret->x = (primary->x == 1) && (additional->x == 1)
 	OPTFLAG(permit_port_forwarding_flag);
@@ -669,7 +711,9 @@ sshauthopt_copy(const struct sshauthopt *orig)
 
 	if (dup_strings(&ret->env, &ret->nenv, orig->env, orig->nenv) != 0 ||
 	    dup_strings(&ret->permitopen, &ret->npermitopen,
-	    orig->permitopen, orig->npermitopen) != 0) {
+	    orig->permitopen, orig->npermitopen) != 0 ||
+	    dup_strings(&ret->permitlisten, &ret->npermitlisten,
+	    orig->permitlisten, orig->npermitlisten) != 0) {
 		sshauthopt_free(ret);
 		return NULL;
 	}
@@ -805,7 +849,9 @@ sshauthopt_serialise(const struct sshauthopt *opts, struct sshbuf *m,
 	if ((r = serialise_array(m, opts->env,
 	    untrusted ? 0 : opts->nenv)) != 0 ||
 	    (r = serialise_array(m, opts->permitopen,
-	    untrusted ? 0 : opts->npermitopen)) != 0)
+	    untrusted ? 0 : opts->npermitopen)) ||
+	    (r = serialise_array(m, opts->permitlisten,
+	    untrusted ? 0 : opts->npermitlisten)) != 0)
 		return r;
 
 	/* success */
@@ -859,7 +905,9 @@ sshauthopt_deserialise(struct sshbuf *m, struct sshauthopt **optsp)
 	/* Array options */
 	if ((r = deserialise_array(m, &opts->env, &opts->nenv)) != 0 ||
 	    (r = deserialise_array(m,
-	    &opts->permitopen, &opts->npermitopen)) != 0)
+	    &opts->permitopen, &opts->npermitopen)) != 0 ||
+	    (r = deserialise_array(m,
+	    &opts->permitlisten, &opts->npermitlisten)) != 0)
 		goto out;
 
 	/* success */
diff --git a/auth-options.h b/auth-options.h
index bf59b30b..0462983b 100644
--- a/auth-options.h
+++ b/auth-options.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.h,v 1.26 2018/03/12 00:52:01 djm Exp $ */
+/* $OpenBSD: auth-options.h,v 1.27 2018/06/06 18:23:32 djm Exp $ */
 
 /*
  * Copyright (c) 2018 Damien Miller <djm at mindrot.org>
@@ -55,6 +55,10 @@ struct sshauthopt {
 	size_t npermitopen;
 	char **permitopen;
 
+	/* Permitted listens (remote forwarding) */
+	size_t npermitlisten;
+	char **permitlisten;
+
 	/*
 	 * Permitted host/addresses (comma-separated)
 	 * Caller must check source address matches both lists (if present).
diff --git a/auth.c b/auth.c
index 573cd03b..0424f1f7 100644
--- a/auth.c
+++ b/auth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth.c,v 1.129 2018/06/01 03:33:53 djm Exp $ */
+/* $OpenBSD: auth.c,v 1.130 2018/06/06 18:23:32 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
@@ -1005,17 +1005,20 @@ auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
 	int do_env = options.permit_user_env && opts->nenv > 0;
 	int do_permitopen = opts->npermitopen > 0 &&
 	    (options.allow_tcp_forwarding & FORWARD_LOCAL) != 0;
+	int do_permitlisten = opts->npermitlisten > 0 &&
+	    (options.allow_tcp_forwarding & FORWARD_REMOTE) != 0;
 	size_t i;
 	char msg[1024], buf[64];
 
 	snprintf(buf, sizeof(buf), "%d", opts->force_tun_device);
 	/* Try to keep this alphabetically sorted */
-	snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s",
+	snprintf(msg, sizeof(msg), "key options:%s%s%s%s%s%s%s%s%s%s%s%s%s",
 	    opts->permit_agent_forwarding_flag ? " agent-forwarding" : "",
 	    opts->force_command == NULL ? "" : " command",
 	    do_env ?  " environment" : "",
 	    opts->valid_before == 0 ? "" : "expires",
 	    do_permitopen ?  " permitopen" : "",
+	    do_permitlisten ?  " permitlisten" : "",
 	    opts->permit_port_forwarding_flag ? " port-forwarding" : "",
 	    opts->cert_principals == NULL ? "" : " principals",
 	    opts->permit_pty_flag ? " pty" : "",
@@ -1049,12 +1052,18 @@ auth_log_authopts(const char *loc, const struct sshauthopt *opts, int do_remote)
 	}
 	if (opts->force_command != NULL)
 		debug("%s: forced command: \"%s\"", loc, opts->force_command);
-	if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
+	if (do_permitopen) {
 		for (i = 0; i < opts->npermitopen; i++) {
 			debug("%s: permitted open: %s",
 			    loc, opts->permitopen[i]);
 		}
 	}
+	if (do_permitlisten) {
+		for (i = 0; i < opts->npermitlisten; i++) {
+			debug("%s: permitted listen: %s",
+			    loc, opts->permitlisten[i]);
+		}
+	}
 }
 
 /* Activate a new set of key/cert options; merging with what is there. */
diff --git a/servconf.c b/servconf.c
index b75faf3f..3c41490b 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
 
-/* $OpenBSD: servconf.c,v 1.329 2018/06/06 18:22:41 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.330 2018/06/06 18:23:32 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -160,7 +160,7 @@ initialize_server_options(ServerOptions *options)
 	options->num_accept_env = 0;
 	options->permit_tun = -1;
 	options->permitted_opens = NULL;
-	options->permitted_remote_opens = NULL;
+	options->permitted_listens = NULL;
 	options->adm_forced_command = NULL;
 	options->chroot_directory = NULL;
 	options->authorized_keys_command = NULL;
@@ -463,7 +463,7 @@ typedef enum {
 	sClientAliveInterval, sClientAliveCountMax, sAuthorizedKeysFile,
 	sGssAuthentication, sGssCleanupCreds, sGssStrictAcceptor,
 	sAcceptEnv, sPermitTunnel,
-	sMatch, sPermitOpen, sPermitRemoteOpen, sForceCommand, sChrootDirectory,
+	sMatch, sPermitOpen, sPermitListen, sForceCommand, sChrootDirectory,
 	sUsePrivilegeSeparation, sAllowAgentForwarding,
 	sHostCertificate,
 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
@@ -598,7 +598,7 @@ static struct {
 	{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
 	{ "match", sMatch, SSHCFG_ALL },
 	{ "permitopen", sPermitOpen, SSHCFG_ALL },
-	{ "permitremoteopen", sPermitRemoteOpen, SSHCFG_ALL },
+	{ "permitlisten", sPermitListen, SSHCFG_ALL },
 	{ "forcecommand", sForceCommand, SSHCFG_ALL },
 	{ "chrootdirectory", sChrootDirectory, SSHCFG_ALL },
 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
@@ -878,9 +878,9 @@ process_permitopen(struct ssh *ssh, ServerOptions *options)
 {
 	process_permitopen_list(ssh, sPermitOpen,
 	    options->permitted_opens, options->num_permitted_opens);
-	process_permitopen_list(ssh, sPermitRemoteOpen,
-	    options->permitted_remote_opens,
-	    options->num_permitted_remote_opens);
+	process_permitopen_list(ssh, sPermitListen,
+	    options->permitted_listens,
+	    options->num_permitted_listens);
 }
 
 struct connection_info *
@@ -1831,11 +1831,11 @@ process_server_config_line(ServerOptions *options, char *line,
 		*activep = value;
 		break;
 
-	case sPermitRemoteOpen:
+	case sPermitListen:
 	case sPermitOpen:
-		if (opcode == sPermitRemoteOpen) {
-			uintptr = &options->num_permitted_remote_opens;
-			chararrayptr = &options->permitted_remote_opens;
+		if (opcode == sPermitListen) {
+			uintptr = &options->num_permitted_listens;
+			chararrayptr = &options->permitted_listens;
 		} else {
 			uintptr = &options->num_permitted_opens;
 			chararrayptr = &options->permitted_opens;
@@ -1857,7 +1857,7 @@ process_server_config_line(ServerOptions *options, char *line,
 		for (; arg != NULL && *arg != '\0'; arg = strdelim(&cp)) {
 			arg2 = xstrdup(arg);
 			p = hpdelim(&arg);
-			/* XXX support bare port number for PermitRemoteOpen */
+			/* XXX support bare port number for PermitListen */
 			if (p == NULL) {
 				fatal("%s line %d: missing host in %s",
 				    filename, linenum,
@@ -2596,12 +2596,12 @@ dump_config(ServerOptions *o)
 			printf(" %s", o->permitted_opens[i]);
 	}
 	printf("\n");
-	printf("permitremoteopen");
-	if (o->num_permitted_remote_opens == 0)
+	printf("permitlisten");
+	if (o->num_permitted_listens == 0)
 		printf(" any");
 	else {
-		for (i = 0; i < o->num_permitted_remote_opens; i++)
-			printf(" %s", o->permitted_remote_opens[i]);
+		for (i = 0; i < o->num_permitted_listens; i++)
+			printf(" %s", o->permitted_listens[i]);
 	}
 	printf("\n");
 }
diff --git a/servconf.h b/servconf.h
index 62acd893..450b94ec 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.132 2018/06/06 18:22:41 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.133 2018/06/06 18:23:32 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo at cs.hut.fi>
@@ -183,8 +183,8 @@ typedef struct {
 
 	char   **permitted_opens;	/* May also be one of PERMITOPEN_* */
 	u_int   num_permitted_opens;
-	char   **permitted_remote_opens; /* May also be one of PERMITOPEN_* */
-	u_int   num_permitted_remote_opens;
+	char   **permitted_listens; /* May also be one of PERMITOPEN_* */
+	u_int   num_permitted_listens;
 
 	char   *chroot_directory;
 	char   *revoked_keys_file;
@@ -248,8 +248,7 @@ struct connection_info {
 		M_CP_STRARRAYOPT(accept_env, num_accept_env); \
 		M_CP_STRARRAYOPT(auth_methods, num_auth_methods); \
 		M_CP_STRARRAYOPT(permitted_opens, num_permitted_opens); \
-		M_CP_STRARRAYOPT(permitted_remote_opens, \
-		    num_permitted_remote_opens); \
+		M_CP_STRARRAYOPT(permitted_listens, num_permitted_listens); \
 	} while (0)
 
 struct connection_info *get_connection_info(int, int);
diff --git a/session.c b/session.c
index 3a3fd841..e72fcb0a 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.296 2018/06/06 18:22:41 djm Exp $ */
+/* $OpenBSD: session.c,v 1.297 2018/06/06 18:23:32 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo at cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -290,27 +290,43 @@ prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
 }
 
 static void
-set_permitopen_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
+set_fwdpermit_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
 {
 	char *tmp, *cp, *host;
 	int port;
 	size_t i;
 
-	if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
-		return;
-	channel_clear_permission(ssh, FORWARD_USER, FORWARD_LOCAL);
-	for (i = 0; i < auth_opts->npermitopen; i++) {
-		tmp = cp = xstrdup(auth_opts->permitopen[i]);
-		/* This shouldn't fail as it has already been checked */
-		if ((host = hpdelim(&cp)) == NULL)
-			fatal("%s: internal error: hpdelim", __func__);
-		host = cleanhostname(host);
-		if (cp == NULL || (port = permitopen_port(cp)) < 0)
-			fatal("%s: internal error: permitopen port",
-			    __func__);
-		channel_add_permission(ssh, FORWARD_USER, FORWARD_LOCAL,
-		    host, port);
-		free(tmp);
+	if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
+		channel_clear_permission(ssh, FORWARD_USER, FORWARD_LOCAL);
+		for (i = 0; i < auth_opts->npermitopen; i++) {
+			tmp = cp = xstrdup(auth_opts->permitopen[i]);
+			/* This shouldn't fail as it has already been checked */
+			if ((host = hpdelim(&cp)) == NULL)
+				fatal("%s: internal error: hpdelim", __func__);
+			host = cleanhostname(host);
+			if (cp == NULL || (port = permitopen_port(cp)) < 0)
+				fatal("%s: internal error: permitopen port",
+				    __func__);
+			channel_add_permission(ssh,
+			    FORWARD_USER, FORWARD_LOCAL, host, port);
+			free(tmp);
+		}
+	}
+	if ((options.allow_tcp_forwarding & FORWARD_REMOTE) != 0) {
+		channel_clear_permission(ssh, FORWARD_USER, FORWARD_REMOTE);
+		for (i = 0; i < auth_opts->npermitlisten; i++) {
+			tmp = cp = xstrdup(auth_opts->permitlisten[i]);
+			/* This shouldn't fail as it has already been checked */
+			if ((host = hpdelim(&cp)) == NULL)
+				fatal("%s: internal error: hpdelim", __func__);
+			host = cleanhostname(host);
+			if (cp == NULL || (port = permitopen_port(cp)) < 0)
+				fatal("%s: internal error: permitlisten port",
+				    __func__);
+			channel_add_permission(ssh,
+			    FORWARD_USER, FORWARD_REMOTE, host, port);
+			free(tmp);
+		}
 	}
 }
 
@@ -323,7 +339,7 @@ do_authenticated(struct ssh *ssh, Authctxt *authctxt)
 
 	/* setup the channel layer */
 	/* XXX - streamlocal? */
-	set_permitopen_from_authopts(ssh, auth_opts);
+	set_fwdpermit_from_authopts(ssh, auth_opts);
 
 	if (!auth_opts->permit_port_forwarding_flag ||
 	    options.disable_forwarding) {

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list