974c89c
diff -up openssh-5.4p1/auth2-pubkey.c.pka openssh-5.4p1/auth2-pubkey.c
ef5d198
--- openssh-5.4p1/auth2-pubkey.c.pka	2010-03-09 08:01:05.000000000 +0100
ef5d198
+++ openssh-5.4p1/auth2-pubkey.c	2010-03-09 08:07:15.000000000 +0100
ef5d198
@@ -187,27 +187,15 @@ done:
201f4ac
 
201f4ac
 /* return 1 if user allows given key */
201f4ac
 static int
201f4ac
-user_key_allowed2(struct passwd *pw, Key *key, char *file)
201f4ac
+user_search_key_in_file(FILE *f, char *file, Key* key, struct passwd *pw)
201f4ac
 {
201f4ac
 	char line[SSH_MAX_PUBKEY_BYTES];
974c89c
 	const char *reason;
201f4ac
 	int found_key = 0;
201f4ac
-	FILE *f;
201f4ac
 	u_long linenum = 0;
201f4ac
 	Key *found;
201f4ac
 	char *fp;
201f4ac
 
201f4ac
-	/* Temporarily use the user's uid. */
201f4ac
-	temporarily_use_uid(pw);
201f4ac
-
201f4ac
-	debug("trying public key file %s", file);
201f4ac
-	f = auth_openkeyfile(file, pw, options.strict_modes);
201f4ac
-
201f4ac
-	if (!f) {
201f4ac
-		restore_uid();
201f4ac
-		return 0;
201f4ac
-	}
201f4ac
-
201f4ac
 	found_key = 0;
974c89c
 	found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
201f4ac
 
ef5d198
@@ -278,8 +266,6 @@ user_key_allowed2(struct passwd *pw, Key
201f4ac
 			break;
201f4ac
 		}
201f4ac
 	}
201f4ac
-	restore_uid();
201f4ac
-	fclose(f);
201f4ac
 	key_free(found);
201f4ac
 	if (!found_key)
201f4ac
 		debug2("key not found");
ef5d198
@@ -327,13 +313,153 @@ user_cert_trusted_ca(struct passwd *pw, 
ef5d198
 	return ret;
201f4ac
 }
201f4ac
 
