]> git.ipfire.org Git - people/ms/ipfire-3.x.git/blobdiff - openssh/patches/openssh-6.1p1-akc.patch
openssh: Update to 6.1p1.
[people/ms/ipfire-3.x.git] / openssh / patches / openssh-6.1p1-akc.patch
diff --git a/openssh/patches/openssh-6.1p1-akc.patch b/openssh/patches/openssh-6.1p1-akc.patch
new file mode 100644 (file)
index 0000000..0401ba0
--- /dev/null
@@ -0,0 +1,565 @@
+diff -up openssh-6.1p1/auth2-pubkey.c.akc openssh-6.1p1/auth2-pubkey.c
+--- openssh-6.1p1/auth2-pubkey.c.akc   2012-11-28 17:12:43.238524384 +0100
++++ openssh-6.1p1/auth2-pubkey.c       2012-11-28 17:12:43.263524297 +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/auth.c.akc openssh-6.1p1/auth.c
+--- openssh-6.1p1/auth.c.akc   2012-11-28 17:12:43.187524558 +0100
++++ openssh-6.1p1/auth.c       2012-11-28 17:12:43.263524297 +0100
+@@ -411,39 +411,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;
+@@ -479,6 +481,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-28 17:12:43.239524381 +0100
++++ openssh-6.1p1/auth.h       2012-11-28 17:12:43.263524297 +0100
+@@ -125,6 +125,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/servconf.c.akc openssh-6.1p1/servconf.c
+--- openssh-6.1p1/servconf.c.akc       2012-11-28 17:12:43.198524521 +0100
++++ openssh-6.1p1/servconf.c   2012-11-28 17:14:50.314005026 +0100
+@@ -137,6 +137,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;
+@@ -331,6 +333,7 @@ typedef enum {
+       sZeroKnowledgePasswordAuthentication, sHostCertificate,
+       sRevokedKeys, sTrustedUserCAKeys, sAuthorizedPrincipalsFile,
+       sKexAlgorithms, sIPQoS, sVersionAddendum,
++      sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
+       sAuthenticationMethods,
+       sDeprecated, sUnsupported
+ } ServerOpCodes;
+@@ -457,6 +460,9 @@ static struct {
+       { "kexalgorithms", sKexAlgorithms, SSHCFG_GLOBAL },
+       { "ipqos", sIPQoS, SSHCFG_ALL },
+       { "versionaddendum", sVersionAddendum, SSHCFG_GLOBAL },
++      { "authorizedkeyscommand", sAuthorizedKeysCommand, SSHCFG_ALL },
++      { "authorizedkeyscommandrunas", sAuthorizedKeysCommandUser, SSHCFG_ALL },
++      { "authorizedkeyscommanduser", sAuthorizedKeysCommandUser, SSHCFG_ALL },
+       { "authenticationmethods", sAuthenticationMethods, SSHCFG_ALL },
+       { NULL, sBadOption, 0 }
+ };
+@@ -1520,6 +1526,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);
+@@ -1670,6 +1696,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);
+@@ -1930,6 +1958,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-28 17:12:43.000000000 +0100
++++ openssh-6.1p1/servconf.h   2012-11-28 17:18:41.217055157 +0100
+@@ -167,6 +167,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 */
+diff -up openssh-6.1p1/sshd.c.akc openssh-6.1p1/sshd.c
+--- openssh-6.1p1/sshd.c.akc   2012-11-28 17:12:43.245524360 +0100
++++ openssh-6.1p1/sshd.c       2012-11-28 17:12:43.265524291 +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.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-28 17:12:43.265524291 +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-28 17:12:43.199524517 +0100
++++ openssh-6.1p1/sshd_config.5        2012-11-28 17:16:23.736624980 +0100
+@@ -173,6 +173,20 @@ Note that each authentication method lis
+ in the configuration.
+ The default is not to require multiple authentication; successful completion
+ of a single authentication method is sufficient.
++.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.
+@@ -734,6 +748,8 @@ Available keywords are
+ .Cm AllowTcpForwarding ,
+ .Cm AllowUsers ,
+ .Cm AuthenticationMethods ,
++.Cm AuthorizedKeysCommand ,
++.Cm AuthorizedKeysCommandUser ,
+ .Cm AuthorizedKeysFile ,
+ .Cm AuthorizedPrincipalsFile ,
+ .Cm Banner ,
+@@ -749,6 +765,7 @@ Available keywords are
+ .Cm KerberosAuthentication ,
+ .Cm MaxAuthTries ,
+ .Cm MaxSessions ,
++.Cm PubkeyAuthentication ,
+ .Cm PasswordAuthentication ,
+ .Cm PermitEmptyPasswords ,
+ .Cm PermitOpen ,
+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-28 17:12:43.265524291 +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