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