201f4ac
-/* check whether given key is in .ssh/authorized_keys* */
201f4ac
+/* return 1 if user allows given key */
201f4ac
+static int
201f4ac
+user_key_allowed2(struct passwd *pw, Key *key, char *file)
201f4ac
+{
201f4ac
+	FILE *f;
201f4ac
+	int found_key = 0;
201f4ac
+
201f4ac
+	/* Temporarily use the user's uid. */
201f4ac
+	temporarily_use_uid(pw);
201f4ac
+
201f4ac
+	debug("trying public key file %s", file);
201f4ac
+	f = auth_openkeyfile(file, pw, options.strict_modes);
201f4ac
+
201f4ac
+ 	if (f) {
201f4ac
+ 		found_key = user_search_key_in_file (f, file, key, pw);
201f4ac
+		fclose(f);
201f4ac
+	}
201f4ac
+
201f4ac
+	restore_uid();
201f4ac
+	return found_key;
201f4ac
+}
201f4ac
+
201f4ac
+#ifdef WITH_PUBKEY_AGENT
201f4ac
+
201f4ac
+#define WHITESPACE " \t\r\n"
201f4ac
+
201f4ac
+/* return 1 if user allows given key */
201f4ac
+static int
201f4ac
+user_key_via_agent_allowed2(struct passwd *pw, Key *key)
201f4ac
+{
201f4ac
+	FILE *f;
201f4ac
+	int found_key = 0;
201f4ac
+	char *pubkey_agent_string = NULL;
201f4ac
+	char *tmp_pubkey_agent_string = NULL;
201f4ac
+	char *progname;
201f4ac
+	char *cp;
201f4ac
+	struct passwd *runas_pw;
201f4ac
+	struct stat st;
201f4ac
+
201f4ac
+	if (options.pubkey_agent == NULL || options.pubkey_agent[0] != '/')
201f4ac
+		return -1;
201f4ac
+
201f4ac
+	/* get the run as identity from config */
201f4ac
+	runas_pw = (options.pubkey_agent_runas == NULL)? pw
201f4ac
+	    : getpwnam (options.pubkey_agent_runas);
201f4ac
+	if (!runas_pw) {
201f4ac
+		error("%s: getpwnam(\"%s\"): %s", __func__,
201f4ac
+		    options.pubkey_agent_runas, strerror(errno));
201f4ac
+		return 0;
201f4ac
+	}
201f4ac
+
201f4ac
+	/* Temporarily use the specified uid. */
201f4ac
+	if (runas_pw->pw_uid != 0)
201f4ac
+		temporarily_use_uid(runas_pw);
201f4ac
+
201f4ac
+	pubkey_agent_string = percent_expand(options.pubkey_agent,
201f4ac
+	    "h", pw->pw_dir, "u", pw->pw_name, (char *)NULL);
201f4ac
+
201f4ac
+	/* Test whether agent can be modified by non root user */
201f4ac
+	tmp_pubkey_agent_string = xstrdup (pubkey_agent_string);
201f4ac
+	progname = strtok (tmp_pubkey_agent_string, WHITESPACE);
201f4ac
+
201f4ac
+	debug3("%s: checking program '%s'", __func__, progname);
201f4ac
+
201f4ac
+	if (stat (progname, &st) < 0) {
201f4ac
+		error("%s: stat(\"%s\"): %s", __func__,
201f4ac
+		    progname, strerror(errno));
201f4ac
+		goto go_away;
201f4ac
+	}
201f4ac
+
201f4ac
+	if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
201f4ac
+		error("bad ownership or modes for pubkey agent \"%s\"",
201f4ac
+		    progname);
201f4ac
+		goto go_away;
201f4ac
+	}
201f4ac
+
201f4ac
+	if (!S_ISREG(st.st_mode)) {
201f4ac
+		error("pubkey agent \"%s\" is not a regular file",
201f4ac
+		    progname);
201f4ac
+		goto go_away;
201f4ac
+	}
201f4ac
+
201f4ac
+	/*
201f4ac
+	 * Descend the path, checking that each component is a
201f4ac
+	 * root-owned directory with strict permissions.
201f4ac
+	 */
201f4ac
+	do {
201f4ac
+		if ((cp = strrchr(progname, '/')) == NULL)
201f4ac
+			break;
201f4ac
+		else 
201f4ac
+			*cp = '\0';
201f4ac
+	
201f4ac
+		debug3("%s: checking component '%s'", __func__, progname);
201f4ac
+
201f4ac
+		if (stat(progname, &st) != 0) {
201f4ac
+			error("%s: stat(\"%s\"): %s", __func__,
201f4ac
+			    progname, strerror(errno));
201f4ac
+			goto go_away;
201f4ac
+		}
201f4ac
+		if (st.st_uid != 0 || (st.st_mode & 022) != 0) {
201f4ac
+			error("bad ownership or modes for pubkey agent path component \"%s\"",
201f4ac
+			    progname);
201f4ac
+			goto go_away;
201f4ac
+		}
201f4ac
+		if (!S_ISDIR(st.st_mode)) {
201f4ac
+			error("pubkey agent path component \"%s\" is not a directory",
201f4ac
+			    progname);
201f4ac
+			goto go_away;
201f4ac
+		}
201f4ac
+	} while (0);
201f4ac
+
201f4ac
+	/* open the pipe and read the keys */
201f4ac
+	f = popen (pubkey_agent_string, "r");
201f4ac
+	if (!f) {
201f4ac
+		error("%s: popen (\"%s\", \"r\"): %s", __func__,
201f4ac
+		    pubkey_agent_string, strerror (errno));
201f4ac
+		goto go_away;
201f4ac
+	}
201f4ac
+
201f4ac
+	found_key = user_search_key_in_file (f, options.pubkey_agent, key, pw);
201f4ac
+	pclose (f);
201f4ac
+
201f4ac
+go_away:
201f4ac
+	if (tmp_pubkey_agent_string)
201f4ac
+		xfree (tmp_pubkey_agent_string);
201f4ac
+	if (pubkey_agent_string)
201f4ac
+		xfree (pubkey_agent_string);
201f4ac
+
201f4ac
+	if (runas_pw->pw_uid != 0)
201f4ac
+		restore_uid();
201f4ac
+	return found_key;
201f4ac
+}
201f4ac
+#endif
201f4ac
+
201f4ac
+/* check whether given key is in 
201f4ac
 int
201f4ac
 user_key_allowed(struct passwd *pw, Key *key)
201f4ac
 {
201f4ac
 	int success;
201f4ac
 	char *file;
201f4ac
 
201f4ac
+#ifdef WITH_PUBKEY_AGENT
201f4ac
+	success = user_key_via_agent_allowed2(pw, key);
201f4ac
+	if (success >= 0)
201f4ac
+		return success;
201f4ac
+#endif
201f4ac
+
ef5d198
 	if (auth_key_is_revoked(key))
ef5d198
 		return 0;
ef5d198
 	if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key))
974c89c
diff -up openssh-5.4p1/configure.ac.pka openssh-5.4p1/configure.ac
ef5d198
--- openssh-5.4p1/configure.ac.pka	2010-03-09 08:01:04.000000000 +0100
ef5d198
+++ openssh-5.4p1/configure.ac	2010-03-09 08:01:05.000000000 +0100
974c89c
@@ -1323,6 +1323,18 @@ AC_ARG_WITH(audit,
9051e57
 	esac ]
9051e57
 )
9051e57
 
9051e57
+# Check whether user wants pubkey agent support
9051e57
+PKA_MSG="no"
9051e57
+AC_ARG_WITH(pka,
9051e57
+	[  --with-pka      Enable pubkey agent support],
9051e57
+	[
9051e57
+		if test "x$withval" != "xno" ; then
9051e57
+			AC_DEFINE([WITH_PUBKEY_AGENT], 1, [Enable pubkey agent support])
9051e57
+			PKA_MSG="yes"
9051e57
+		fi
9051e57
+	]
9051e57
+)
9051e57
+
9051e57
 dnl    Checks for library functions. Please keep in alphabetical order
9051e57
 AC_CHECK_FUNCS( \
9051e57
 	arc4random \
974c89c
@@ -4206,6 +4218,7 @@ echo "               Linux audit support
9051e57
 echo "                 Smartcard support: $SCARD_MSG"
9051e57
 echo "                     S/KEY support: $SKEY_MSG"
9051e57
 echo "              TCP Wrappers support: $TCPW_MSG"
9051e57
+echo "                       PKA support: $PKA_MSG"
9051e57
 echo "              MD5 password support: $MD5_MSG"
9051e57
 echo "                   libedit support: $LIBEDIT_MSG"
9051e57
 echo "  Solaris process contract support: $SPC_MSG"
974c89c
diff -up openssh-5.4p1/servconf.c.pka openssh-5.4p1/servconf.c
ef5d198
--- openssh-5.4p1/servconf.c.pka	2010-03-09 08:01:04.000000000 +0100
ef5d198
+++ openssh-5.4p1/servconf.c	2010-03-09 09:04:57.000000000 +0100
974c89c
@@ -129,6 +129,8 @@ initialize_server_options(ServerOptions 
201f4ac
 	options->num_permitted_opens = -1;
201f4ac
 	options->adm_forced_command = NULL;
201f4ac
 	options->chroot_directory = NULL;
201f4ac
+	options->pubkey_agent = NULL;
201f4ac
+	options->pubkey_agent_runas = NULL;
201f4ac
 	options->zero_knowledge_password_authentication = -1;
ef5d198
 	options->revoked_keys_file = NULL;
ef5d198
 	options->trusted_user_ca_keys = NULL;
ef5d198
@@ -315,6 +317,7 @@ typedef enum {
201f4ac
 	sUsePrivilegeSeparation, sAllowAgentForwarding,
974c89c
 	sZeroKnowledgePasswordAuthentication, sHostCertificate,
ef5d198
 	sRevokedKeys, sTrustedUserCAKeys,
201f4ac
+	sPubkeyAgent, sPubkeyAgentRunAs,
201f4ac
 	sDeprecated, sUnsupported
201f4ac
 } ServerOpCodes;
201f4ac
 
ef5d198
@@ -437,6 +440,13 @@ static struct {
974c89c
 	{ "hostcertificate", sHostCertificate, SSHCFG_GLOBAL },
ef5d198
 	{ "revokedkeys", sRevokedKeys, SSHCFG_ALL },
ef5d198
 	{ "trustedusercakeys", sTrustedUserCAKeys, SSHCFG_ALL },
201f4ac
+#ifdef WITH_PUBKEY_AGENT
201f4ac
+	{ "pubkeyagent", sPubkeyAgent, SSHCFG_ALL },
201f4ac
+	{ "pubkeyagentrunas", sPubkeyAgentRunAs, SSHCFG_ALL },
201f4ac
+#else
201f4ac
+	{ "pubkeyagent", sUnsupported, SSHCFG_ALL },
201f4ac
+	{ "pubkeyagentrunas", sUnsupported, SSHCFG_ALL },
201f4ac
+#endif
201f4ac
 	{ NULL, sBadOption, 0 }
201f4ac
 };
201f4ac
 
ef5d198
@@ -1345,6 +1355,20 @@ process_server_config_line(ServerOptions
ef5d198
 		charptr = &options->revoked_keys_file;
ef5d198
 		goto parse_filename;
201f4ac
 
201f4ac
+	case sPubkeyAgent:
201f4ac
+		len = strspn(cp, WHITESPACE);
201f4ac
+		if (*activep && options->pubkey_agent == NULL)
201f4ac
+			options->pubkey_agent = xstrdup(cp + len);
201f4ac
+		return 0;
201f4ac
+
201f4ac
+	case sPubkeyAgentRunAs:
201f4ac
+		charptr = &options->pubkey_agent_runas;
9051e57
+
9051e57
+		arg = strdelim(&cp;;
9051e57
+		if (*activep && *charptr == NULL)
9051e57
+			*charptr = xstrdup(arg);
201f4ac
+		break;
201f4ac
+
201f4ac
 	case sDeprecated:
201f4ac
 		logit("%s line %d: Deprecated option %s",
201f4ac
 		    filename, linenum, arg);
ef5d198
@@ -1438,6 +1462,8 @@ copy_set_server_options(ServerOptions *d
201f4ac
 	M_CP_INTOPT(gss_authentication);
201f4ac
 	M_CP_INTOPT(rsa_authentication);
201f4ac
 	M_CP_INTOPT(pubkey_authentication);
201f4ac
+	M_CP_STROPT(pubkey_agent);
201f4ac
+	M_CP_STROPT(pubkey_agent_runas);
201f4ac
 	M_CP_INTOPT(kerberos_authentication);
201f4ac
 	M_CP_INTOPT(hostbased_authentication);
201f4ac
 	M_CP_INTOPT(kbd_interactive_authentication);
ef5d198
@@ -1683,6 +1709,8 @@ dump_config(ServerOptions *o)
974c89c
 	dump_cfg_string(sChrootDirectory, o->chroot_directory);
ef5d198
 	dump_cfg_string(sTrustedUserCAKeys, o->trusted_user_ca_keys);
ef5d198
 	dump_cfg_string(sRevokedKeys, o->revoked_keys_file);
201f4ac
+	dump_cfg_string(sPubkeyAgent, o->pubkey_agent);
201f4ac
+	dump_cfg_string(sPubkeyAgentRunAs, o->pubkey_agent_runas);
201f4ac
 
201f4ac
 	/* string arguments requiring a lookup */
