packages: openssh/authorized-keys-command.patch (NEW) - from https://bugzil...

glen glen at pld-linux.org
Thu Sep 29 00:07:18 CEST 2011


Author: glen                         Date: Wed Sep 28 22:07:18 2011 GMT
Module: packages                      Tag: HEAD
---- Log message:
- from https://bugzilla.mindrot.org/show_bug.cgi?id=1663#c21

---- Files affected:
packages/openssh:
   authorized-keys-command.patch (NONE -> 1.1)  (NEW)

---- Diffs:

================================================================
Index: packages/openssh/authorized-keys-command.patch
diff -u /dev/null packages/openssh/authorized-keys-command.patch:1.1
--- /dev/null	Thu Sep 29 00:07:18 2011
+++ packages/openssh/authorized-keys-command.patch	Thu Sep 29 00:07:13 2011
@@ -0,0 +1,441 @@
+--- openssh-5.9p1/auth2-pubkey.c	2011-05-29 13:39:38.000000000 +0200
++++ openssh-5.9p1/auth2-pubkey.c	2011-09-13 01:17:16.352798645 +0200
+@@ -27,6 +27,7 @@ 
+ 
+ #include <sys/types.h>
+ #include <sys/stat.h>
++#include <sys/wait.h>
+ 
+ #include <fcntl.h>
+ #include <pwd.h>
+@@ -256,27 +257,15 @@ match_principals_file(char *file, struct
+ 
+ /* return 1 if user allows given key */
+ static int
+-user_key_allowed2(struct passwd *pw, Key *key, char *file)
++user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw)
+ {
+ 	char line[SSH_MAX_PUBKEY_BYTES];
+ 	const char *reason;
+ 	int found_key = 0;
+-	FILE *f;
+ 	u_long linenum = 0;
+ 	Key *found;
+ 	char *fp;
+ 
+-	/* Temporarily use the user's uid. */
+-	temporarily_use_uid(pw);
+-
+-	debug("trying public key file %s", file);
+-	f = auth_openkeyfile(file, pw, options.strict_modes);
+-
+-	if (!f) {
+-		restore_uid();
+-		return 0;
+-	}
+-
+ 	found_key = 0;
+ 	found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
+ 
+@@ -369,8 +358,6 @@ user_key_allowed2(struct passwd *pw, Key
+ 			break;
+ 		}
+ 	}
+-	restore_uid();
+-	fclose(f);
+ 	key_free(found);
+ 	if (!found_key)
+ 		debug2("key not found");
+@@ -432,13 +419,191 @@ user_cert_trusted_ca(struct passwd *pw,
+ 	return ret;
+ }
+ 
+-/* check whether given key is in .ssh/authorized_keys* */
++/* return 1 if user allows given key */
++static int
++user_key_allowed2(struct passwd *pw, Key *key, char *file)
++{
++	FILE *f;
++	int found_key = 0;
++
++	/* Temporarily use the user's uid. */
++	temporarily_use_uid(pw);
++
++	debug("trying public key file %s", file);
++	f = auth_openkeyfile(file, pw, options.strict_modes);
++
++ 	if (f) {
++ 		found_key = user_search_key_in_file (f, file, key, pw);
++		fclose(f);
++	}
++
++	restore_uid();
++	return found_key;
++}
++
++#ifdef WITH_AUTHORIZED_KEYS_COMMAND
++
++#define WHITESPACE " \t\r\n"
++
++/* return 1 if user allows given key */
++static int
++user_key_via_command_allowed2(struct passwd *pw, Key *key)
++{
++	FILE *f;
++	int found_key = 0;
++	char *progname = NULL;
++	char *cp;
++	struct passwd *runas_pw;
++	struct stat st;
++	int childdescriptors[2], i;
++	pid_t pstat, pid, child;
++
++	if (options.authorized_keys_command == NULL || options.authorized_keys_command[0] != '/')
++		return 0;
++
++	/* get the run as identity from config */
++	runas_pw = (options.authorized_keys_command_runas == NULL)? pw
++	    : getpwnam (options.authorized_keys_command_runas);
++	if (!runas_pw) {
++		error("%s: getpwnam(\"%s\"): %s", __func__,
++		    options.authorized_keys_command_runas, strerror(errno));
++		return 0;
++	}
++
++	/* Temporarily use the specified uid. */
++	if (runas_pw->pw_uid != 0)
++		temporarily_use_uid(runas_pw);
++
++	progname = xstrdup(options.authorized_keys_command);
++
++	debug3("%s: checking program '%s'", __func__, progname);
++
++	if (stat (progname, &st) < 0) {
++		error("%s: stat(\"%s\"): %s", __func__,
++		    progname, strerror(errno));
++		goto go_away;
++	}
++
++	if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
++		error("bad ownership or modes for AuthorizedKeysCommand \"%s\"",
++		    progname);
++		goto go_away;
++	}
++
++	if (!S_ISREG(st.st_mode)) {
++		error("AuthorizedKeysCommand \"%s\" is not a regular file",
++		    progname);
++		goto go_away;
++	}
++
++	/*
++	 * Descend the path, checking that each component is a
++	 * root-owned directory with strict permissions.
++	 */
++	do {
++		if ((cp = strrchr(progname, '/')) == NULL)
++			break;
++		else 
++			*cp = '\0';
++	
++		debug3("%s: checking component '%s'", __func__, (*progname == '\0' ? "/" : progname));
++
++		if (stat((*progname == '\0' ? "/" : progname), &st) != 0) {
++			error("%s: stat(\"%s\"): %s", __func__,
++			    progname, strerror(errno));
++			goto go_away;
++		}
++		if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
++			error("bad ownership or modes for AuthorizedKeysCommand path component \"%s\"",
++			    progname);
++			goto go_away;
++		}
++		if (!S_ISDIR(st.st_mode)) {
++			error("AuthorizedKeysCommand path component \"%s\" is not a directory",
++			    progname);
++			goto go_away;
++		}
++	} while (1);
++
++	/* open the pipe and read the keys */
++	if (pipe(childdescriptors)) {
++		error("failed to pipe(2) for AuthorizedKeysCommand: %s",
++		    strerror(errno));
++		goto go_away;
++	}
++
++	child = fork();
++	if (child == -1) {
++		error("failed to fork(2) for AuthorizedKeysCommand: %s",
++		    strerror(errno));
++		goto go_away;
++	} else if (child == 0) {
++		/* we're in the child process here -- we should never return from this block. */
++		/* permanently drop privs in child process */
++		if (runas_pw->pw_uid != 0) {
++			restore_uid();
++			permanently_set_uid(runas_pw);
++	  	}
++
++		close(childdescriptors[0]);
++		/* put the write end of the pipe on stdout (FD 1) */
++		if (dup2(childdescriptors[1], 1) == -1) {
++			error("failed to dup2(2) from AuthorizedKeysCommand: %s",
++			    strerror(errno));
++			_exit(127);
++		}
++
++		debug3("about to execl() AuthorizedKeysCommand: \"%s\" \"%s\"", options.authorized_keys_command, pw->pw_name);
++		/* see session.c:child_close_fds() */
++		for (i = 3; i < 64; ++i) {
++			close(i);
++		}
++
++		execl(options.authorized_keys_command, options.authorized_keys_command, pw->pw_name, NULL);
++
++		/* if we got here, it didn't work */
++		error("failed to execl AuthorizedKeysCommand: %s", strerror(errno)); /* this won't work because we closed the fds above */
++		_exit(127);
++	}
++	
++	close(childdescriptors[1]);
++	f = fdopen(childdescriptors[0], "r");
++	if (!f) {
++		error("%s: could not buffer FDs from AuthorizedKeysCommand (\"%s\", \"r\"): %s", __func__,
++		    options.authorized_keys_command, strerror (errno));
++		goto go_away;
++	}
++
++	found_key = user_search_key_in_file (f, options.authorized_keys_command, key, pw);
++	fclose (f);
++	do {
++		pid = waitpid(child, &pstat, 0);
++	} while (pid == -1 && errno == EINTR);
++
++	/* what about the return value from the child process? */
++go_away:
++	if (progname)
++		xfree (progname);
++
++	if (runas_pw->pw_uid != 0)
++		restore_uid();
++	return found_key;
++}
++#endif
++
++/* check whether given key is in <AuthorizedKeysCommand or .ssh/authorized_keys* */
+ int
+ user_key_allowed(struct passwd *pw, Key *key)
+ {
+ 	u_int success, i;
+ 	char *file;
+ 
++#ifdef WITH_AUTHORIZED_KEYS_COMMAND
++	success = user_key_via_command_allowed2(pw, key);
++	if (success > 0)
++		return success;
++#endif
++
+ 	if (auth_key_is_revoked(key))
+ 		return 0;
+ 	if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
+--- openssh-5.9p1/configure.ac	2011-08-18 06:48:24.000000000 +0200
++++ openssh-5.9p1/configure.ac	2011-09-13 01:17:16.388769789 +0200
+@@ -1421,6 +1421,18 @@ AC_ARG_WITH([audit],
+ 	esac ]
+ )
+ 
++# Check whether user wants AuthorizedKeysCommand support
++AKC_MSG="no"
++AC_ARG_WITH(authorized-keys-command,
++	[  --with-authorized-keys-command      Enable AuthorizedKeysCommand support],
++	[
++		if test "x$withval" != "xno" ; then
++			AC_DEFINE([WITH_AUTHORIZED_KEYS_COMMAND], 1, [Enable AuthorizedKeysCommand support])
++			AKC_MSG="yes"
++		fi
++	]
++)
++
+ dnl    Checks for library functions. Please keep in alphabetical order
+ AC_CHECK_FUNCS([ \
+ 	arc4random \
+@@ -4235,6 +4247,7 @@ echo "                   SELinux support
+ echo "                 Smartcard support: $SCARD_MSG"
+ echo "                     S/KEY support: $SKEY_MSG"
+ echo "              TCP Wrappers support: $TCPW_MSG"
++echo "     AuthorizedKeysCommand support: $AKC_MSG"
+ echo "              MD5 password support: $MD5_MSG"
+ echo "                   libedit support: $LIBEDIT_MSG"
+ echo "  Solaris process contract support: $SPC_MSG"
+--- openssh-5.9p1/servconf.c	2011-06-23 00:30:03.000000000 +0200
++++ openssh-5.9p1/servconf.c	2011-09-13 01:18:27.828816240 +0200
+@@ -132,6 +132,8 @@ initialize_server_options(ServerOptions
+ 	options->num_permitted_opens = -1;
+ 	options->adm_forced_command = NULL;
+ 	options->chroot_directory = NULL;
++	options->authorized_keys_command = NULL;
++	options->authorized_keys_command_runas = NULL;
+ 	options->zero_knowledge_password_authentication = -1;
+ 	options->revoked_keys_file = NULL;
+ 	options->trusted_user_ca_keys = NULL;
+@@ -324,6 +326,7 @@ typedef enum {
+ 	sZeroKnowledgePasswordAuthentication, sHostCertificate,
+ 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
+ 	sKexAlgorithms, sIPQoS,
++	sAuthorizedKeysCommand, sAuthorizedKeysCommandRunAs,
+ 	sDeprecated, sUnsupported
+ } ServerOpCodes;
+ 
+@@ -448,6 +451,13 @@ static struct {
+ 	{ "authorizedprincipalsfile", sAuthorizedPrincipalsFile, SSHCFG_ALL },
+ 	{ "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
+ 	{ "ipqos", sIPQoS, SSHCFG_ALL },
++#ifdef WITH_AUTHORIZED_KEYS_COMMAND
++	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
++	{ "authorizedkeyscommandrunas", sAuthorizedKeysCommandRunAs, SSHCFG_ALL },
++#else
++	{ "authorizedkeyscommand", sUnsupported, SSHCFG_ALL },
++	{ "authorizedkeyscommandrunas", sUnsupported, SSHCFG_ALL },
++#endif
+ 	{ NULL, sBadOption, 0 }
+ };
+ 
+@@ -1395,6 +1405,20 @@ process_server_config_line(ServerOptions
+ 		}
+ 		break;
+ 
++	case sAuthorizedKeysCommand:
++		len = strspn(cp, WHITESPACE);
++		if (*activep && options->authorized_keys_command == NULL)
++			options->authorized_keys_command = xstrdup(cp + len);
++		return 0;
++
++	case sAuthorizedKeysCommandRunAs:
++		charptr = &options->authorized_keys_command_runas;
++
++		arg = strdelim(&cp);
++		if (*activep && *charptr == NULL)
++			*charptr = xstrdup(arg);
++		break;
++
+ 	case sDeprecated:
+ 		logit("%s line %d: Deprecated option %s",
+ 		    filename, linenum, arg);
+@@ -1499,6 +1523,8 @@ copy_set_server_options(ServerOptions *d
+ 	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
+ 	M_CP_INTOPT(kbd_interactive_authentication);
+ 	M_CP_INTOPT(zero_knowledge_password_authentication);
++	M_CP_STROPT(authorized_keys_command);
++	M_CP_STROPT(authorized_keys_command_runas);
+ 	M_CP_INTOPT(permit_root_login);
+ 	M_CP_INTOPT(permit_empty_passwd);
+ 
+@@ -1758,6 +1784,8 @@ dump_config(ServerOptions *o)
+ 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
+ 	dump_cfg_string(sAuthorizedPrincipalsFile,
+ 	    o->authorized_principals_file);
++	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
++	dump_cfg_string(sAuthorizedKeysCommandRunAs, o->authorized_keys_command_runas);
+ 
+ 	/* string arguments requiring a lookup */
+ 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
+--- openssh-5.9p1/servconf.h	2011-06-23 00:30:03.000000000 +0200
++++ openssh-5.9p1/servconf.h	2011-09-13 01:17:16.481674272 +0200
+@@ -166,6 +166,8 @@ typedef struct {
+ 	char   *revoked_keys_file;
+ 	char   *trusted_user_ca_keys;
+ 	char   *authorized_principals_file;
++	char   *authorized_keys_command;
++	char   *authorized_keys_command_runas;
+ }       ServerOptions;
+ 
+ /*
+--- openssh-5.9p1/sshd_config.0	2011-09-07 01:16:30.000000000 +0200
++++ openssh-5.9p1/sshd_config.0	2011-09-13 01:17:16.509816302 +0200
+@@ -71,6 +71,23 @@ DESCRIPTION
+ 
+              See PATTERNS in ssh_config(5) for more information on patterns.
+ 
++     AuthorizedKeysCommand
++
++             Specifies a program to be used for lookup of the user's
++	     public keys.  The program will be invoked with its first
++	     argument the name of the user being authorized, and should produce 
++	     on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS 
++	     in sshd(8)).  By default (or when set to the empty string) there is no
++	     AuthorizedKeysCommand run.  If the AuthorizedKeysCommand does not successfully
++	     authorize the user, authorization falls through to the
++	     AuthorizedKeysFile.  Note that this option has an effect
++	     only with PubkeyAuthentication turned on.
++
++     AuthorizedKeysCommandRunAs
++             Specifies the user under whose account the AuthorizedKeysCommand is run.
++             Empty string (the default value) means the user being authorized
++             is used.
++
+      AuthorizedKeysFile
+              Specifies the file that contains the public keys that can be used
+              for user authentication.  The format is described in the
+@@ -401,7 +418,8 @@ DESCRIPTION
+ 
+              Only a subset of keywords may be used on the lines following a
+              Match keyword.  Available keywords are AllowAgentForwarding,
+-             AllowTcpForwarding, AuthorizedKeysFile, AuthorizedPrincipalsFile,
++             AllowTcpForwarding, AuthorizedKeysFile, AuthorizedKeysCommand,
++             AuthorizedKeysCommandRunAs, AuthorizedPrincipalsFile,
+              Banner, ChrootDirectory, ForceCommand, GatewayPorts,
+              GSSAPIAuthentication, HostbasedAuthentication,
+              HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication,
+--- openssh-5.9p1/sshd_config.5	2011-08-05 22:17:33.000000000 +0200
++++ openssh-5.9p1/sshd_config.5	2011-09-13 01:17:16.536674498 +0200
+@@ -706,6 +706,8 @@ Available keywords are
+ .Cm AllowAgentForwarding ,
+ .Cm AllowTcpForwarding ,
+ .Cm AuthorizedKeysFile ,
++.Cm AuthorizedKeysCommand ,
++.Cm AuthorizedKeysCommandRunAs ,
+ .Cm AuthorizedPrincipalsFile ,
+ .Cm Banner ,
+ .Cm ChrootDirectory ,
+@@ -718,6 +720,7 @@ Available keywords are
+ .Cm KerberosAuthentication ,
+ .Cm MaxAuthTries ,
+ .Cm MaxSessions ,
++.Cm PubkeyAuthentication ,
+ .Cm PasswordAuthentication ,
+ .Cm PermitEmptyPasswords ,
+ .Cm PermitOpen ,
+@@ -920,6 +923,20 @@ Specifies a list of revoked public keys.
+ Keys listed in this file will be refused for public key authentication.
+ Note that if this file is not readable, then public key authentication will
+ be refused for all users.
++.It Cm AuthorizedKeysCommand
++Specifies a program to be used for lookup of the user's
++public keys.  The program will be invoked with its first
++argument the name of the user being authorized, and should produce 
++on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS 
++in sshd(8)).  By default (or when set to the empty string) there is no
++AuthorizedKeysCommand run.  If the AuthorizedKeysCommand does not successfully
++authorize the user, authorization falls through to the
++AuthorizedKeysFile.  Note that this option has an effect
++only with PubkeyAuthentication turned on.
++.It Cm AuthorizedKeysCommandRunAs
++Specifies the user under whose account the AuthorizedKeysCommand is run. Empty
++string (the default value) means the user being authorized is used.
++.Dq 
+ .It Cm RhostsRSAAuthentication
+ Specifies whether rhosts or /etc/hosts.equiv authentication together
+ with successful RSA host authentication is allowed.
+--- openssh-5.9p1/sshd_config	2011-05-29 13:39:39.000000000 +0200
++++ openssh-5.9p1/sshd_config	2011-09-13 01:17:16.555799142 +0200
+@@ -49,6 +49,9 @@ 
+ # but this is overridden so installations will only check .ssh/authorized_keys
+ AuthorizedKeysFile	.ssh/authorized_keys
+ 
++#AuthorizedKeysCommand none
++#AuthorizedKeysCommandRunAs nobody
++
+ # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
+ #RhostsRSAAuthentication no
+ # similar for protocol version 2
================================================================


More information about the pld-cvs-commit mailing list