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