201f4ac
 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
974c89c
diff -up openssh-5.4p1/servconf.h.pka openssh-5.4p1/servconf.h
ef5d198
--- openssh-5.4p1/servconf.h.pka	2010-03-09 08:01:04.000000000 +0100
ef5d198
+++ openssh-5.4p1/servconf.h	2010-03-09 09:05:29.000000000 +0100
ef5d198
@@ -157,6 +157,8 @@ typedef struct {
201f4ac
 	char   *chroot_directory;
ef5d198
 	char   *revoked_keys_file;
ef5d198
 	char   *trusted_user_ca_keys;
201f4ac
+	char   *pubkey_agent;
201f4ac
+	char   *pubkey_agent_runas;
201f4ac
 }       ServerOptions;
201f4ac
 
201f4ac
 void	 initialize_server_options(ServerOptions *);
974c89c
diff -up openssh-5.4p1/sshd_config.0.pka openssh-5.4p1/sshd_config.0
ef5d198
--- openssh-5.4p1/sshd_config.0.pka	2010-03-09 08:01:04.000000000 +0100
ef5d198
+++ openssh-5.4p1/sshd_config.0	2010-03-09 09:07:35.000000000 +0100
974c89c
@@ -352,7 +352,8 @@ DESCRIPTION
201f4ac
              KbdInteractiveAuthentication, KerberosAuthentication,
