vishalmishra434 / rpms / openssh

Forked from rpms/openssh a month ago
Clone
bach f7f8b4
diff -up openssh-6.1p1/auth.c.akc openssh-6.1p1/auth.c
bach f7f8b4
--- openssh-6.1p1/auth.c.akc	2012-11-02 14:00:49.181077248 +0100
bach f7f8b4
+++ openssh-6.1p1/auth.c	2012-11-02 14:00:49.253077860 +0100
bach f7f8b4
@@ -413,39 +413,41 @@ check_key_in_hostfiles(struct passwd *pw
bach f7f8b4
 
bach f7f8b4
 
bach f7f8b4
 /*
bach f7f8b4
- * Check a given file for security. This is defined as all components
bach f7f8b4
+ * Check a given path for security. This is defined as all components
bach f7f8b4
  * of the path to the file must be owned by either the owner of
bach f7f8b4
  * of the file or root and no directories must be group or world writable.
bach f7f8b4
  *
bach f7f8b4
  * XXX Should any specific check be done for sym links ?
bach f7f8b4
  *
bach f7f8b4
- * Takes an open file descriptor, the file name, a uid and and
bach f7f8b4
+ * Takes an the file name, its stat information (preferably from fstat() to
bach f7f8b4
+ * avoid races), the uid of the expected owner, their home directory and an
bach f7f8b4
  * error buffer plus max size as arguments.
bach f7f8b4
  *
bach f7f8b4
  * Returns 0 on success and -1 on failure
bach f7f8b4
  */
bach f7f8b4
-static int
bach f7f8b4
-secure_filename(FILE *f, const char *file, struct passwd *pw,
bach f7f8b4
-    char *err, size_t errlen)
bach f7f8b4
+int
bach f7f8b4
+auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
bach f7f8b4
+    uid_t uid, char *err, size_t errlen)
bach f7f8b4
 {
bach f7f8b4
-	uid_t uid = pw->pw_uid;
bach f7f8b4
 	char buf[MAXPATHLEN], homedir[MAXPATHLEN];
bach f7f8b4
 	char *cp;
bach f7f8b4
 	int comparehome = 0;
bach f7f8b4
 	struct stat st;
bach f7f8b4
 
bach f7f8b4
-	if (realpath(file, buf) == NULL) {
bach f7f8b4
-		snprintf(err, errlen, "realpath %s failed: %s", file,
bach f7f8b4
+	if (realpath(name, buf) == NULL) {
bach f7f8b4
+		snprintf(err, errlen, "realpath %s failed: %s", name,
bach f7f8b4
 		    strerror(errno));
bach f7f8b4
 		return -1;
bach f7f8b4
 	}
bach f7f8b4
-	if (realpath(pw->pw_dir, homedir) != NULL)
bach f7f8b4
+	if (pw_dir != NULL && realpath(pw_dir, homedir) != NULL)
bach f7f8b4
 		comparehome = 1;
bach f7f8b4
 
bach f7f8b4
-	/* check the open file to avoid races */
bach f7f8b4
-	if (fstat(fileno(f), &st) < 0 ||
bach f7f8b4
-	    (st.st_uid != 0 && st.st_uid != uid) ||
bach f7f8b4
-	    (st.st_mode & 022) != 0) {
bach f7f8b4
+	if (!S_ISREG(stp->st_mode)) {
bach f7f8b4
+		snprintf(err, errlen, "%s is not a regular file", buf);
bach f7f8b4
+		return -1;
bach f7f8b4
+	}
bach f7f8b4
+	if ((stp->st_uid != 0 && stp->st_uid != uid) ||
bach f7f8b4
+	    (stp->st_mode & 022) != 0) {
bach f7f8b4
 		snprintf(err, errlen, "bad ownership or modes for file %s",
bach f7f8b4
 		    buf);
bach f7f8b4
 		return -1;
bach f7f8b4
@@ -481,6 +483,31 @@ secure_filename(FILE *f, const char *fil
bach f7f8b4
 	return 0;
bach f7f8b4
 }
bach f7f8b4
 
bach f7f8b4
+/*
bach f7f8b4
+ * Version of secure_path() that accepts an open file descriptor to
bach f7f8b4
+ * avoid races.
bach f7f8b4
+ *
bach f7f8b4
+ * Returns 0 on success and -1 on failure
bach f7f8b4
+ */
bach f7f8b4
+static int
bach f7f8b4
+secure_filename(FILE *f, const char *file, struct passwd *pw,
bach f7f8b4
+    char *err, size_t errlen)
bach f7f8b4
+{
bach f7f8b4
+	uid_t uid = pw->pw_uid;
bach f7f8b4
+	char buf[MAXPATHLEN], homedir[MAXPATHLEN];
bach f7f8b4
+	char *cp;
bach f7f8b4
+	int comparehome = 0;
bach f7f8b4
+	struct stat st;
bach f7f8b4
+
bach f7f8b4
+	/* check the open file to avoid races */
bach f7f8b4
+	if (fstat(fileno(f), &st) < 0) {
bach f7f8b4
+		snprintf(err, errlen, "cannot stat file %s: %s",
bach f7f8b4
+		    buf, strerror(errno));
bach f7f8b4
+		return -1;
bach f7f8b4
+	}
bach f7f8b4
+	return auth_secure_path(file, &st, pw->pw_dir, pw->pw_uid, err, errlen);
bach f7f8b4
+}
bach f7f8b4
+
bach f7f8b4
 static FILE *
bach f7f8b4
 auth_openfile(const char *file, struct passwd *pw, int strict_modes,
bach f7f8b4
     int log_missing, char *file_type)
bach f7f8b4
diff -up openssh-6.1p1/auth.h.akc openssh-6.1p1/auth.h
bach f7f8b4
--- openssh-6.1p1/auth.h.akc	2012-11-02 14:00:49.239077742 +0100
bach f7f8b4
+++ openssh-6.1p1/auth.h	2012-11-02 14:00:49.253077860 +0100
bach f7f8b4
@@ -123,6 +123,10 @@ int	 auth_rhosts_rsa_key_allowed(struct
bach f7f8b4
 int	 hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
bach f7f8b4
 int	 user_key_allowed(struct passwd *, Key *);
bach f7f8b4
 
bach f7f8b4
+struct stat;
bach f7f8b4
+int	 auth_secure_path(const char *, struct stat *, const char *, uid_t,
bach f7f8b4
+    char *, size_t);
bach f7f8b4
+
bach f7f8b4
 #ifdef KRB5
bach f7f8b4
 int	auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *);
bach f7f8b4
 int	auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt);
Petr Lautrbach 9fe1af
diff -up openssh-6.1p1/auth2-pubkey.c.akc openssh-6.1p1/auth2-pubkey.c
bach f7f8b4
--- openssh-6.1p1/auth2-pubkey.c.akc	2012-11-02 14:00:49.241077758 +0100
bach f7f8b4
+++ openssh-6.1p1/auth2-pubkey.c	2012-11-02 14:00:49.252077852 +0100
bach f7f8b4
@@ -27,9 +27,13 @@
Jan F. Chadima 69dd72
 
Jan F. Chadima 69dd72
 #include <sys/types.h>
Jan F. Chadima 69dd72
 #include <sys/stat.h>
Jan F. Chadima 69dd72
+#include <sys/wait.h>
Jan F. Chadima 69dd72
 
bach f7f8b4
+#include <errno.h>
Jan F. Chadima 69dd72
 #include <fcntl.h>
bach f7f8b4
+#include <paths.h>
Jan F. Chadima 69dd72
 #include <pwd.h>
bach f7f8b4
+#include <signal.h>
bach f7f8b4
 #include <stdio.h>
bach f7f8b4
 #include <stdarg.h>
bach f7f8b4
 #include <string.h>
bach f7f8b4
@@ -260,7 +264,7 @@ match_principals_file(char *file, struct
bach f7f8b4
 			if (strcmp(cp, cert->principals[i]) == 0) {
bach f7f8b4
 				debug3("matched principal \"%.100s\" "
bach f7f8b4
 				    "from file \"%s\" on line %lu",
bach f7f8b4
-			    	    cert->principals[i], file, linenum);
bach f7f8b4
+				    cert->principals[i], file, linenum);
bach f7f8b4
 				if (auth_parse_options(pw, line_opts,
bach f7f8b4
 				    file, linenum) != 1)
bach f7f8b4
 					continue;
bach f7f8b4
@@ -273,31 +277,22 @@ match_principals_file(char *file, struct
bach f7f8b4
 	fclose(f);
bach f7f8b4
 	restore_uid();
bach f7f8b4
 	return 0;
bach f7f8b4
-}	
bach f7f8b4
+}
Jan F. Chadima 69dd72
 
bach f7f8b4
-/* return 1 if user allows given key */
bach f7f8b4
+/*
bach f7f8b4
+ * Checks whether key is allowed in authorized_keys-format file,
bach f7f8b4
+ * returns 1 if the key is allowed or 0 otherwise.
bach f7f8b4
+ */
Jan F. Chadima 69dd72
 static int
Jan F. Chadima 69dd72
-user_key_allowed2(struct passwd *pw, Key *key, char *file)
bach f7f8b4
+check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw)
Jan F. Chadima 69dd72
 {
Jan F. Chadima 69dd72
 	char line[SSH_MAX_PUBKEY_BYTES];
Jan F. Chadima 69dd72
 	const char *reason;
Jan F. Chadima 69dd72
 	int found_key = 0;
Jan F. Chadima 69dd72
-	FILE *f;
Jan F. Chadima 69dd72
 	u_long linenum = 0;
Jan F. Chadima 69dd72
 	Key *found;
Jan F. Chadima 69dd72
 	char *fp;
Jan F. Chadima 69dd72
 
Jan F. Chadima 69dd72
-	/* Temporarily use the user's uid. */
Jan F. Chadima 69dd72
-	temporarily_use_uid(pw);
Jan F. Chadima 69dd72
-
Jan F. Chadima 69dd72
-	debug("trying public key file %s", file);
Jan F. Chadima 69dd72
-	f = auth_openkeyfile(file, pw, options.strict_modes);
Jan F. Chadima 69dd72
-
Jan F. Chadima 69dd72
-	if (!f) {
Jan F. Chadima 69dd72
-		restore_uid();
Jan F. Chadima 69dd72
-		return 0;
Jan F. Chadima 69dd72
-	}
Jan F. Chadima 69dd72
-
Jan F. Chadima 69dd72
 	found_key = 0;
Jan F. Chadima 69dd72
 	found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type);
Jan F. Chadima 69dd72
 
bach f7f8b4
@@ -390,8 +385,6 @@ user_key_allowed2(struct passwd *pw, Key
Jan F. Chadima 69dd72
 			break;
Jan F. Chadima 69dd72
 		}
Jan F. Chadima 69dd72
 	}
Jan F. Chadima 69dd72
-	restore_uid();
Jan F. Chadima 69dd72
-	fclose(f);
Jan F. Chadima 69dd72
 	key_free(found);
Jan F. Chadima 69dd72
 	if (!found_key)
Jan F. Chadima 69dd72
 		debug2("key not found");
bach f7f8b4
@@ -453,7 +446,173 @@ user_cert_trusted_ca(struct passwd *pw,
Jan F. Chadima 69dd72
 	return ret;
Jan F. Chadima 69dd72
 }
Jan F. Chadima 69dd72
 
Jan F. Chadima 69dd72
-/* check whether given key is in .ssh/authorized_keys* */
bach f7f8b4
+/*
bach f7f8b4
+ * Checks whether key is allowed in file.
bach f7f8b4
+ * returns 1 if the key is allowed or 0 otherwise.
bach f7f8b4
+ */
Jan F. Chadima 69dd72
+static int
Jan F. Chadima 69dd72
+user_key_allowed2(struct passwd *pw, Key *key, char *file)
Jan F. Chadima 69dd72
+{
Jan F. Chadima 69dd72
+	FILE *f;
Jan F. Chadima 69dd72
+	int found_key = 0;
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
+	/* Temporarily use the user's uid. */
Jan F. Chadima 69dd72
+	temporarily_use_uid(pw);
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
+	debug("trying public key file %s", file);
bach f7f8b4
+	if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) {
bach f7f8b4
+		found_key = check_authkeys_file(f, file, key, pw);
Jan F. Chadima 69dd72
+		fclose(f);
Jan F. Chadima 69dd72
+	}
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
+	restore_uid();
Jan F. Chadima 69dd72
+	return found_key;
Jan F. Chadima 69dd72
+}
Jan F. Chadima 69dd72
+
bach f7f8b4
+/*
bach f7f8b4
+ * Checks whether key is allowed in output of command.
bach f7f8b4
+ * returns 1 if the key is allowed or 0 otherwise.
bach f7f8b4
+ */
Jan F. Chadima 69dd72
+static int
bach f7f8b4
+user_key_command_allowed2(struct passwd *user_pw, Key *key)
Jan F. Chadima 69dd72
+{
Jan F. Chadima 69dd72
+	FILE *f;
bach f7f8b4
+	int ok, found_key = 0;
bach f7f8b4
+	struct passwd *pw;
Jan F. Chadima 69dd72
+	struct stat st;
bach f7f8b4
+	int status, devnull, p[2], i;
bach f7f8b4
+	pid_t pid;
bach f7f8b4
+	char errmsg[512];
Jan F. Chadima 69dd72
+
bach f7f8b4
+	if (options.authorized_keys_command == NULL ||
bach f7f8b4
+	    options.authorized_keys_command[0] != '/')
Jan F. Chadima 1df0cf
+		return 0;
Jan F. Chadima 69dd72
+
bach f7f8b4
+	/* If no user specified to run commands the default to target user */
bach f7f8b4
+	if (options.authorized_keys_command_user == NULL)
bach f7f8b4
+		pw = user_pw;
bach f7f8b4
+	else {
bach f7f8b4
+		pw = getpwnam(options.authorized_keys_command_user);
bach f7f8b4
+		if (pw == NULL) {
bach f7f8b4
+			error("AuthorizedKeyCommandUser \"%s\" not found: %s",
bach f7f8b4
+			    options.authorized_keys_command, strerror(errno));
bach f7f8b4
+			return 0;
bach f7f8b4
+		}
Jan F. Chadima 69dd72
+	}
Jan F. Chadima 69dd72
+
bach f7f8b4
+	temporarily_use_uid(pw);
bach f7f8b4
+	if (stat(options.authorized_keys_command, &st) < 0) {
bach f7f8b4
+		error("Could not stat AuthorizedKeysCommand \"%s\": %s",
bach f7f8b4
+		    options.authorized_keys_command, strerror(errno));
bach f7f8b4
+		goto out;
Jan F. Chadima 69dd72
+	}
Jan F. Chadima 69dd72
+
bach f7f8b4
+	if (auth_secure_path(options.authorized_keys_command, &st, NULL, 0,
bach f7f8b4
+	    errmsg, sizeof(errmsg)) != 0) {
bach f7f8b4
+		error("Unsafe AuthorizedKeysCommand: %s", errmsg);
bach f7f8b4
+		goto out;
Jan F. Chadima 69dd72
+	}
Jan F. Chadima 69dd72
+
bach f7f8b4
+	/* open the pipe and read the keys */
bach f7f8b4
+	if (pipe(p) != 0) {
bach f7f8b4
+		error("%s: pipe: %s", __func__, strerror(errno));
bach f7f8b4
+		goto out;
bach f7f8b4
+ 	}
bach f7f8b4
+
bach f7f8b4
+	debug3("Running AuthorizedKeysCommand: \"%s\" as \"%s\"",
bach f7f8b4
+	    options.authorized_keys_command, pw->pw_name);
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
+	/*
bach f7f8b4
+	 * Don't want to call this in the child, where it can fatal() and
bach f7f8b4
+	 * run cleanup_exit() code.
Jan F. Chadima 69dd72
+	 */
bach f7f8b4
+	restore_uid();
Jan F. Chadima 69dd72
+
bach f7f8b4
+	switch ((pid = fork())) {
bach f7f8b4
+	case -1: /* error */
bach f7f8b4
+		error("%s: fork: %s", __func__, strerror(errno));
bach f7f8b4
+		close(p[0]);
bach f7f8b4
+		close(p[1]);
bach f7f8b4
+		return 0;
bach f7f8b4
+	case 0: /* child */
bach f7f8b4
+		for (i = 0; i < NSIG; i++)
bach f7f8b4
+			signal(i, SIG_DFL);
bach f7f8b4
+
bach f7f8b4
+		/* Don't use permanently_set_uid() here to avoid fatal() */
bach f7f8b4
+		if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) {
bach f7f8b4
+			error("setresgid %u: %s", (u_int)pw->pw_gid,
bach f7f8b4
+			    strerror(errno));
bach f7f8b4
+			_exit(1);
Jan F. Chadima 69dd72
+		}
bach f7f8b4
+		if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) {
bach f7f8b4
+			error("setresuid %u: %s", (u_int)pw->pw_uid,
bach f7f8b4
+			    strerror(errno));
bach f7f8b4
+			_exit(1);
Jan F. Chadima 69dd72
+		}
Jan F. Chadima 69dd72
+
bach f7f8b4
+		close(p[0]);
bach f7f8b4
+		if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) {
bach f7f8b4
+			error("%s: open %s: %s", __func__, _PATH_DEVNULL,
Jan F. Chadima 69dd72
+			    strerror(errno));
bach f7f8b4
+			_exit(1);
Jan F. Chadima 69dd72
+		}
bach f7f8b4
+		if (dup2(devnull, STDIN_FILENO) == -1 ||
bach f7f8b4
+		    dup2(p[1], STDOUT_FILENO) == -1 ||
bach f7f8b4
+		    dup2(devnull, STDERR_FILENO) == -1) {
bach f7f8b4
+			error("%s: dup2: %s", __func__, strerror(errno));
bach f7f8b4
+			_exit(1);
Jan F. Chadima 69dd72
+		}
bach f7f8b4
+		closefrom(STDERR_FILENO + 1);
Jan F. Chadima 69dd72
+
bach f7f8b4
+		execl(options.authorized_keys_command,
bach f7f8b4
+		    options.authorized_keys_command, pw->pw_name, NULL);
Jan F. Chadima 69dd72
+
bach f7f8b4
+		error("AuthorizedKeysCommand %s exec failed: %s",
bach f7f8b4
+		    options.authorized_keys_command, strerror(errno));
Jan F. Chadima 69dd72
+		_exit(127);
bach f7f8b4
+	default: /* parent */
bach f7f8b4
+		break;
Jan F. Chadima 69dd72
+	}
Jan F. Chadima 69dd72
+	
bach f7f8b4
+	temporarily_use_uid(pw);
Jan F. Chadima 69dd72
+
bach f7f8b4
+	close(p[1]);
bach f7f8b4
+	if ((f = fdopen(p[0], "r")) == NULL) {
bach f7f8b4
+		error("%s: fdopen: %s", __func__, strerror(errno));
bach f7f8b4
+		close(p[0]);
bach f7f8b4
+		/* Don't leave zombie child */
bach f7f8b4
+		while (waitpid(pid, NULL, 0) == -1 && errno == EINTR)
bach f7f8b4
+			;
bach f7f8b4
+		goto out;
bach f7f8b4
+	}
bach f7f8b4
+	ok = check_authkeys_file(f, options.authorized_keys_command, key, pw);
bach f7f8b4
+	fclose(f);
Jan F. Chadima 69dd72
+
bach f7f8b4
+	while (waitpid(pid, &status, 0) == -1) {
bach f7f8b4
+		if (errno != EINTR) {
bach f7f8b4
+			error("%s: waitpid: %s", __func__, strerror(errno));
bach f7f8b4
+			goto out;
bach f7f8b4
+		}
bach f7f8b4
+	}
bach f7f8b4
+	if (WIFSIGNALED(status)) {
bach f7f8b4
+		error("AuthorizedKeysCommand %s exited on signal %d",
bach f7f8b4
+		    options.authorized_keys_command, WTERMSIG(status));
bach f7f8b4
+		goto out;
bach f7f8b4
+	} else if (WEXITSTATUS(status) != 0) {
bach f7f8b4
+		error("AuthorizedKeysCommand %s returned status %d",
bach f7f8b4
+		    options.authorized_keys_command, WEXITSTATUS(status));
bach f7f8b4
+		goto out;
bach f7f8b4
+	}
bach f7f8b4
+	found_key = ok;
bach f7f8b4
+ out:
bach f7f8b4
+	restore_uid();
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
+	return found_key;
Jan F. Chadima 69dd72
+}
Jan F. Chadima 69dd72
+
bach f7f8b4
+/*
bach f7f8b4
+ * Check whether key authenticates and authorises the user.
bach f7f8b4
+ */
Jan F. Chadima 69dd72
 int
