The branch main has been updated by emaste:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=4d3fc8b0570b29fb0d6ee9525f104d52176ff0d4

commit 4d3fc8b0570b29fb0d6ee9525f104d52176ff0d4
Merge: 7d0b91591966 36b354d74be5
Author:     Ed Maste <[email protected]>
AuthorDate: 2023-03-16 14:29:55 +0000
Commit:     Ed Maste <[email protected]>
CommitDate: 2023-03-16 14:29:55 +0000

    ssh: Update to OpenSSH 9.3p1
    
    This release fixes a number of security bugs and has minor new
    features and bug fixes.  Security fixes, from the release notes
    (https://www.openssh.com/txt/release-9.3):
    
    This release contains fixes for a security problem and a memory
    safety problem. The memory safety problem is not believed to be
    exploitable, but we report most network-reachable memory faults as
    security bugs.
    
     * ssh-add(1): when adding smartcard keys to ssh-agent(1) with the
       per-hop destination constraints (ssh-add -h ...) added in OpenSSH
       8.9, a logic error prevented the constraints from being
       communicated to the agent. This resulted in the keys being added
       without constraints. The common cases of non-smartcard keys and
       keys without destination constraints are unaffected. This problem
       was reported by Luci Stanescu.
    
     * ssh(1): Portable OpenSSH provides an implementation of the
       getrrsetbyname(3) function if the standard library does not
       provide it, for use by the VerifyHostKeyDNS feature. A
       specifically crafted DNS response could cause this function to
       perform an out-of-bounds read of adjacent stack data, but this
       condition does not appear to be exploitable beyond denial-of-
       service to the ssh(1) client.
    
       The getrrsetbyname(3) replacement is only included if the system's
       standard library lacks this function and portable OpenSSH was not
       compiled with the ldns library (--with-ldns). getrrsetbyname(3) is
       only invoked if using VerifyHostKeyDNS to fetch SSHFP records. This
       problem was found by the Coverity static analyzer.
    
    Sponsored by:   The FreeBSD Foundation

 crypto/openssh/.depend                             |    51 +-
 crypto/openssh/.github/ci-status.md                |     7 +-
 crypto/openssh/.github/configs                     |     2 +-
 crypto/openssh/.github/run_test.sh                 |     2 +-
 crypto/openssh/.github/setup_ci.sh                 |     6 +-
 crypto/openssh/.github/workflows/c-cpp.yml         |     1 +
 crypto/openssh/.github/workflows/selfhosted.yml    |     3 +
 crypto/openssh/.github/workflows/upstream.yml      |     1 +
 crypto/openssh/ChangeLog                           | 15098 ++++++++++---------
 crypto/openssh/Makefile.in                         |     5 +
 crypto/openssh/README                              |     3 +-
 crypto/openssh/README.md                           |     1 +
 crypto/openssh/auth-pam.c                          |    15 +-
 crypto/openssh/auth-shadow.c                       |    14 +-
 crypto/openssh/auth.c                              |     3 +-
 crypto/openssh/auth2-hostbased.c                   |     9 +-
 crypto/openssh/auth2-none.c                        |     3 +-
 crypto/openssh/auth2-pubkey.c                      |     8 +-
 crypto/openssh/auth2-pubkeyfile.c                  |     3 +-
 crypto/openssh/auth2.c                             |     5 +-
 crypto/openssh/authfd.c                            |     9 +-
 crypto/openssh/authfile.c                          |     4 +-
 crypto/openssh/canohost.c                          |     5 +-
 crypto/openssh/channels.c                          |    42 +-
 crypto/openssh/channels.h                          |     4 +-
 crypto/openssh/clientloop.c                        |    14 +-
 crypto/openssh/compat.c                            |    53 +-
 crypto/openssh/compat.h                            |    14 +-
 crypto/openssh/contrib/redhat/openssh.spec         |     2 +-
 crypto/openssh/contrib/suse/openssh.spec           |     2 +-
 crypto/openssh/dispatch.c                          |     3 +-
 crypto/openssh/dns.c                               |     8 +-
 crypto/openssh/dns.h                               |     4 +-
 crypto/openssh/hostfile.c                          |    15 +-
 crypto/openssh/kex.c                               |    72 +-
 crypto/openssh/kex.h                               |     5 +-
 crypto/openssh/kexgexs.c                           |     3 +-
 crypto/openssh/krl.c                               |     3 +-
 crypto/openssh/misc.c                              |     5 +-
 crypto/openssh/misc.h                              |     5 +-
 crypto/openssh/moduli.c                            |    13 +-
 crypto/openssh/monitor.c                           |    11 +-
 crypto/openssh/mux.c                               |     4 +-
 crypto/openssh/openbsd-compat/bsd-getentropy.c     |     2 +-
 crypto/openssh/openbsd-compat/bsd-snprintf.c       |    90 +-
 crypto/openssh/openbsd-compat/getopt.h             |     3 +
 crypto/openssh/openbsd-compat/getopt_long.c        |    14 +
 crypto/openssh/openbsd-compat/getrrsetbyname.c     |    47 +-
 .../openssh/openbsd-compat/libressl-api-compat.c   |    14 +-
 crypto/openssh/openbsd-compat/mktemp.c             |    23 +
 crypto/openssh/openbsd-compat/openbsd-compat.h     |     3 +
 crypto/openssh/packet.c                            |     4 +-
 crypto/openssh/progressmeter.c                     |    95 +-
 crypto/openssh/readconf.c                          |    11 +-
 crypto/openssh/regress/Makefile                    |     6 +-
 crypto/openssh/regress/agent-getpeereid.sh         |     3 +-
 crypto/openssh/regress/agent-restrict.sh           |     6 +-
 crypto/openssh/regress/agent.sh                    |     4 +-
 crypto/openssh/regress/dhgex.sh                    |     6 +-
 crypto/openssh/regress/integrity.sh                |     4 +-
 crypto/openssh/regress/keygen-sshfp.sh             |    22 +-
 crypto/openssh/regress/knownhosts.sh               |    20 +-
 crypto/openssh/regress/multiplex.sh                |     4 +-
 crypto/openssh/regress/sshd-log-wrapper.sh         |    12 -
 crypto/openssh/regress/test-exec.sh                |    88 +-
 crypto/openssh/regress/timestamp.c                 |    46 +
 .../openssh/regress/unittests/kex/test_proposal.c  |    47 +-
 crypto/openssh/regress/unittests/kex/tests.c       |     8 +-
 .../openssh/regress/unittests/misc/test_ptimeout.c |     6 +-
 crypto/openssh/sandbox-seccomp-filter.c            |    93 +-
 crypto/openssh/scp.c                               |     8 +-
 crypto/openssh/servconf.c                          |    15 +-
 crypto/openssh/serverloop.c                        |     5 +-
 crypto/openssh/session.c                           |     4 +-
 crypto/openssh/sftp-client.c                       |     3 +-
 crypto/openssh/sftp-server.c                       |     4 +-
 crypto/openssh/sftp.c                              |    14 +-
 crypto/openssh/ssh-add.c                           |     9 +-
 crypto/openssh/ssh-agent.c                         |     8 +-
 crypto/openssh/ssh-dss.c                           |     3 +-
 crypto/openssh/ssh-ecdsa-sk.c                      |     3 +-
 crypto/openssh/ssh-ecdsa.c                         |     4 +-
 crypto/openssh/ssh-keygen.1                        |    19 +-
 crypto/openssh/ssh-keygen.c                        |    42 +-
 crypto/openssh/ssh-keyscan.1                       |    19 +-
 crypto/openssh/ssh-keyscan.c                       |    22 +-
 crypto/openssh/ssh-pkcs11.c                        |     8 +-
 crypto/openssh/ssh-rsa.c                           |     3 +-
 crypto/openssh/ssh.c                               |     3 +-
 crypto/openssh/ssh_config.5                        |     6 +-
 crypto/openssh/ssh_namespace.h                     |     4 +-
 crypto/openssh/sshconnect.c                        |     5 +-
 crypto/openssh/sshconnect2.c                       |    81 +-
 crypto/openssh/sshd.8                              |    20 +-
 crypto/openssh/sshd.c                              |    92 +-
 crypto/openssh/sshd_config                         |     2 +-
 crypto/openssh/sshd_config.5                       |    20 +-
 crypto/openssh/umac.c                              |     5 +-
 crypto/openssh/version.h                           |     6 +-
 secure/lib/libssh/Makefile                         |     1 +
 100 files changed, 8556 insertions(+), 8103 deletions(-)

diff --cc crypto/openssh/README.md
index 3da933817989,000000000000..9431b0ffdd89
mode 100644,000000..100644
--- a/crypto/openssh/README.md
+++ b/crypto/openssh/README.md
@@@ -1,85 -1,0 +1,86 @@@
 +# Portable OpenSSH
 +
 +[![C/C++ 
CI](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/openssh/openssh-portable/actions/workflows/c-cpp.yml)
 +[![Fuzzing 
Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/openssh.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:openssh)
++[![Coverity 
Status](https://scan.coverity.com/projects/21341/badge.svg)](https://scan.coverity.com/projects/openssh-portable)
 +
 +OpenSSH is a complete implementation of the SSH protocol (version 2) for 
secure remote login, command execution and file transfer. It includes a client 
``ssh`` and server ``sshd``, file transfer utilities ``scp`` and ``sftp`` as 
well as tools for key generation (``ssh-keygen``), run-time key storage 
(``ssh-agent``) and a number of supporting programs.
 +
 +This is a port of OpenBSD's [OpenSSH](https://openssh.com) to most Unix-like 
operating systems, including Linux, OS X and Cygwin. Portable OpenSSH polyfills 
OpenBSD APIs that are not available elsewhere, adds sshd sandboxing for more 
operating systems and includes support for OS-native authentication and 
auditing (e.g. using PAM).
 +
 +## Documentation
 +
 +The official documentation for OpenSSH are the man pages for each tool:
 +
 +* [ssh(1)](https://man.openbsd.org/ssh.1)
 +* [sshd(8)](https://man.openbsd.org/sshd.8)
 +* [ssh-keygen(1)](https://man.openbsd.org/ssh-keygen.1)
 +* [ssh-agent(1)](https://man.openbsd.org/ssh-agent.1)
 +* [scp(1)](https://man.openbsd.org/scp.1)
 +* [sftp(1)](https://man.openbsd.org/sftp.1)
 +* [ssh-keyscan(8)](https://man.openbsd.org/ssh-keyscan.8)
 +* [sftp-server(8)](https://man.openbsd.org/sftp-server.8)
 +
 +## Stable Releases
 +
 +Stable release tarballs are available from a number of [download 
mirrors](https://www.openssh.com/portable.html#downloads). We recommend the use 
of a stable release for most users. Please read the [release 
notes](https://www.openssh.com/releasenotes.html) for details of recent changes 
and potential incompatibilities.
 +
 +## Building Portable OpenSSH
 +
 +### Dependencies
 +
 +Portable OpenSSH is built using autoconf and make. It requires a working C 
compiler, standard library and headers.
 +
 +``libcrypto`` from either [LibreSSL](https://www.libressl.org/) or 
[OpenSSL](https://www.openssl.org) may also be used.  OpenSSH may be built 
without either of these, but the resulting binaries will have only a subset of 
the cryptographic algorithms normally available.
 +
 +[zlib](https://www.zlib.net/) is optional; without it transport compression 
is not supported.
 +
 +FIDO security token support needs 
[libfido2](https://github.com/Yubico/libfido2) and its dependencies and will be 
enabled automatically if they are found.
 +
 +In addition, certain platforms and build-time options may require additional 
dependencies; see README.platform for details about your platform.
 +
 +### Building a release
 +
 +Releases include a pre-built copy of the ``configure`` script and may be 
built using:
 +
 +```
 +tar zxvf openssh-X.YpZ.tar.gz
 +cd openssh
 +./configure # [options]
 +make && make tests
 +```
 +
 +See the [Build-time Customisation](#build-time-customisation) section below 
for configure options. If you plan on installing OpenSSH to your system, then 
you will usually want to specify destination paths.
 +
 +### Building from git
 +
 +If building from git, you'll need 
[autoconf](https://www.gnu.org/software/autoconf/) installed to build the 
``configure`` script. The following commands will check out and build portable 
OpenSSH from git:
 +
 +```
 +git clone https://github.com/openssh/openssh-portable # or 
https://anongit.mindrot.org/openssh.git
 +cd openssh-portable
 +autoreconf
 +./configure
 +make && make tests
 +```
 +
 +### Build-time Customisation
 +
 +There are many build-time customisation options available. All Autoconf 
destination path flags (e.g. ``--prefix``) are supported (and are usually 
required if you want to install OpenSSH).
 +
 +For a full list of available flags, run ``./configure --help`` but a few of 
the more frequently-used ones are described below. Some of these flags will 
require additional libraries and/or headers be installed.
 +
 +Flag | Meaning
 +--- | ---
 +``--with-pam`` | Enable 
[PAM](https://en.wikipedia.org/wiki/Pluggable_authentication_module) support. 
[OpenPAM](https://www.openpam.org/), [Linux PAM](http://www.linux-pam.org/) and 
Solaris PAM are supported.
 +``--with-libedit`` | Enable [libedit](https://www.thrysoee.dk/editline/) 
support for sftp.
 +``--with-kerberos5`` | Enable Kerberos/GSSAPI support. Both 
[Heimdal](https://www.h5l.org/) and [MIT](https://web.mit.edu/kerberos/) 
Kerberos implementations are supported.
 +``--with-selinux`` | Enable 
[SELinux](https://en.wikipedia.org/wiki/Security-Enhanced_Linux) support.
 +
 +## Development
 +
 +Portable OpenSSH development is discussed on the [openssh-unix-dev mailing 
list](https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev) ([archive 
mirror](https://marc.info/?l=openssh-unix-dev)). Bugs and feature requests are 
tracked on our [Bugzilla](https://bugzilla.mindrot.org/).
 +
 +## Reporting bugs
 +
 +_Non-security_ bugs may be reported to the developers via 
[Bugzilla](https://bugzilla.mindrot.org/) or via the mailing list above. 
Security bugs should be reported to 
[[email protected]](mailto:openssh.openssh.com).
diff --cc crypto/openssh/auth.c
index 93610963f3b3,000000000000..f390df839d62
mode 100644,000000..100644
--- a/crypto/openssh/auth.c
+++ b/crypto/openssh/auth.c
@@@ -1,880 -1,0 +1,879 @@@
- /* $OpenBSD: auth.c,v 1.159 2022/12/09 00:17:40 dtucker Exp $ */
++/* $OpenBSD: auth.c,v 1.160 2023/03/05 05:34:09 dtucker Exp $ */
 +/*
 + * Copyright (c) 2000 Markus Friedl.  All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "includes.h"
 +
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +#include <sys/socket.h>
 +#include <sys/wait.h>
 +
 +#include <netinet/in.h>
 +
 +#include <stdlib.h>
 +#include <errno.h>
 +#include <fcntl.h>
 +#ifdef HAVE_PATHS_H
 +# include <paths.h>
 +#endif
 +#include <pwd.h>
 +#ifdef HAVE_LOGIN_H
 +#include <login.h>
 +#endif
 +#ifdef USE_SHADOW
 +#include <shadow.h>
 +#endif
 +#include <stdarg.h>
 +#include <stdio.h>
 +#include <string.h>
 +#include <unistd.h>
 +#include <limits.h>
 +#include <netdb.h>
 +#include <time.h>
 +
 +#include "xmalloc.h"
 +#include "match.h"
 +#include "groupaccess.h"
 +#include "log.h"
 +#include "sshbuf.h"
 +#include "misc.h"
 +#include "servconf.h"
 +#include "sshkey.h"
 +#include "hostfile.h"
 +#include "auth.h"
 +#include "auth-options.h"
 +#include "canohost.h"
 +#include "uidswap.h"
 +#include "packet.h"
 +#include "loginrec.h"
 +#ifdef GSSAPI
 +#include "ssh-gss.h"
 +#endif
 +#include "authfile.h"
 +#include "monitor_wrap.h"
 +#include "ssherr.h"
- #include "compat.h"
 +#include "channels.h"
 +#include "blacklist_client.h"
 +
 +/* import */
 +extern ServerOptions options;
 +extern struct include_list includes;
 +extern int use_privsep;
 +extern struct sshbuf *loginmsg;
 +extern struct passwd *privsep_pw;
 +extern struct sshauthopt *auth_opts;
 +
 +/* Debugging messages */
 +static struct sshbuf *auth_debug;
 +
 +/*
 + * Check if the user is allowed to log in via ssh. If user is listed
 + * in DenyUsers or one of user's groups is listed in DenyGroups, false
 + * will be returned. If AllowUsers isn't empty and user isn't listed
 + * there, or if AllowGroups isn't empty and one of user's groups isn't
 + * listed there, false will be returned.
 + * If the user's shell is not executable, false will be returned.
 + * Otherwise true is returned.
 + */
 +int
 +allowed_user(struct ssh *ssh, struct passwd * pw)
 +{
 +      struct stat st;
 +      const char *hostname = NULL, *ipaddr = NULL;
 +      u_int i;
 +      int r;
 +
 +      /* Shouldn't be called if pw is NULL, but better safe than sorry... */
 +      if (!pw || !pw->pw_name)
 +              return 0;
 +
 +      if (!options.use_pam && platform_locked_account(pw)) {
 +              logit("User %.100s not allowed because account is locked",
 +                  pw->pw_name);
 +              return 0;
 +      }
 +
 +      /*
 +       * Deny if shell does not exist or is not executable unless we
 +       * are chrooting.
 +       */
 +      if (options.chroot_directory == NULL ||
 +          strcasecmp(options.chroot_directory, "none") == 0) {
 +              char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
 +                  _PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
 +
 +              if (stat(shell, &st) == -1) {
 +                      logit("User %.100s not allowed because shell %.100s "
 +                          "does not exist", pw->pw_name, shell);
 +                      free(shell);
 +                      return 0;
 +              }
 +              if (S_ISREG(st.st_mode) == 0 ||
 +                  (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)) == 0) {
 +                      logit("User %.100s not allowed because shell %.100s "
 +                          "is not executable", pw->pw_name, shell);
 +                      free(shell);
 +                      return 0;
 +              }
 +              free(shell);
 +      }
 +
 +      if (options.num_deny_users > 0 || options.num_allow_users > 0 ||
 +          options.num_deny_groups > 0 || options.num_allow_groups > 0) {
 +              hostname = auth_get_canonical_hostname(ssh, options.use_dns);
 +              ipaddr = ssh_remote_ipaddr(ssh);
 +      }
 +
 +      /* Return false if user is listed in DenyUsers */
 +      if (options.num_deny_users > 0) {
 +              for (i = 0; i < options.num_deny_users; i++) {
 +                      r = match_user(pw->pw_name, hostname, ipaddr,
 +                          options.deny_users[i]);
 +                      if (r < 0) {
 +                              fatal("Invalid DenyUsers pattern \"%.100s\"",
 +                                  options.deny_users[i]);
 +                      } else if (r != 0) {
 +                              logit("User %.100s from %.100s not allowed "
 +                                  "because listed in DenyUsers",
 +                                  pw->pw_name, hostname);
 +                              return 0;
 +                      }
 +              }
 +      }
 +      /* Return false if AllowUsers isn't empty and user isn't listed there */
 +      if (options.num_allow_users > 0) {
 +              for (i = 0; i < options.num_allow_users; i++) {
 +                      r = match_user(pw->pw_name, hostname, ipaddr,
 +                          options.allow_users[i]);
 +                      if (r < 0) {
 +                              fatal("Invalid AllowUsers pattern \"%.100s\"",
 +                                  options.allow_users[i]);
 +                      } else if (r == 1)
 +                              break;
 +              }
 +              /* i < options.num_allow_users iff we break for loop */
 +              if (i >= options.num_allow_users) {
 +                      logit("User %.100s from %.100s not allowed because "
 +                          "not listed in AllowUsers", pw->pw_name, hostname);
 +                      return 0;
 +              }
 +      }
 +      if (options.num_deny_groups > 0 || options.num_allow_groups > 0) {
 +              /* Get the user's group access list (primary and supplementary) 
*/
 +              if (ga_init(pw->pw_name, pw->pw_gid) == 0) {
 +                      logit("User %.100s from %.100s not allowed because "
 +                          "not in any group", pw->pw_name, hostname);
 +                      return 0;
 +              }
 +
 +              /* Return false if one of user's groups is listed in DenyGroups 
*/
 +              if (options.num_deny_groups > 0)
 +                      if (ga_match(options.deny_groups,
 +                          options.num_deny_groups)) {
 +                              ga_free();
 +                              logit("User %.100s from %.100s not allowed "
 +                                  "because a group is listed in DenyGroups",
 +                                  pw->pw_name, hostname);
 +                              return 0;
 +                      }
 +              /*
 +               * Return false if AllowGroups isn't empty and one of user's 
groups
 +               * isn't listed there
 +               */
 +              if (options.num_allow_groups > 0)
 +                      if (!ga_match(options.allow_groups,
 +                          options.num_allow_groups)) {
 +                              ga_free();
 +                              logit("User %.100s from %.100s not allowed "
 +                                  "because none of user's groups are listed "
 +                                  "in AllowGroups", pw->pw_name, hostname);
 +                              return 0;
 +                      }
 +              ga_free();
 +      }
 +
 +#ifdef CUSTOM_SYS_AUTH_ALLOWED_USER
 +      if (!sys_auth_allowed_user(pw, loginmsg))
 +              return 0;
 +#endif
 +
 +      /* We found no reason not to let this user try to log on... */
 +      return 1;
 +}
 +
 +/*
 + * Formats any key left in authctxt->auth_method_key for inclusion in
 + * auth_log()'s message. Also includes authxtct->auth_method_info if present.
 + */
 +static char *
 +format_method_key(Authctxt *authctxt)
 +{
 +      const struct sshkey *key = authctxt->auth_method_key;
 +      const char *methinfo = authctxt->auth_method_info;
 +      char *fp, *cafp, *ret = NULL;
 +
 +      if (key == NULL)
 +              return NULL;
 +
 +      if (sshkey_is_cert(key)) {
 +              fp = sshkey_fingerprint(key,
 +                  options.fingerprint_hash, SSH_FP_DEFAULT);
 +              cafp = sshkey_fingerprint(key->cert->signature_key,
 +                  options.fingerprint_hash, SSH_FP_DEFAULT);
 +              xasprintf(&ret, "%s %s ID %s (serial %llu) CA %s %s%s%s",
 +                  sshkey_type(key), fp == NULL ? "(null)" : fp,
 +                  key->cert->key_id,
 +                  (unsigned long long)key->cert->serial,
 +                  sshkey_type(key->cert->signature_key),
 +                  cafp == NULL ? "(null)" : cafp,
 +                  methinfo == NULL ? "" : ", ",
 +                  methinfo == NULL ? "" : methinfo);
 +              free(fp);
 +              free(cafp);
 +      } else {
 +              fp = sshkey_fingerprint(key, options.fingerprint_hash,
 +                  SSH_FP_DEFAULT);
 +              xasprintf(&ret, "%s %s%s%s", sshkey_type(key),
 +                  fp == NULL ? "(null)" : fp,
 +                  methinfo == NULL ? "" : ", ",
 +                  methinfo == NULL ? "" : methinfo);
 +              free(fp);
 +      }
 +      return ret;
 +}
 +
 +void
 +auth_log(struct ssh *ssh, int authenticated, int partial,
 +    const char *method, const char *submethod)
 +{
 +      Authctxt *authctxt = (Authctxt *)ssh->authctxt;
 +      int level = SYSLOG_LEVEL_VERBOSE;
 +      const char *authmsg;
 +      char *extra = NULL;
 +
 +      if (use_privsep && !mm_is_monitor() && !authctxt->postponed)
 +              return;
 +
 +      /* Raise logging level */
 +      if (authenticated == 1 ||
 +          !authctxt->valid ||
 +          authctxt->failures >= options.max_authtries / 2 ||
 +          strcmp(method, "password") == 0)
 +              level = SYSLOG_LEVEL_INFO;
 +
 +      if (authctxt->postponed)
 +              authmsg = "Postponed";
 +      else if (partial)
 +              authmsg = "Partial";
 +      else {
 +              authmsg = authenticated ? "Accepted" : "Failed";
 +              if (authenticated)
 +                      BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_OK, "ssh");
 +      }
 +
 +      if ((extra = format_method_key(authctxt)) == NULL) {
 +              if (authctxt->auth_method_info != NULL)
 +                      extra = xstrdup(authctxt->auth_method_info);
 +      }
 +
 +      do_log2(level, "%s %s%s%s for %s%.100s from %.200s port %d ssh2%s%s",
 +          authmsg,
 +          method,
 +          submethod != NULL ? "/" : "", submethod == NULL ? "" : submethod,
 +          authctxt->valid ? "" : "invalid user ",
 +          authctxt->user,
 +          ssh_remote_ipaddr(ssh),
 +          ssh_remote_port(ssh),
 +          extra != NULL ? ": " : "",
 +          extra != NULL ? extra : "");
 +
 +      free(extra);
 +
 +#if defined(CUSTOM_FAILED_LOGIN) || defined(SSH_AUDIT_EVENTS)
 +      if (authenticated == 0 && !(authctxt->postponed || partial)) {
 +              /* Log failed login attempt */
 +# ifdef CUSTOM_FAILED_LOGIN
 +              if (strcmp(method, "password") == 0 ||
 +                  strncmp(method, "keyboard-interactive", 20) == 0 ||
 +                  strcmp(method, "challenge-response") == 0)
 +                      record_failed_login(ssh, authctxt->user,
 +                          auth_get_canonical_hostname(ssh, options.use_dns), 
"ssh");
 +# endif
 +# ifdef SSH_AUDIT_EVENTS
 +              audit_event(ssh, audit_classify_auth(method));
 +# endif
 +      }
 +#endif
 +#if defined(CUSTOM_FAILED_LOGIN) && defined(WITH_AIXAUTHENTICATE)
 +      if (authenticated)
 +              sys_auth_record_login(authctxt->user,
 +                  auth_get_canonical_hostname(ssh, options.use_dns), "ssh",
 +                  loginmsg);
 +#endif
 +}
 +
 +void
 +auth_maxtries_exceeded(struct ssh *ssh)
 +{
 +      Authctxt *authctxt = (Authctxt *)ssh->authctxt;
 +
 +      error("maximum authentication attempts exceeded for "
 +          "%s%.100s from %.200s port %d ssh2",
 +          authctxt->valid ? "" : "invalid user ",
 +          authctxt->user,
 +          ssh_remote_ipaddr(ssh),
 +          ssh_remote_port(ssh));
 +      ssh_packet_disconnect(ssh, "Too many authentication failures");
 +      /* NOTREACHED */
 +}
 +
 +/*
 + * Check whether root logins are disallowed.
 + */
 +int
 +auth_root_allowed(struct ssh *ssh, const char *method)
 +{
 +      switch (options.permit_root_login) {
 +      case PERMIT_YES:
 +              return 1;
 +      case PERMIT_NO_PASSWD:
 +              if (strcmp(method, "publickey") == 0 ||
 +                  strcmp(method, "hostbased") == 0 ||
 +                  strcmp(method, "gssapi-with-mic") == 0)
 +                      return 1;
 +              break;
 +      case PERMIT_FORCED_ONLY:
 +              if (auth_opts->force_command != NULL) {
 +                      logit("Root login accepted for forced command.");
 +                      return 1;
 +              }
 +              break;
 +      }
 +      logit("ROOT LOGIN REFUSED FROM %.200s port %d",
 +          ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
 +      return 0;
 +}
 +
 +
 +/*
 + * Given a template and a passwd structure, build a filename
 + * by substituting % tokenised options. Currently, %% becomes '%',
 + * %h becomes the home directory and %u the username.
 + *
 + * This returns a buffer allocated by xmalloc.
 + */
 +char *
 +expand_authorized_keys(const char *filename, struct passwd *pw)
 +{
 +      char *file, uidstr[32], ret[PATH_MAX];
 +      int i;
 +
 +      snprintf(uidstr, sizeof(uidstr), "%llu",
 +          (unsigned long long)pw->pw_uid);
 +      file = percent_expand(filename, "h", pw->pw_dir,
 +          "u", pw->pw_name, "U", uidstr, (char *)NULL);
 +
 +      /*
 +       * Ensure that filename starts anchored. If not, be backward
 +       * compatible and prepend the '%h/'
 +       */
 +      if (path_absolute(file))
 +              return (file);
 +
 +      i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
 +      if (i < 0 || (size_t)i >= sizeof(ret))
 +              fatal("expand_authorized_keys: path too long");
 +      free(file);
 +      return (xstrdup(ret));
 +}
 +
 +char *
 +authorized_principals_file(struct passwd *pw)
 +{
 +      if (options.authorized_principals_file == NULL)
 +              return NULL;
 +      return expand_authorized_keys(options.authorized_principals_file, pw);
 +}
 +
 +/* return ok if key exists in sysfile or userfile */
 +HostStatus
 +check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char 
*host,
 +    const char *sysfile, const char *userfile)
 +{
 +      char *user_hostfile;
 +      struct stat st;
 +      HostStatus host_status;
 +      struct hostkeys *hostkeys;
 +      const struct hostkey_entry *found;
 +
 +      hostkeys = init_hostkeys();
 +      load_hostkeys(hostkeys, host, sysfile, 0);
 +      if (userfile != NULL) {
 +              user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
 +              if (options.strict_modes &&
 +                  (stat(user_hostfile, &st) == 0) &&
 +                  ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
 +                  (st.st_mode & 022) != 0)) {
 +                      logit("Authentication refused for %.100s: "
 +                          "bad owner or modes for %.200s",
 +                          pw->pw_name, user_hostfile);
 +                      auth_debug_add("Ignored %.200s: bad ownership or modes",
 +                          user_hostfile);
 +              } else {
 +                      temporarily_use_uid(pw);
 +                      load_hostkeys(hostkeys, host, user_hostfile, 0);
 +                      restore_uid();
 +              }
 +              free(user_hostfile);
 +      }
 +      host_status = check_key_in_hostkeys(hostkeys, key, &found);
 +      if (host_status == HOST_REVOKED)
 +              error("WARNING: revoked key for %s attempted authentication",
 +                  host);
 +      else if (host_status == HOST_OK)
 +              debug_f("key for %s found at %s:%ld",
 +                  found->host, found->file, found->line);
 +      else
 +              debug_f("key for host %s not found", host);
 +
 +      free_hostkeys(hostkeys);
 +
 +      return host_status;
 +}
 +
 +struct passwd *
 +getpwnamallow(struct ssh *ssh, const char *user)
 +{
 +#ifdef HAVE_LOGIN_CAP
 +      extern login_cap_t *lc;
 +#ifdef HAVE_AUTH_HOSTOK
 +      const char *from_host, *from_ip;
 +#endif
 +#ifdef BSD_AUTH
 +      auth_session_t *as;
 +#endif
 +#endif
 +      struct passwd *pw;
 +      struct connection_info *ci;
 +      u_int i;
 +
 +      ci = get_connection_info(ssh, 1, options.use_dns);
 +      ci->user = user;
 +      parse_server_match_config(&options, &includes, ci);
 +      log_change_level(options.log_level);
 +      log_verbose_reset();
 +      for (i = 0; i < options.num_log_verbose; i++)
 +              log_verbose_add(options.log_verbose[i]);
 +      process_permitopen(ssh, &options);
 +
 +#if defined(_AIX) && defined(HAVE_SETAUTHDB)
 +      aix_setauthdb(user);
 +#endif
 +
 +      pw = getpwnam(user);
 +
 +#if defined(_AIX) && defined(HAVE_SETAUTHDB)
 +      aix_restoreauthdb();
 +#endif
 +      if (pw == NULL) {
 +              BLACKLIST_NOTIFY(ssh, BLACKLIST_BAD_USER, user);
 +              logit("Invalid user %.100s from %.100s port %d",
 +                  user, ssh_remote_ipaddr(ssh), ssh_remote_port(ssh));
 +#ifdef CUSTOM_FAILED_LOGIN
 +              record_failed_login(ssh, user,
 +                  auth_get_canonical_hostname(ssh, options.use_dns), "ssh");
 +#endif
 +#ifdef SSH_AUDIT_EVENTS
 +              audit_event(ssh, SSH_INVALID_USER);
 +#endif /* SSH_AUDIT_EVENTS */
 +              return (NULL);
 +      }
 +      if (!allowed_user(ssh, pw))
 +              return (NULL);
 +#ifdef HAVE_LOGIN_CAP
 +      if ((lc = login_getpwclass(pw)) == NULL) {
 +              debug("unable to get login class: %s", user);
 +              return (NULL);
 +      }
 +#ifdef HAVE_AUTH_HOSTOK
 +      from_host = auth_get_canonical_hostname(ssh, options.use_dns);
 +      from_ip = ssh_remote_ipaddr(ssh);
 +      if (!auth_hostok(lc, from_host, from_ip)) {
 +              debug("Denied connection for %.200s from %.200s [%.200s].",
 +                  pw->pw_name, from_host, from_ip);
 +              return (NULL);
 +      }
 +#endif /* HAVE_AUTH_HOSTOK */
 +#ifdef HAVE_AUTH_TIMEOK
 +      if (!auth_timeok(lc, time(NULL))) {
 +              debug("LOGIN %.200s REFUSED (TIME)", pw->pw_name);
 +              return (NULL);
 +      }
 +#endif /* HAVE_AUTH_TIMEOK */
 +#ifdef BSD_AUTH
 +      if ((as = auth_open()) == NULL || auth_setpwd(as, pw) != 0 ||
 +          auth_approval(as, lc, pw->pw_name, "ssh") <= 0) {
 +              debug("Approval failure for %s", user);
 +              pw = NULL;
 +      }
 +      if (as != NULL)
 +              auth_close(as);
 +#endif
 +#endif
 +      if (pw != NULL)
 +              return (pwcopy(pw));
 +      return (NULL);
 +}
 +
 +/* Returns 1 if key is revoked by revoked_keys_file, 0 otherwise */
 +int
 +auth_key_is_revoked(struct sshkey *key)
 +{
 +      char *fp = NULL;
 +      int r;
 +
 +      if (options.revoked_keys_file == NULL)
 +              return 0;
 +      if ((fp = sshkey_fingerprint(key, options.fingerprint_hash,
 +          SSH_FP_DEFAULT)) == NULL) {
 +              r = SSH_ERR_ALLOC_FAIL;
 +              error_fr(r, "fingerprint key");
 +              goto out;
 +      }
 +
 +      r = sshkey_check_revoked(key, options.revoked_keys_file);
 +      switch (r) {
 +      case 0:
 +              break; /* not revoked */
 +      case SSH_ERR_KEY_REVOKED:
 +              error("Authentication key %s %s revoked by file %s",
 +                  sshkey_type(key), fp, options.revoked_keys_file);
 +              goto out;
 +      default:
 +              error_r(r, "Error checking authentication key %s %s in "
 +                  "revoked keys file %s", sshkey_type(key), fp,
 +                  options.revoked_keys_file);
 +              goto out;
 +      }
 +
 +      /* Success */
 +      r = 0;
 +
 + out:
 +      free(fp);
 +      return r == 0 ? 0 : 1;
 +}
 +
 +void
 +auth_debug_add(const char *fmt,...)
 +{
 +      char buf[1024];
 +      va_list args;
 +      int r;
 +
 +      va_start(args, fmt);
 +      vsnprintf(buf, sizeof(buf), fmt, args);
 +      va_end(args);
 +      debug3("%s", buf);
 +      if (auth_debug != NULL)
 +              if ((r = sshbuf_put_cstring(auth_debug, buf)) != 0)
 +                      fatal_fr(r, "sshbuf_put_cstring");
 +}
 +
 +void
 +auth_debug_send(struct ssh *ssh)
 +{
 +      char *msg;
 +      int r;
 +
 +      if (auth_debug == NULL)
 +              return;
 +      while (sshbuf_len(auth_debug) != 0) {
 +              if ((r = sshbuf_get_cstring(auth_debug, &msg, NULL)) != 0)
 +                      fatal_fr(r, "sshbuf_get_cstring");
 +              ssh_packet_send_debug(ssh, "%s", msg);
 +              free(msg);
 +      }
 +}
 +
 +void
 +auth_debug_reset(void)
 +{
 +      if (auth_debug != NULL)
 +              sshbuf_reset(auth_debug);
 +      else if ((auth_debug = sshbuf_new()) == NULL)
 +              fatal_f("sshbuf_new failed");
 +}
 +
 +struct passwd *
 +fakepw(void)
 +{
 +      static int done = 0;
 +      static struct passwd fake;
 +      const char hashchars[] = "./ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 +          "abcdefghijklmnopqrstuvwxyz0123456789"; /* from bcrypt.c */
 +      char *cp;
 +
 +      if (done)
 +              return (&fake);
 +
 +      memset(&fake, 0, sizeof(fake));
 +      fake.pw_name = "NOUSER";
 +      fake.pw_passwd = xstrdup("$2a$10$"
 +          "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
 +      for (cp = fake.pw_passwd + 7; *cp != '\0'; cp++)
 +              *cp = hashchars[arc4random_uniform(sizeof(hashchars) - 1)];
 +#ifdef HAVE_STRUCT_PASSWD_PW_GECOS
 +      fake.pw_gecos = "NOUSER";
 +#endif
 +      fake.pw_uid = privsep_pw == NULL ? (uid_t)-1 : privsep_pw->pw_uid;
 +      fake.pw_gid = privsep_pw == NULL ? (gid_t)-1 : privsep_pw->pw_gid;
 +#ifdef HAVE_STRUCT_PASSWD_PW_CLASS
 +      fake.pw_class = "";
 +#endif
 +      fake.pw_dir = "/nonexist";
 +      fake.pw_shell = "/nonexist";
 +      done = 1;
 +
 +      return (&fake);
 +}
 +
 +/*
 + * Returns the remote DNS hostname as a string. The returned string must not
 + * be freed. NB. this will usually trigger a DNS query the first time it is
 + * called.
 + * This function does additional checks on the hostname to mitigate some
 + * attacks on based on conflation of hostnames and IP addresses.
 + */
 +
 +static char *
 +remote_hostname(struct ssh *ssh)
 +{
 +      struct sockaddr_storage from;
 +      socklen_t fromlen;
 +      struct addrinfo hints, *ai, *aitop;
 +      char name[NI_MAXHOST], ntop2[NI_MAXHOST];
 +      const char *ntop = ssh_remote_ipaddr(ssh);
 +
 +      /* Get IP address of client. */
 +      fromlen = sizeof(from);
 +      memset(&from, 0, sizeof(from));
 +      if (getpeername(ssh_packet_get_connection_in(ssh),
 +          (struct sockaddr *)&from, &fromlen) == -1) {
 +              debug("getpeername failed: %.100s", strerror(errno));
 +              return xstrdup(ntop);
 +      }
 +
 +      ipv64_normalise_mapped(&from, &fromlen);
 +      if (from.ss_family == AF_INET6)
 +              fromlen = sizeof(struct sockaddr_in6);
 +
 +      debug3("Trying to reverse map address %.100s.", ntop);
 +      /* Map the IP address to a host name. */
 +      if (getnameinfo((struct sockaddr *)&from, fromlen, name, sizeof(name),
 +          NULL, 0, NI_NAMEREQD) != 0) {
 +              /* Host name not found.  Use ip address. */
 +              return xstrdup(ntop);
 +      }
 +
 +      /*
 +       * if reverse lookup result looks like a numeric hostname,
 +       * someone is trying to trick us by PTR record like following:
 +       *      1.1.1.10.in-addr.arpa.  IN PTR  2.3.4.5
 +       */
 +      memset(&hints, 0, sizeof(hints));
 +      hints.ai_socktype = SOCK_DGRAM; /*dummy*/
 +      hints.ai_flags = AI_NUMERICHOST;
 +      if (getaddrinfo(name, NULL, &hints, &ai) == 0) {
 +              logit("Nasty PTR record \"%s\" is set up for %s, ignoring",
 +                  name, ntop);
 +              freeaddrinfo(ai);
 +              return xstrdup(ntop);
 +      }
 +
 +      /* Names are stored in lowercase. */
 +      lowercase(name);
 +
 +      /*
 +       * Map it back to an IP address and check that the given
 +       * address actually is an address of this host.  This is
 +       * necessary because anyone with access to a name server can
 +       * define arbitrary names for an IP address. Mapping from
 +       * name to IP address can be trusted better (but can still be
 +       * fooled if the intruder has access to the name server of
 +       * the domain).
 +       */
 +      memset(&hints, 0, sizeof(hints));
 +      hints.ai_family = from.ss_family;
 +      hints.ai_socktype = SOCK_STREAM;
 +      if (getaddrinfo(name, NULL, &hints, &aitop) != 0) {
 +              logit("reverse mapping checking getaddrinfo for %.700s "
 +                  "[%s] failed.", name, ntop);
 +              return xstrdup(ntop);
 +      }
 +      /* Look for the address from the list of addresses. */
 +      for (ai = aitop; ai; ai = ai->ai_next) {
 +              if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop2,
 +                  sizeof(ntop2), NULL, 0, NI_NUMERICHOST) == 0 &&
*** 7651 LINES SKIPPED ***

Reply via email to