974c89c
              MaxAuthTries, MaxSessions, PasswordAuthentication,
974c89c
              PermitEmptyPasswords, PermitOpen, PermitRootLogin,
974c89c
-             PubkeyAuthentication, RhostsRSAAuthentication, RSAAuthentication,
974c89c
+             PubkeyAuthentication, PubkeyAgent, PubkeyAgentRunAs,
974c89c
+             RhostsRSAAuthentication, RSAAuthentication,
974c89c
              X11DisplayOffset, X11Forwarding and X11UseLocalHost.
201f4ac
 
201f4ac
      MaxAuthTries
ef5d198
@@ -467,6 +468,17 @@ DESCRIPTION
ef5d198
              this file is not readable, then public key authentication will be
ef5d198
              refused for all users.
201f4ac
 
201f4ac
+     PubkeyAgent
201f4ac
+             Specifies which agent is used for lookup of the user's public
201f4ac
+             keys. Empty string means to use the authorized_keys file.  By
201f4ac
+             default there is no PubkeyAgent set.  Note that this option has
201f4ac
+             an effect only with PubkeyAuthentication switched on.
201f4ac
+
201f4ac
+     PubkeyAgentRunAs
201f4ac
+             Specifies the user under whose account the PubkeyAgent is run.
201f4ac
+             Empty string (the default value) means the user being authorized
201f4ac
+             is used.
201f4ac
+
201f4ac
      RhostsRSAAuthentication