Jan F. Chadima 69dd72
 user_key_allowed(struct passwd *pw, Key *key)
Jan F. Chadima 69dd72
 {
bach f7f8b4
@@ -469,6 +628,10 @@ user_key_allowed(struct passwd *pw, Key
bach f7f8b4
 	if (success)
bach f7f8b4
 		return success;
Tomas Mraz fc87f2
 
bach f7f8b4
+	success = user_key_command_allowed2(pw, key);
Tomas Mraz fc87f2
+	if (success > 0)
Tomas Mraz fc87f2
+		return success;
Tomas Mraz fc87f2
+
bach f7f8b4
 	for (i = 0; !success && i < options.num_authkeys_files; i++) {
bach f7f8b4
 		file = expand_authorized_keys(
bach f7f8b4
 		    options.authorized_keys_files[i], pw);
Petr Lautrbach 9fe1af
diff -up openssh-6.1p1/servconf.c.akc openssh-6.1p1/servconf.c
bach f7f8b4
--- openssh-6.1p1/servconf.c.akc	2012-11-02 14:00:49.186077290 +0100
bach f7f8b4
+++ openssh-6.1p1/servconf.c	2012-11-02 14:26:32.086138017 +0100
Petr Lautrbach 9fe1af
@@ -139,6 +139,8 @@ initialize_server_options(ServerOptions
Jan F. Chadima 69dd72
 	options->num_permitted_opens = -1;
Jan F. Chadima 69dd72
 	options->adm_forced_command = NULL;
Jan F. Chadima 69dd72
 	options->chroot_directory = NULL;
Jan F. Chadima 69dd72
+	options->authorized_keys_command = NULL;
bach f7f8b4
+	options->authorized_keys_command_user = NULL;
Jan F. Chadima 69dd72
 	options->zero_knowledge_password_authentication = -1;
Jan F. Chadima 69dd72
 	options->revoked_keys_file = NULL;
Jan F. Chadima 69dd72
 	options->trusted_user_ca_keys = NULL;
Petr Lautrbach 9fe1af
@@ -334,6 +336,7 @@ typedef enum {
Jan F. Chadima 69dd72
 	sZeroKnowledgePasswordAuthentication, sHostCertificate,
Jan F. Chadima 69dd72
 	sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
Petr Lautrbach 9fe1af
 	sKexAlgorithms, sIPQoS, sVersionAddendum,
bach f7f8b4
+	sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
Jan F. Chadima 69dd72
 	sDeprecated, sUnsupported
Jan F. Chadima 69dd72
 } ServerOpCodes;
Jan F. Chadima 69dd72
 
bach f7f8b4
@@ -460,6 +463,9 @@ static struct {
bach f7f8b4
 	{ "requiredauthentications1", sRequiredAuthentications1, SSHCFG_ALL },
Petr Lautrbach d9e618
 	{ "requiredauthentications2", sRequiredAuthentications2, SSHCFG_ALL },
Jan F. Chadima 69dd72
 	{ "ipqos", sIPQoS, SSHCFG_ALL },
Jan F. Chadima 69dd72
+	{ "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
bach f7f8b4
+	{ "authorizedkeyscommandrunas", sAuthorizedKeysCommandUser, SSHCFG_ALL },
bach f7f8b4
+	{ "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
bach f7f8b4
 	{ "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
Jan F. Chadima 69dd72
 	{ NULL, sBadOption, 0 }
Jan F. Chadima 69dd72
 };
bach f7f8b4
@@ -1532,6 +1538,26 @@ process_server_config_line(ServerOptions
Jan F. Chadima 69dd72
 		}
Petr Lautrbach 9fe1af
 		return 0;
Jan F. Chadima 69dd72
 
Jan F. Chadima 69dd72
+	case sAuthorizedKeysCommand:
Jan F. Chadima 69dd72
+		len = strspn(cp, WHITESPACE);
bach f7f8b4
+		if (*activep && options->authorized_keys_command == NULL) {
Jan F. Chadima 69dd72
+			options->authorized_keys_command = xstrdup(cp + len);
bach f7f8b4
+			if (*options->authorized_keys_command != '/') {
bach f7f8b4
+				fatal("%.200s line %d: AuthorizedKeysCommand "
bach f7f8b4
+				    "must be an absolute path",
bach f7f8b4
+				    filename, linenum);
bach f7f8b4
+			}
bach f7f8b4
+		}
Jan F. Chadima 69dd72
+		return 0;
Jan F. Chadima 69dd72
+
bach f7f8b4
+	case sAuthorizedKeysCommandUser:
bach f7f8b4
+		charptr = &options->authorized_keys_command_user;
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
+		arg = strdelim(&cp;;
Jan F. Chadima 69dd72
+		if (*activep && *charptr == NULL)
Jan F. Chadima 69dd72
+			*charptr = xstrdup(arg);
Jan F. Chadima 69dd72
+		break;
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
 	case sDeprecated:
Jan F. Chadima 69dd72
 		logit("%s line %d: Deprecated option %s",
Jan F. Chadima 69dd72
 		    filename, linenum, arg);
bach f7f8b4
@@ -1682,6 +1708,8 @@ copy_set_server_options(ServerOptions *d
Petr Lautrbach d9e618
 	M_CP_INTOPT(hostbased_uses_name_from_packet_only);
Petr Lautrbach d9e618
 	M_CP_INTOPT(kbd_interactive_authentication);
Jan F. Chadima 69dd72
 	M_CP_INTOPT(zero_knowledge_password_authentication);
Jan F. Chadima 69dd72
+	M_CP_STROPT(authorized_keys_command);
bach f7f8b4
+	M_CP_STROPT(authorized_keys_command_user);
Jan F. Chadima 69dd72
 	M_CP_INTOPT(permit_root_login);
Jan F. Chadima 69dd72
 	M_CP_INTOPT(permit_empty_passwd);
Jan F. Chadima 69dd72
 
bach f7f8b4
@@ -1942,6 +1970,8 @@ dump_config(ServerOptions *o)
Jan F. Chadima 69dd72
 	dump_cfg_string(sAuthorizedPrincipalsFile,
Jan F. Chadima 69dd72
 	    o->authorized_principals_file);
Petr Lautrbach 9fe1af
 	dump_cfg_string(sVersionAddendum, o->version_addendum);
Jan F. Chadima 69dd72
+	dump_cfg_string(sAuthorizedKeysCommand, o->authorized_keys_command);
bach f7f8b4
+	dump_cfg_string(sAuthorizedKeysCommandUser, o->authorized_keys_command_user);
Jan F. Chadima 69dd72
 
Jan F. Chadima 69dd72
 	/* string arguments requiring a lookup */
Jan F. Chadima 69dd72
 	dump_cfg_string(sLogLevel, log_level_name(o->log_level));
Petr Lautrbach 9fe1af
diff -up openssh-6.1p1/servconf.h.akc openssh-6.1p1/servconf.h
bach f7f8b4
--- openssh-6.1p1/servconf.h.akc	2012-11-02 14:00:49.186077290 +0100
bach f7f8b4
+++ openssh-6.1p1/servconf.h	2012-11-02 14:00:49.254077869 +0100
Petr Lautrbach d9e618
@@ -169,6 +169,8 @@ typedef struct {
Jan F. Chadima 69dd72
 	char   *revoked_keys_file;
Jan F. Chadima 69dd72
 	char   *trusted_user_ca_keys;
Jan F. Chadima 69dd72
 	char   *authorized_principals_file;
Jan F. Chadima 69dd72
+	char   *authorized_keys_command;
bach f7f8b4
+	char   *authorized_keys_command_user;
Jan F. Chadima 69dd72
 
Petr Lautrbach 9fe1af
 	char   *version_addendum;	/* Appended to SSH banner */
Petr Lautrbach 9fe1af
 }       ServerOptions;
bach f7f8b4
diff -up openssh-6.1p1/sshd.c.akc openssh-6.1p1/sshd.c
bach f7f8b4
--- openssh-6.1p1/sshd.c.akc	2012-11-02 14:00:49.249077826 +0100
bach f7f8b4
+++ openssh-6.1p1/sshd.c	2012-11-02 14:00:49.254077869 +0100
bach f7f8b4
@@ -366,9 +366,20 @@ main_sigchld_handler(int sig)
bach f7f8b4
 static void
bach f7f8b4
 grace_alarm_handler(int sig)
bach f7f8b4
 {
bach f7f8b4
+	pid_t pgid;
bach f7f8b4
+
bach f7f8b4
 	if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0)
bach f7f8b4
 		kill(pmonitor->m_pid, SIGALRM);
bach f7f8b4
 
bach f7f8b4
+	/*
bach f7f8b4
+	 * Try to kill any processes that we have spawned, E.g. authorized
bach f7f8b4
+	 * keys command helpers.
bach f7f8b4
+	 */
bach f7f8b4
+	if ((pgid = getpgid(0)) == getpid()) {
bach f7f8b4
+		signal(SIGTERM, SIG_IGN);
bach f7f8b4
+		killpg(pgid, SIGTERM);
bach f7f8b4
+	}
bach f7f8b4
+
bach f7f8b4
 	/* Log error and exit. */
bach f7f8b4
 	sigdie("Timeout before authentication for %s", get_remote_ipaddr());
bach f7f8b4
 }
Petr Lautrbach 9fe1af
diff -up openssh-6.1p1/sshd_config.akc openssh-6.1p1/sshd_config
Petr Lautrbach 9fe1af
--- openssh-6.1p1/sshd_config.akc	2012-07-31 04:21:34.000000000 +0200
bach f7f8b4
+++ openssh-6.1p1/sshd_config	2012-11-02 14:00:49.255077878 +0100
Petr Lautrbach d9e618
@@ -49,6 +49,9 @@
Petr Lautrbach d9e618
 # but this is overridden so installations will only check .ssh/authorized_keys
Petr Lautrbach d9e618
 AuthorizedKeysFile	.ssh/authorized_keys
Petr Lautrbach d9e618
 
Petr Lautrbach d9e618
+#AuthorizedKeysCommand none
bach f7f8b4
+#AuthorizedKeysCommandUser nobody
Petr Lautrbach d9e618
+
Petr Lautrbach 9fe1af
 #AuthorizedPrincipalsFile none
Petr Lautrbach 9fe1af
 
Petr Lautrbach d9e618
 # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
Petr Lautrbach 9fe1af
diff -up openssh-6.1p1/sshd_config.0.akc openssh-6.1p1/sshd_config.0
Petr Lautrbach 9fe1af
--- openssh-6.1p1/sshd_config.0.akc	2012-08-29 02:53:04.000000000 +0200
bach f7f8b4
+++ openssh-6.1p1/sshd_config.0	2012-11-02 14:00:49.255077878 +0100
Jan F. Chadima 69dd72
@@ -71,6 +71,23 @@ DESCRIPTION
Jan F. Chadima 69dd72
 
Jan F. Chadima 69dd72
              See PATTERNS in ssh_config(5) for more information on patterns.
Jan F. Chadima 69dd72
 
Jan F. Chadima 69dd72
+     AuthorizedKeysCommand
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
+             Specifies a program to be used for lookup of the user's
Jan F. Chadima 69dd72
+	     public keys.  The program will be invoked with its first
Petr Lautrbach d9e618
+	     argument the name of the user being authorized, and should produce
Petr Lautrbach d9e618
+	     on standard output AuthorizedKeys lines (see AUTHORIZED_KEYS
Jan F. Chadima 69dd72
+	     in sshd(8)).  By default (or when set to the empty string) there is no
Jan F. Chadima 69dd72
+	     AuthorizedKeysCommand run.  If the AuthorizedKeysCommand does not successfully
Jan F. Chadima 69dd72
+	     authorize the user, authorization falls through to the
Jan F. Chadima 69dd72
+	     AuthorizedKeysFile.  Note that this option has an effect
Jan F. Chadima 69dd72
+	     only with PubkeyAuthentication turned on.
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
+     AuthorizedKeysCommandRunAs
Jan F. Chadima 69dd72
+             Specifies the user under whose account the AuthorizedKeysCommand is run.
Jan F. Chadima 69dd72
+             Empty string (the default value) means the user being authorized
Jan F. Chadima 69dd72
+             is used.
Jan F. Chadima 69dd72
+
Jan F. Chadima 69dd72
      AuthorizedKeysFile
Jan F. Chadima 69dd72
              Specifies the file that contains the public keys that can be used
Jan F. Chadima 69dd72
              for user authentication.  The format is described in the
Petr Lautrbach 9fe1af
@@ -402,7 +419,8 @@ DESCRIPTION
Jan F. Chadima 69dd72
              Only a subset of keywords may be used on the lines following a
Petr Lautrbach 9fe1af
              Match keyword.  Available keywords are AcceptEnv,
Petr Lautrbach 9fe1af
              AllowAgentForwarding, AllowGroups, AllowTcpForwarding,
Petr Lautrbach 9fe1af
-             AllowUsers, AuthorizedKeysFile, AuthorizedPrincipalsFile, Banner,
Petr Lautrbach 9fe1af
+             AllowUsers, AuthorizedKeysFile, AuthorizedKeysCommand,
Petr Lautrbach 9fe1af
+             AuthorizedKeysCommandRunAs, AuthorizedPrincipalsFile, Banner,
Petr Lautrbach 9fe1af
              ChrootDirectory, DenyGroups, DenyUsers, ForceCommand,
Petr Lautrbach 9fe1af
              GatewayPorts, GSSAPIAuthentication, HostbasedAuthentication,
Jan F. Chadima 69dd72
              HostbasedUsesNameFromPacketOnly, KbdInteractiveAuthentication,
Petr Lautrbach 9fe1af
diff -up openssh-6.1p1/sshd_config.5.akc openssh-6.1p1/sshd_config.5
bach f7f8b4
--- openssh-6.1p1/sshd_config.5.akc	2012-11-02 14:00:49.187077299 +0100
bach f7f8b4
+++ openssh-6.1p1/sshd_config.5	2012-11-02 14:00:49.255077878 +0100
bach f7f8b4
@@ -151,6 +151,20 @@ See
Petr Lautrbach d9e618
 in
Petr Lautrbach d9e618
 .Xr ssh_config 5
Petr Lautrbach d9e618
 for more information on patterns.
Petr Lautrbach d9e618
+.It Cm AuthorizedKeysCommand
bach f7f8b4
+Specifies a program to be used for lookup of the user's public keys.
bach f7f8b4
+The program will be invoked with a single argument of the username
bach f7f8b4
+being authenticated, and should produce on standard output zero or
bach f7f8b4
+more lines of authorized_keys output (see AUTHORIZED_KEYS in
bach f7f8b4
+.Xr sshd 8 )
bach f7f8b4
+If a key supplied by AuthorizedKeysCommand does not successfully authenticate
bach f7f8b4
+and authorize the user then public key authentication continues using the usual
bach f7f8b4
+.Cm AuthorizedKeysFile
bach f7f8b4
+files.
bach f7f8b4
+By default, no AuthorizedKeysCommand is run.
bach f7f8b4
+.It Cm AuthorizedKeysCommandUser
bach f7f8b4
+Specifies the user under whose account the AuthorizedKeysCommand is run.
bach f7f8b4
+The default is the user being authenticated.
Petr Lautrbach d9e618
 .It Cm AuthorizedKeysFile
Petr Lautrbach d9e618
 Specifies the file that contains the public keys that can be used
Petr Lautrbach d9e618
 for user authentication.
bach f7f8b4
@@ -712,6 +726,8 @@ Available keywords are
Jan F. Chadima 69dd72
 .Cm AllowTcpForwarding ,
Petr Lautrbach 9fe1af
 .Cm AllowUsers ,
Jan F. Chadima 69dd72
 .Cm AuthorizedKeysFile ,
Jan F. Chadima 69dd72
+.Cm AuthorizedKeysCommand ,
bach f7f8b4
+.Cm AuthorizedKeysCommandUser ,
Jan F. Chadima 69dd72
 .Cm AuthorizedPrincipalsFile ,
Jan F. Chadima 69dd72
 .Cm Banner ,
Jan F. Chadima 69dd72
 .Cm ChrootDirectory ,
bach f7f8b4
@@ -726,6 +742,7 @@ Available keywords are
Jan F. Chadima 69dd72
 .Cm KerberosAuthentication ,
Jan F. Chadima 69dd72
 .Cm MaxAuthTries ,
Jan F. Chadima 69dd72
 .Cm MaxSessions ,
Jan F. Chadima 69dd72
+.Cm PubkeyAuthentication ,
Jan F. Chadima 69dd72
 .Cm PasswordAuthentication ,
Jan F. Chadima 69dd72
 .Cm PermitEmptyPasswords ,
Jan F. Chadima 69dd72
 .Cm PermitOpen ,