201f4ac
              Specifies whether rhosts or /etc/hosts.equiv authentication to-
201f4ac
              gether with successful RSA host authentication is allowed.  The
974c89c
diff -up openssh-5.4p1/sshd_config.5.pka openssh-5.4p1/sshd_config.5
ef5d198
--- openssh-5.4p1/sshd_config.5.pka	2010-03-09 08:01:04.000000000 +0100
ef5d198
+++ openssh-5.4p1/sshd_config.5	2010-03-09 09:06:40.000000000 +0100
974c89c
@@ -618,6 +618,9 @@ Available keywords are
201f4ac
 .Cm KerberosAuthentication ,
201f4ac
 .Cm MaxAuthTries ,
201f4ac
 .Cm MaxSessions ,
201f4ac
+.Cm PubkeyAuthentication ,
201f4ac
+.Cm PubkeyAgent ,
201f4ac
+.Cm PubkeyAgentRunAs ,
201f4ac
 .Cm PasswordAuthentication ,
201f4ac
 .Cm PermitEmptyPasswords ,
201f4ac
 .Cm PermitOpen ,
ef5d198
@@ -819,6 +822,16 @@ Specifies a list of revoked public keys.
ef5d198
 Keys listed in this file will be refused for public key authentication.
ef5d198
 Note that if this file is not readable, then public key authentication will
ef5d198
 be refused for all users.
ef5d198
++.It Cm PubkeyAgent
ef5d198
++Specifies which agent is used for lookup of the user's public
ef5d198
++keys. Empty string means to use the authorized_keys file.
ef5d198
++By default there is no PubkeyAgent set.
ef5d198
++Note that this option has an effect only with PubkeyAuthentication
ef5d198
++switched on.
ef5d198
++.It Cm PubkeyAgentRunAs
ef5d198
++Specifies the user under whose account the PubkeyAgent is run. Empty
ef5d198
++string (the default value) means the user being authorized is used.
ef5d198
++.Dq 
201f4ac
 .It Cm RhostsRSAAuthentication
201f4ac
 Specifies whether rhosts or /etc/hosts.equiv authentication together
201f4ac
 with successful RSA host authentication is allowed.
974c89c
diff -up openssh-5.4p1/sshd_config.pka openssh-5.4p1/sshd_config
ef5d198
--- openssh-5.4p1/sshd_config.pka	2010-03-09 08:01:04.000000000 +0100
ef5d198
+++ openssh-5.4p1/sshd_config	2010-03-09 08:01:06.000000000 +0100
974c89c
@@ -45,6 +45,8 @@ SyslogFacility AUTHPRIV
974c89c
 #RSAAuthentication yes
974c89c
 #PubkeyAuthentication yes
974c89c
 #AuthorizedKeysFile	.ssh/authorized_keys
974c89c
+#PubkeyAgent none
974c89c
+#PubkeyAgentRunAs nobody
974c89c
 
974c89c
 # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
974c89c
 #RhostsRSAAuthentication no