Marcus Meissner
3fed02069e
- Version upgrade to 8.8p1 * No changes for askpass, see main package changelog for details - Version update to 8.8p1: = Security * sshd(8) from OpenSSH 6.2 through 8.7 failed to correctly initialise supplemental groups when executing an AuthorizedKeysCommand or AuthorizedPrincipalsCommand, where a AuthorizedKeysCommandUser or AuthorizedPrincipalsCommandUser directive has been set to run the command as a different user. Instead these commands would inherit the groups that sshd(8) was started with. Depending on system configuration, inherited groups may allow AuthorizedKeysCommand/AuthorizedPrincipalsCommand helper programs to gain unintended privilege. Neither AuthorizedKeysCommand nor AuthorizedPrincipalsCommand are enabled by default in sshd_config(5). = Potentially-incompatible changes * This release disables RSA signatures using the SHA-1 hash algorithm by default. This change has been made as the SHA-1 hash algorithm is cryptographically broken, and it is possible to create chosen-prefix hash collisions for <USD$50K. For most users, this change should be invisible and there is no need to replace ssh-rsa keys. OpenSSH has supported RFC8332 RSA/SHA-256/512 signatures since release 7.2 and existing ssh-rsa keys will automatically use the stronger algorithm where possible. Incompatibility is more likely when connecting to older SSH implementations that have not been upgraded or have not closely tracked improvements in the SSH protocol. For these cases, it may be necessary to selectively re-enable RSA/SHA1 to allow connection and/or user authentication via the HostkeyAlgorithms and PubkeyAcceptedAlgorithms options. = New features * ssh(1): allow the ssh_config(5) CanonicalizePermittedCNAMEs directive to accept a "none" argument to specify the default behaviour. = Bugfixes * scp(1): when using the SFTP protocol, continue transferring files after a transfer error occurs, better matching original scp/rcp behaviour. * ssh(1): fixed a number of memory leaks in multiplexing, * ssh-keygen(1): avoid crash when using the -Y find-principals command. * A number of documentation and manual improvements, including bz#3340, PR139, PR215, PR241, PR257 - Additional changes from 8.7p1 release: = Potentially-incompatible changes * scp(1): this release changes the behaviour of remote to remote copies (e.g. "scp host-a:/path host-b:") to transfer through the local host by default. This was previously available via the -3 flag. This mode avoids the need to expose credentials on the origin hop, avoids triplicate interpretation of filenames by the shell (by the local system, the copy origin and the destination) and, in conjunction with the SFTP support for scp(1) mentioned below, allows use of all authentication methods to the remote hosts (previously, only non-interactive methods could be used). A -R flag has been added to select the old behaviour. * ssh(1)/sshd(8): both the client and server are now using a stricter configuration file parser. The new parser uses more shell-like rules for quotes, space and escape characters. It is also more strict in rejecting configurations that include options lacking arguments. Previously some options (e.g. DenyUsers) could appear on a line with no subsequent arguments. This release will reject such configurations. The new parser will also reject configurations with unterminated quotes and multiple '=' characters after the option name. * ssh(1): when using SSHFP DNS records for host key verification, ssh(1) will verify all matching records instead of just those with the specific signature type requested. This may cause host key verification problems if stale SSHFP records of a different or legacy signature type exist alongside other records for a particular host. bz#3322 * ssh-keygen(1): when generating a FIDO key and specifying an explicit attestation challenge (using -Ochallenge), the challenge will now be hashed by the builtin security key middleware. This removes the (undocumented) requirement that challenges be exactly 32 bytes in length and matches the expectations of libfido2. * sshd(8): environment="..." directives in authorized_keys files are now first-match-wins and limited to 1024 discrete environment variable names. = New features * scp(1): experimental support for transfers using the SFTP protocol as a replacement for the venerable SCP/RCP protocol that it has traditionally used. SFTP offers more predictable filename handling and does not require expansion of glob(3) patterns via the shell on the remote side. * sftp-server(8): add a protocol extension to support expansion of ~/ and ~user/ prefixed paths. This was added to support these paths when used by scp(1) while in SFTP mode. * ssh(1): add a ForkAfterAuthentication ssh_config(5) counterpart to the ssh(1) -f flag. GHPR231 * ssh(1): add a StdinNull directive to ssh_config(5) that allows the config file to do the same thing as -n does on the ssh(1) command- line. GHPR231 * ssh(1): add a SessionType directive to ssh_config, allowing the configuration file to offer equivalent control to the -N (no session) and -s (subsystem) command-line flags. GHPR231 * ssh-keygen(1): allowed signers files used by ssh-keygen(1) signatures now support listing key validity intervals alongside they key, and ssh-keygen(1) can optionally check during signature verification whether a specified time falls inside this interval. This feature is intended for use by git to support signing and verifying objects using ssh keys. * ssh-keygen(8): support printing of the full public key in a sshsig signature via a -Oprint-pubkey flag. = Bugfixes * ssh(1)/sshd(8): start time-based re-keying exactly on schedule in the client and server mainloops. Previously the re-key timeout could expire but re-keying would not start until a packet was sent or received, causing a spin in select() if the connection was quiescent. * ssh-keygen(1): avoid Y2038 problem in printing certificate validity lifetimes. Dates past 2^31-1 seconds since epoch were displayed incorrectly on some platforms. bz#3329 * scp(1): allow spaces to appear in usernames for local to remote and scp -3 remote to remote copies. bz#1164 * ssh(1)/sshd(8): remove references to ChallengeResponseAuthentication in favour of KbdInteractiveAuthentication. The former is what was in SSHv1, the latter is what is in SSHv2 (RFC4256) and they were treated as somewhat but not entirely equivalent. We retain the old name as a deprecated alias so configuration files continue to work as well as a reference in the man page for people looking for it. bz#3303 * ssh(1)/ssh-add(1)/ssh-keygen(1): fix decoding of X.509 subject name when extracting a key from a PKCS#11 certificate. bz#3327 * ssh(1): restore blocking status on stdio fds before close. ssh(1) needs file descriptors in non-blocking mode to operate but it was not restoring the original state on exit. This could cause problems with fds shared with other programs via the shell, bz#3280 and GHPR246 * ssh(1)/sshd(8): switch both client and server mainloops from select(3) to pselect(3). Avoids race conditions where a signal may arrive immediately before select(3) and not be processed until an event fires. bz#2158 * ssh(1): sessions started with ControlPersist were incorrectly executing a shell when the -N (no shell) option was specified. bz#3290 * ssh(1): check if IPQoS or TunnelDevice are already set before overriding. Prevents values in config files from overriding values supplied on the command line. bz#3319 * ssh(1): fix debug message when finding a private key to match a certificate being attempted for user authentication. Previously it would print the certificate's path, whereas it was supposed to be showing the private key's path. GHPR247 * sshd(8): match host certificates against host public keys, not private keys. Allows use of certificates with private keys held in a ssh-agent. bz#3524 * ssh(1): add a workaround for a bug in OpenSSH 7.4 sshd(8), which allows RSA/SHA2 signatures for public key authentication but fails to advertise this correctly via SSH2_MSG_EXT_INFO. This causes clients of these server to incorrectly match PubkeyAcceptedAlgorithmse and potentially refuse to offer valid keys. bz#3213 * sftp(1)/scp(1): degrade gracefully if a sftp-server offers the limits@openssh.com extension but fails when the client tries to invoke it. bz#3318 * ssh(1): allow ssh_config SetEnv to override $TERM, which is otherwise handled specially by the protocol. Useful in ~/.ssh/config to set TERM to something generic (e.g. "xterm" instead of "xterm-256color") for destinations that lack terminfo entries. * sftp-server(8): the limits@openssh.com extension was incorrectly marked as an operation that writes to the filesystem, which made it unavailable in sftp-server read-only mode. bz#3318 * ssh(1): fix SEGV in UpdateHostkeys debug() message, triggered when the update removed more host keys than remain present. * Many manual page fixes. - Additional changes from 8.6p1 release: = Security * sshd(8): OpenSSH 8.5 introduced the LogVerbose keyword. When this option was enabled with a set of patterns that activated logging in code that runs in the low-privilege sandboxed sshd process, the log messages were constructed in such a way that printf(3) format strings could effectively be specified the low-privilege code. = New features * sftp-server(8): add a new limits@openssh.com protocol extension that allows a client to discover various server limits, including maximum packet size and maximum read/write length. * sftp(1): use the new limits@openssh.com extension (when available) to select better transfer lengths in the client. * sshd(8): Add ModuliFile keyword to sshd_config to specify the location of the "moduli" file containing the groups for DH-GEX. * unit tests: Add a TEST_SSH_ELAPSED_TIMES environment variable to enable printing of the elapsed time in seconds of each test. = Bugfixes * ssh_config(5), sshd_config(5): sync CASignatureAlgorithms lists in manual pages with the current default. GHPR174 * ssh(1): ensure that pkcs11_del_provider() is called before exit. GHPR234 * ssh(1), sshd(8): fix problems in string->argv conversion. Multiple backslashes were not being dequoted correctly and quoted space in the middle of a string was being incorrectly split. GHPR223 * ssh(1): return non-zero exit status when killed by signal; bz#3281 * sftp-server(8): increase maximum SSH2_FXP_READ to match the maximum packet size. Also handle zero-length reads that are not explicitly banned by the spec. - Additional changes from 8.5p1 release: = Security * ssh-agent(1): fixed a double-free memory corruption that was introduced in OpenSSH 8.2 . We treat all such memory faults as potentially exploitable. This bug could be reached by an attacker with access to the agent socket. = Potentially-incompatible changes * ssh(1), sshd(8): this release changes the first-preference signature algorithm from ECDSA to ED25519. * ssh(1), sshd(8): set the TOS/DSCP specified in the configuration for interactive use prior to TCP connect. The connection phase of the SSH session is time-sensitive and often explicitly interactive. The ultimate interactive/bulk TOS/DSCP will be set after authentication completes. * ssh(1), sshd(8): remove the pre-standardization cipher rijndael-cbc@lysator.liu.se. It is an alias for aes256-cbc before it was standardized in RFC4253 (2006), has been deprecated and disabled by default since OpenSSH 7.2 (2016) and was only briefly documented in ssh.1 in 2001. * ssh(1), sshd(8): update/replace the experimental post-quantum hybrid key exchange method based on Streamlined NTRU Prime coupled with X25519. The previous sntrup4591761x25519-sha512@tinyssh.org method is replaced with sntrup761x25519-sha512@openssh.com. * ssh(1): disable CheckHostIP by default. It provides insignificant benefits while making key rotation significantly more difficult, especially for hosts behind IP-based load-balancers. = New features * ssh(1): this release enables UpdateHostkeys by default subject to some conservative preconditions: - The key was matched in the UserKnownHostsFile (and not in the GlobalKnownHostsFile). - The same key does not exist under another name. - A certificate host key is not in use. - known_hosts contains no matching wildcard hostname pattern. - VerifyHostKeyDNS is not enabled. - The default UserKnownHostsFile is in use. * ssh(1), sshd(8): add a new LogVerbose configuration directive for that allows forcing maximum debug logging by file/function/line pattern-lists. * ssh(1): when prompting the user to accept a new hostkey, display any other host names/addresses already associated with the key. * ssh(1): allow UserKnownHostsFile=none to indicate that no known_hosts file should be used to identify host keys. * ssh(1): add a ssh_config KnownHostsCommand option that allows the client to obtain known_hosts data from a command in addition to the usual files. * ssh(1): add a ssh_config PermitRemoteOpen option that allows the client to restrict the destination when RemoteForward is used with SOCKS. * ssh(1): for FIDO keys, if a signature operation fails with a "incorrect PIN" reason and no PIN was initially requested from the user, then request a PIN and retry the operation. This supports some biometric devices that fall back to requiring PIN when reading of the biometric failed, and devices that require PINs for all hosted credentials. * sshd(8): implement client address-based rate-limiting via new sshd_config(5) PerSourceMaxStartups and PerSourceNetBlockSize directives that provide more fine-grained control on a per-origin address basis than the global MaxStartups limit. = Bugfixes * ssh(1): Prefix keyboard interactive prompts with "(user@host)" to make it easier to determine which connection they are associated with in cases like scp -3, ProxyJump, etc. bz#3224 * sshd(8): fix sshd_config SetEnv directives located inside Match blocks. GHPR201 * ssh(1): when requesting a FIDO token touch on stderr, inform the user once the touch has been recorded. * ssh(1): prevent integer overflow when ridiculously large ConnectTimeout values are specified, capping the effective value (for most platforms) at 24 days. bz#3229 * ssh(1): consider the ECDSA key subtype when ordering host key algorithms in the client. * ssh(1), sshd(8): rename the PubkeyAcceptedKeyTypes keyword to PubkeyAcceptedAlgorithms. The previous name incorrectly suggested that it control allowed key algorithms, when this option actually specifies the signature algorithms that are accepted. The previous name remains available as an alias. bz#3253 * ssh(1), sshd(8): similarly, rename HostbasedKeyTypes (ssh) and HostbasedAcceptedKeyTypes (sshd) to HostbasedAcceptedAlgorithms. * sftp-server(8): add missing lsetstat@openssh.com documentation and advertisement in the server's SSH2_FXP_VERSION hello packet. * ssh(1), sshd(8): more strictly enforce KEX state-machine by banning packet types once they are received. Fixes memleak caused by duplicate SSH2_MSG_KEX_DH_GEX_REQUEST (oss-fuzz #30078). * sftp(1): allow the full range of UIDs/GIDs for chown/chgrp on 32bit platforms instead of being limited by LONG_MAX. bz#3206 * Minor man page fixes (capitalization, commas, etc.) bz#3223 * sftp(1): when doing an sftp recursive upload or download of a read-only directory, ensure that the directory is created with write and execute permissions in the interim so that the transfer can actually complete, then set the directory permission as the final step. bz#3222 * ssh-keygen(1): document the -Z, check the validity of its argument earlier and provide a better error message if it's not correct. bz#2879 * ssh(1): ignore comments at the end of config lines in ssh_config, similar to what we already do for sshd_config. bz#2320 * sshd_config(5): mention that DisableForwarding is valid in a sshd_config Match block. bz3239 * sftp(1): fix incorrect sorting of "ls -ltr" under some circumstances. bz3248. * ssh(1), sshd(8): fix potential integer truncation of (unlikely) timeout values. bz#3250 * ssh(1): make hostbased authentication send the signature algorithm in its SSH2_MSG_USERAUTH_REQUEST packets instead of the key type. This make HostbasedAcceptedAlgorithms do what it is supposed to - filter on signature algorithm and not key type. - Rebased patches: * openssh-7.7p1-IPv6_X_forwarding.patch * openssh-7.7p1-X11_trusted_forwarding.patch * openssh-7.7p1-X_forward_with_disabled_ipv6.patch * openssh-7.7p1-cavstest-ctr.patch * openssh-7.7p1-cavstest-kdf.patch * openssh-7.7p1-disable_openssl_abi_check.patch * openssh-7.7p1-eal3.patch * openssh-7.7p1-enable_PAM_by_default.patch * openssh-7.7p1-fips.patch * openssh-7.7p1-fips_checks.patch * openssh-7.7p1-host_ident.patch * openssh-7.7p1-hostname_changes_when_forwarding_X.patch * openssh-7.7p1-ldap.patch * openssh-7.7p1-no_fork-no_pid_file.patch * openssh-7.7p1-pam_check_locks.patch * openssh-7.7p1-pts_names_formatting.patch * openssh-7.7p1-remove_xauth_cookies_on_exit.patch * openssh-7.7p1-seccomp_ipc_flock.patch * openssh-7.7p1-seccomp_stat.patch * openssh-7.7p1-send_locale.patch * openssh-7.7p1-sftp_force_permissions.patch * openssh-7.7p1-sftp_print_diagnostic_messages.patch * openssh-7.7p1-systemd-notify.patch * openssh-7.9p1-keygen-preserve-perms.patch * openssh-7.9p1-revert-new-qos-defaults.patch * openssh-8.0p1-gssapi-keyex.patch * openssh-8.1p1-audit.patch * openssh-8.1p1-seccomp-clock_gettime64.patch * openssh-8.1p1-seccomp-clock_nanosleep.patch * openssh-8.1p1-seccomp-clock_nanosleep_time64.patch * openssh-8.1p1-use-openssl-kdf.patch * openssh-8.4p1-vendordir.patch * openssh-fips-ensure-approved-moduli.patch * openssh-link-with-sk.patch * openssh-reenable-dh-group14-sha1-default.patch * openssh-whitelist-syscalls.patch - Removed openssh-fix-ssh-copy-id.patch (fixed upstream). OBS-URL: https://build.opensuse.org/request/show/922068 OBS-URL: https://build.opensuse.org/package/show/network/openssh?expand=0&rev=235
2339 lines
69 KiB
Diff
2339 lines
69 KiB
Diff
Index: openssh-8.8p1/Makefile.in
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/Makefile.in
|
|
+++ openssh-8.8p1/Makefile.in
|
|
@@ -114,7 +114,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
|
|
kexsntrup761x25519.o sntrup761.o kexgen.o \
|
|
kexgssc.o \
|
|
sftp-realpath.o platform-pledge.o platform-tracing.o platform-misc.o \
|
|
- sshbuf-io.o
|
|
+ sshbuf-io.o auditstub.o
|
|
|
|
SKOBJS= ssh-sk-client.o
|
|
|
|
Index: openssh-8.8p1/audit-bsm.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/audit-bsm.c
|
|
+++ openssh-8.8p1/audit-bsm.c
|
|
@@ -373,13 +373,26 @@ audit_connection_from(const char *host,
|
|
#endif
|
|
}
|
|
|
|
+int
|
|
+audit_run_command(struct ssh *ssh, const char *command)
|
|
+{
|
|
+ /* not implemented */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
void
|
|
-audit_run_command(const char *command)
|
|
+audit_end_command(struct ssh *ssh, int handle, const char *command)
|
|
{
|
|
/* not implemented */
|
|
}
|
|
|
|
void
|
|
+audit_count_session_open(void)
|
|
+{
|
|
+ /* not necessary */
|
|
+}
|
|
+
|
|
+void
|
|
audit_session_open(struct logininfo *li)
|
|
{
|
|
/* not implemented */
|
|
@@ -391,6 +404,12 @@ audit_session_close(struct logininfo *li
|
|
/* not implemented */
|
|
}
|
|
|
|
+int
|
|
+audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv)
|
|
+{
|
|
+ /* not implemented */
|
|
+}
|
|
+
|
|
void
|
|
audit_event(struct ssh *ssh, ssh_audit_event_t event)
|
|
{
|
|
@@ -452,4 +471,28 @@ audit_event(struct ssh *ssh, ssh_audit_e
|
|
debug("%s: unhandled event %d", __func__, event);
|
|
}
|
|
}
|
|
+
|
|
+void
|
|
+audit_unsupported_body(struct ssh *ssh, int what)
|
|
+{
|
|
+ /* not implemented */
|
|
+}
|
|
+
|
|
+void
|
|
+audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid, uid_t uid)
|
|
+{
|
|
+ /* not implemented */
|
|
+}
|
|
+
|
|
+void
|
|
+audit_session_key_free_body(struct ssh * ssh, int ctos, pid_t pid, uid_t uid)
|
|
+{
|
|
+ /* not implemented */
|
|
+}
|
|
+
|
|
+void
|
|
+audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid)
|
|
+{
|
|
+ /* not implemented */
|
|
+}
|
|
#endif /* BSM */
|
|
Index: openssh-8.8p1/audit-linux.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/audit-linux.c
|
|
+++ openssh-8.8p1/audit-linux.c
|
|
@@ -33,27 +33,40 @@
|
|
|
|
#include "log.h"
|
|
#include "audit.h"
|
|
+#include "sshkey.h"
|
|
+#include "hostfile.h"
|
|
+#include "auth.h"
|
|
+#include "misc.h" /* servconf.h needs misc.h for struct ForwardOptions */
|
|
+#include "servconf.h"
|
|
#include "canohost.h"
|
|
#include "packet.h"
|
|
-
|
|
+#include "cipher.h"
|
|
+#include "channels.h"
|
|
+#include "session.h"
|
|
+
|
|
+#define AUDIT_LOG_SIZE 256
|
|
+
|
|
+extern ServerOptions options;
|
|
+extern Authctxt *the_authctxt;
|
|
+extern u_int utmp_len;
|
|
const char *audit_username(void);
|
|
|
|
-int
|
|
-linux_audit_record_event(int uid, const char *username, const char *hostname,
|
|
- const char *ip, const char *ttyn, int success)
|
|
+static void
|
|
+linux_audit_user_logxxx(int uid, const char *username,
|
|
+ const char *ip, const char *ttyn, int success, int event)
|
|
{
|
|
int audit_fd, rc, saved_errno;
|
|
|
|
if ((audit_fd = audit_open()) < 0) {
|
|
if (errno == EINVAL || errno == EPROTONOSUPPORT ||
|
|
errno == EAFNOSUPPORT)
|
|
- return 1; /* No audit support in kernel */
|
|
+ return; /* No audit support in kernel */
|
|
else
|
|
- return 0; /* Must prevent login */
|
|
+ goto fatal_report; /* Must prevent login */
|
|
}
|
|
- rc = audit_log_acct_message(audit_fd, AUDIT_USER_LOGIN,
|
|
+ rc = audit_log_acct_message(audit_fd, event,
|
|
NULL, "login", username ? username : "(unknown)",
|
|
- username == NULL ? uid : -1, hostname, ip, ttyn, success);
|
|
+ username == NULL ? uid : -1, NULL, ip, ttyn, success);
|
|
saved_errno = errno;
|
|
close(audit_fd);
|
|
|
|
@@ -65,9 +78,96 @@ linux_audit_record_event(int uid, const
|
|
rc = 0;
|
|
errno = saved_errno;
|
|
|
|
- return rc >= 0;
|
|
+ if (rc < 0) {
|
|
+fatal_report:
|
|
+ fatal("linux_audit_write_entry failed: %s", strerror(errno));
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+linux_audit_user_auth(int uid, const char *username,
|
|
+ const char *ip, const char *ttyn, int success, int event)
|
|
+{
|
|
+ int audit_fd, rc, saved_errno;
|
|
+ static const char *event_name[] = {
|
|
+ "maxtries exceeded",
|
|
+ "root denied",
|
|
+ "success",
|
|
+ "none",
|
|
+ "password",
|
|
+ "challenge-response",
|
|
+ "pubkey",
|
|
+ "hostbased",
|
|
+ "gssapi",
|
|
+ "invalid user",
|
|
+ "nologin",
|
|
+ "connection closed",
|
|
+ "connection abandoned",
|
|
+ "unknown"
|
|
+ };
|
|
+
|
|
+ audit_fd = audit_open();
|
|
+ if (audit_fd < 0) {
|
|
+ if (errno == EINVAL || errno == EPROTONOSUPPORT ||
|
|
+ errno == EAFNOSUPPORT)
|
|
+ return; /* No audit support in kernel */
|
|
+ else
|
|
+ goto fatal_report; /* Must prevent login */
|
|
+ }
|
|
+
|
|
+ if ((event < 0) || (event > SSH_AUDIT_UNKNOWN))
|
|
+ event = SSH_AUDIT_UNKNOWN;
|
|
+
|
|
+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH,
|
|
+ NULL, event_name[event], username ? username : "(unknown)",
|
|
+ username == NULL ? uid : -1, NULL, ip, ttyn, success);
|
|
+ saved_errno = errno;
|
|
+ close(audit_fd);
|
|
+ /*
|
|
+ * Do not report error if the error is EPERM and sshd is run as non
|
|
+ * root user.
|
|
+ */
|
|
+ if ((rc == -EPERM) && (geteuid() != 0))
|
|
+ rc = 0;
|
|
+ errno = saved_errno;
|
|
+ if (rc < 0) {
|
|
+fatal_report:
|
|
+ fatal("linux_audit_write_entry failed: %s", strerror(errno));
|
|
+ }
|
|
+}
|
|
+
|
|
+int
|
|
+audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv)
|
|
+{
|
|
+ char buf[AUDIT_LOG_SIZE];
|
|
+ int audit_fd, rc, saved_errno;
|
|
+
|
|
+ audit_fd = audit_open();
|
|
+ if (audit_fd < 0) {
|
|
+ if (errno == EINVAL || errno == EPROTONOSUPPORT ||
|
|
+ errno == EAFNOSUPPORT)
|
|
+ return 1; /* No audit support in kernel */
|
|
+ else
|
|
+ return 0; /* Must prevent login */
|
|
+ }
|
|
+ snprintf(buf, sizeof(buf), "%s_auth grantors=auth-key", host_user ? "pubkey" : "hostbased");
|
|
+ rc = audit_log_acct_message(audit_fd, AUDIT_USER_AUTH, NULL,
|
|
+ buf, audit_username(), -1, NULL, ssh_remote_ipaddr(ssh), NULL, rv);
|
|
+ if ((rc < 0) && ((rc != -1) || (getuid() == 0)))
|
|
+ goto out;
|
|
+ snprintf(buf, sizeof(buf), "op=negotiate kind=auth-key fp=%s", fp);
|
|
+ rc = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER, buf, NULL,
|
|
+ ssh_remote_ipaddr(ssh), NULL, rv);
|
|
+out:
|
|
+ saved_errno = errno;
|
|
+ audit_close(audit_fd);
|
|
+ errno = saved_errno;
|
|
+ /* do not report error if the error is EPERM and sshd is run as non root user */
|
|
+ return (rc >= 0) || ((rc == -EPERM) && (getuid() != 0));
|
|
}
|
|
|
|
+static int user_login_count = 0;
|
|
+
|
|
/* Below is the sshd audit API code */
|
|
|
|
void
|
|
@@ -76,49 +176,210 @@ audit_connection_from(const char *host,
|
|
/* not implemented */
|
|
}
|
|
|
|
+int
|
|
+audit_run_command(struct ssh *ssh, const char *command)
|
|
+{
|
|
+ if (!user_login_count++)
|
|
+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
|
|
+ ssh_remote_ipaddr(ssh),
|
|
+ "ssh", 1, AUDIT_USER_LOGIN);
|
|
+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
|
|
+ ssh_remote_ipaddr(ssh),
|
|
+ "ssh", 1, AUDIT_USER_START);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
void
|
|
-audit_run_command(const char *command)
|
|
+audit_end_command(struct ssh *ssh, int handle, const char *command)
|
|
{
|
|
- /* not implemented */
|
|
+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
|
|
+ ssh_remote_ipaddr(ssh),
|
|
+ "ssh", 1, AUDIT_USER_END);
|
|
+ if (user_login_count && !--user_login_count)
|
|
+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
|
|
+ ssh_remote_ipaddr(ssh),
|
|
+ "ssh", 1, AUDIT_USER_LOGOUT);
|
|
+}
|
|
+
|
|
+void
|
|
+audit_count_session_open(void)
|
|
+{
|
|
+ user_login_count++;
|
|
}
|
|
|
|
void
|
|
audit_session_open(struct logininfo *li)
|
|
{
|
|
- if (linux_audit_record_event(li->uid, NULL, li->hostname, NULL,
|
|
- li->line, 1) == 0)
|
|
- fatal("linux_audit_write_entry failed: %s", strerror(errno));
|
|
+ if (!user_login_count++)
|
|
+ linux_audit_user_logxxx(li->uid, NULL, li->hostname,
|
|
+ li->line, 1, AUDIT_USER_LOGIN);
|
|
+ linux_audit_user_logxxx(li->uid, NULL, li->hostname,
|
|
+ li->line, 1, AUDIT_USER_START);
|
|
}
|
|
|
|
void
|
|
audit_session_close(struct logininfo *li)
|
|
{
|
|
- /* not implemented */
|
|
+ linux_audit_user_logxxx(li->uid, NULL, li->hostname,
|
|
+ li->line, 1, AUDIT_USER_END);
|
|
+ if (user_login_count && !--user_login_count)
|
|
+ linux_audit_user_logxxx(li->uid, NULL, li->hostname,
|
|
+ li->line, 1, AUDIT_USER_LOGOUT);
|
|
}
|
|
|
|
void
|
|
audit_event(struct ssh *ssh, ssh_audit_event_t event)
|
|
{
|
|
switch(event) {
|
|
- case SSH_AUTH_SUCCESS:
|
|
- case SSH_CONNECTION_CLOSE:
|
|
case SSH_NOLOGIN:
|
|
- case SSH_LOGIN_EXCEED_MAXTRIES:
|
|
case SSH_LOGIN_ROOT_DENIED:
|
|
+ linux_audit_user_auth(-1, audit_username(),
|
|
+ ssh_remote_ipaddr(ssh), "ssh", 0, event);
|
|
+ linux_audit_user_logxxx(-1, audit_username(),
|
|
+ ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN);
|
|
break;
|
|
- case SSH_AUTH_FAIL_NONE:
|
|
case SSH_AUTH_FAIL_PASSWD:
|
|
+ if (options.use_pam)
|
|
+ break;
|
|
+ case SSH_LOGIN_EXCEED_MAXTRIES:
|
|
case SSH_AUTH_FAIL_KBDINT:
|
|
case SSH_AUTH_FAIL_PUBKEY:
|
|
case SSH_AUTH_FAIL_HOSTBASED:
|
|
case SSH_AUTH_FAIL_GSSAPI:
|
|
+ linux_audit_user_auth(-1, audit_username(),
|
|
+ ssh_remote_ipaddr(ssh), "ssh", 0, event);
|
|
+ break;
|
|
+
|
|
+ case SSH_CONNECTION_CLOSE:
|
|
+ if (user_login_count) {
|
|
+ while (user_login_count--)
|
|
+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
|
|
+ ssh_remote_ipaddr(ssh),
|
|
+ "ssh", 1, AUDIT_USER_END);
|
|
+ linux_audit_user_logxxx(the_authctxt->pw->pw_uid, NULL,
|
|
+ ssh_remote_ipaddr(ssh),
|
|
+ "ssh", 1, AUDIT_USER_LOGOUT);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case SSH_CONNECTION_ABANDON:
|
|
case SSH_INVALID_USER:
|
|
- linux_audit_record_event(-1, audit_username(), NULL,
|
|
- ssh_remote_ipaddr(ssh), "sshd", 0);
|
|
+ linux_audit_user_logxxx(-1, audit_username(),
|
|
+ ssh_remote_ipaddr(ssh), "ssh", 0, AUDIT_USER_LOGIN);
|
|
break;
|
|
default:
|
|
debug("%s: unhandled event %d", __func__, event);
|
|
break;
|
|
}
|
|
}
|
|
+
|
|
+void
|
|
+audit_unsupported_body(struct ssh *ssh, int what)
|
|
+{
|
|
+#ifdef AUDIT_CRYPTO_SESSION
|
|
+ char buf[AUDIT_LOG_SIZE];
|
|
+ const static char *name[] = { "cipher", "mac", "comp" };
|
|
+ char *s;
|
|
+ int audit_fd;
|
|
+
|
|
+ snprintf(buf, sizeof(buf), "op=unsupported-%s direction=? cipher=? ksize=? rport=%d laddr=%s lport=%d ",
|
|
+ name[what], ssh_remote_port(ssh), (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))),
|
|
+ ssh_local_port(ssh));
|
|
+ free(s);
|
|
+ audit_fd = audit_open();
|
|
+ if (audit_fd < 0)
|
|
+ /* no problem, the next instruction will be fatal() */
|
|
+ return;
|
|
+ audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
|
|
+ buf, NULL, ssh_remote_ipaddr(ssh), NULL, 0);
|
|
+ audit_close(audit_fd);
|
|
+#endif
|
|
+}
|
|
+
|
|
+const static char *direction[] = { "from-server", "from-client", "both" };
|
|
+
|
|
+void
|
|
+audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress,
|
|
+ char *pfs, pid_t pid, uid_t uid)
|
|
+{
|
|
+#ifdef AUDIT_CRYPTO_SESSION
|
|
+ char buf[AUDIT_LOG_SIZE];
|
|
+ int audit_fd, audit_ok;
|
|
+ const struct sshcipher *cipher = cipher_by_name(enc);
|
|
+ char *s;
|
|
+
|
|
+ snprintf(buf, sizeof(buf), "op=start direction=%s cipher=%s ksize=%d mac=%s pfs=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
|
|
+ direction[ctos], enc, cipher ? 8 * cipher->key_len : 0, mac, pfs,
|
|
+ (intmax_t)pid, (intmax_t)uid,
|
|
+ ssh_remote_port(ssh), (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))), ssh_local_port(ssh));
|
|
+ free(s);
|
|
+ audit_fd = audit_open();
|
|
+ if (audit_fd < 0) {
|
|
+ if (errno == EINVAL || errno == EPROTONOSUPPORT ||
|
|
+ errno == EAFNOSUPPORT)
|
|
+ return; /* No audit support in kernel */
|
|
+ else
|
|
+ fatal("cannot open audit"); /* Must prevent login */
|
|
+ }
|
|
+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_SESSION,
|
|
+ buf, NULL, ssh_remote_ipaddr(ssh), NULL, 1);
|
|
+ audit_close(audit_fd);
|
|
+ /* do not abort if the error is EPERM and sshd is run as non root user */
|
|
+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
|
|
+ fatal("cannot write into audit"); /* Must prevent login */
|
|
+#endif
|
|
+}
|
|
+
|
|
+void
|
|
+audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid)
|
|
+{
|
|
+ char buf[AUDIT_LOG_SIZE];
|
|
+ int audit_fd, audit_ok;
|
|
+ char *s;
|
|
+
|
|
+ snprintf(buf, sizeof(buf), "op=destroy kind=session fp=? direction=%s spid=%jd suid=%jd rport=%d laddr=%s lport=%d ",
|
|
+ direction[ctos], (intmax_t)pid, (intmax_t)uid,
|
|
+ ssh_remote_port(ssh),
|
|
+ (s = get_local_ipaddr(ssh_packet_get_connection_in(ssh))),
|
|
+ ssh_local_port(ssh));
|
|
+ free(s);
|
|
+ audit_fd = audit_open();
|
|
+ if (audit_fd < 0) {
|
|
+ if (errno != EINVAL && errno != EPROTONOSUPPORT &&
|
|
+ errno != EAFNOSUPPORT)
|
|
+ error("cannot open audit");
|
|
+ return;
|
|
+ }
|
|
+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
|
|
+ buf, NULL, ssh_remote_ipaddr(ssh), NULL, 1);
|
|
+ audit_close(audit_fd);
|
|
+ /* do not abort if the error is EPERM and sshd is run as non root user */
|
|
+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
|
|
+ error("cannot write into audit");
|
|
+}
|
|
+
|
|
+void
|
|
+audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid)
|
|
+{
|
|
+ char buf[AUDIT_LOG_SIZE];
|
|
+ int audit_fd, audit_ok;
|
|
+
|
|
+ snprintf(buf, sizeof(buf), "op=destroy kind=server fp=%s direction=? spid=%jd suid=%jd ",
|
|
+ fp, (intmax_t)pid, (intmax_t)uid);
|
|
+ audit_fd = audit_open();
|
|
+ if (audit_fd < 0) {
|
|
+ if (errno != EINVAL && errno != EPROTONOSUPPORT &&
|
|
+ errno != EAFNOSUPPORT)
|
|
+ error("cannot open audit");
|
|
+ return;
|
|
+ }
|
|
+ audit_ok = audit_log_user_message(audit_fd, AUDIT_CRYPTO_KEY_USER,
|
|
+ buf, NULL,
|
|
+ listening_for_clients() ? NULL : ssh_remote_ipaddr(ssh),
|
|
+ NULL, 1);
|
|
+ audit_close(audit_fd);
|
|
+ /* do not abort if the error is EPERM and sshd is run as non root user */
|
|
+ if ((audit_ok < 0) && ((audit_ok != -1) || (getuid() == 0)))
|
|
+ error("cannot write into audit");
|
|
+}
|
|
#endif /* USE_LINUX_AUDIT */
|
|
Index: openssh-8.8p1/audit.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/audit.c
|
|
+++ openssh-8.8p1/audit.c
|
|
@@ -34,6 +34,12 @@
|
|
#include "log.h"
|
|
#include "hostfile.h"
|
|
#include "auth.h"
|
|
+#include "ssh-gss.h"
|
|
+#include "monitor_wrap.h"
|
|
+#include "xmalloc.h"
|
|
+#include "misc.h"
|
|
+#include "servconf.h"
|
|
+#include "ssherr.h"
|
|
|
|
/*
|
|
* Care must be taken when using this since it WILL NOT be initialized when
|
|
@@ -41,6 +47,7 @@
|
|
* audit_event(CONNECTION_ABANDON) is called. Test for NULL before using.
|
|
*/
|
|
extern Authctxt *the_authctxt;
|
|
+extern ServerOptions options;
|
|
|
|
/* Maybe add the audit class to struct Authmethod? */
|
|
ssh_audit_event_t
|
|
@@ -69,13 +76,10 @@ audit_classify_auth(const char *method)
|
|
const char *
|
|
audit_username(void)
|
|
{
|
|
- static const char unknownuser[] = "(unknown user)";
|
|
- static const char invaliduser[] = "(invalid user)";
|
|
+ static const char unknownuser[] = "(unknown)";
|
|
|
|
- if (the_authctxt == NULL || the_authctxt->user == NULL)
|
|
+ if (the_authctxt == NULL || the_authctxt->user == NULL || !the_authctxt->valid)
|
|
return (unknownuser);
|
|
- if (!the_authctxt->valid)
|
|
- return (invaliduser);
|
|
return (the_authctxt->user);
|
|
}
|
|
|
|
@@ -109,6 +113,35 @@ audit_event_lookup(ssh_audit_event_t ev)
|
|
return(event_lookup[i].name);
|
|
}
|
|
|
|
+void
|
|
+audit_key(struct ssh *ssh, int host_user, int *rv, const struct sshkey *key)
|
|
+{
|
|
+ char *fp;
|
|
+
|
|
+ fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_HEX);
|
|
+ if (audit_keyusage(ssh, host_user, fp, (*rv == 0)) == 0)
|
|
+ *rv = -SSH_ERR_INTERNAL_ERROR;
|
|
+ free(fp);
|
|
+}
|
|
+
|
|
+void
|
|
+audit_unsupported(struct ssh *ssh, int what)
|
|
+{
|
|
+ PRIVSEP(audit_unsupported_body(ssh, what));
|
|
+}
|
|
+
|
|
+void
|
|
+audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs)
|
|
+{
|
|
+ PRIVSEP(audit_kex_body(ssh, ctos, enc, mac, comp, pfs, getpid(), getuid()));
|
|
+}
|
|
+
|
|
+void
|
|
+audit_session_key_free(struct ssh *ssh, int ctos)
|
|
+{
|
|
+ PRIVSEP(audit_session_key_free_body(ssh, ctos, getpid(), getuid()));
|
|
+}
|
|
+
|
|
# ifndef CUSTOM_SSH_AUDIT_EVENTS
|
|
/*
|
|
* Null implementations of audit functions.
|
|
@@ -138,6 +171,17 @@ audit_event(struct ssh *ssh, ssh_audit_e
|
|
}
|
|
|
|
/*
|
|
+ * Called when a child process has called, or will soon call,
|
|
+ * audit_session_open.
|
|
+ */
|
|
+void
|
|
+audit_count_session_open(void)
|
|
+{
|
|
+ debug("audit count session open euid %d user %s", geteuid(),
|
|
+ audit_username());
|
|
+}
|
|
+
|
|
+/*
|
|
* Called when a user session is started. Argument is the tty allocated to
|
|
* the session, or NULL if no tty was allocated.
|
|
*
|
|
@@ -172,13 +216,82 @@ audit_session_close(struct logininfo *li
|
|
/*
|
|
* This will be called when a user runs a non-interactive command. Note that
|
|
* it may be called multiple times for a single connection since SSH2 allows
|
|
- * multiple sessions within a single connection.
|
|
+ * multiple sessions within a single connection. Returns a "handle" for
|
|
+ * audit_end_command.
|
|
*/
|
|
-void
|
|
-audit_run_command(const char *command)
|
|
+int
|
|
+audit_run_command(struct ssh *ssh, const char *command)
|
|
{
|
|
debug("audit run command euid %d user %s command '%.200s'", geteuid(),
|
|
audit_username(), command);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This will be called when the non-interactive command finishes. Note that
|
|
+ * it may be called multiple times for a single connection since SSH2 allows
|
|
+ * multiple sessions within a single connection. "handle" should come from
|
|
+ * the corresponding audit_run_command.
|
|
+ */
|
|
+void
|
|
+audit_end_command(struct ssh *ssh, int handle, const char *command)
|
|
+{
|
|
+ debug("audit end nopty exec euid %d user %s command '%.200s'", geteuid(),
|
|
+ audit_username(), command);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This will be called when user is successfully autherized by the RSA1/RSA/DSA key.
|
|
+ *
|
|
+ * Type is the key type, len is the key length(byte) and fp is the fingerprint of the key.
|
|
+ */
|
|
+int
|
|
+audit_keyusage(struct ssh *ssh, int host_user, char *fp, int rv)
|
|
+{
|
|
+ debug("audit %s key usage euid %d user %s fingerprint %s, result %d",
|
|
+ host_user ? "pubkey" : "hostbased", geteuid(), audit_username(),
|
|
+ fp, rv);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This will be called when the protocol negotiation fails.
|
|
+ */
|
|
+void
|
|
+audit_unsupported_body(struct ssh *ssh, int what)
|
|
+{
|
|
+ debug("audit unsupported protocol euid %d type %d", geteuid(), what);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This will be called on succesfull protocol negotiation.
|
|
+ */
|
|
+void
|
|
+audit_kex_body(struct ssh *ssh, int ctos, char *enc, char *mac, char *compress, char *pfs, pid_t pid,
|
|
+ uid_t uid)
|
|
+{
|
|
+ debug("audit protocol negotiation euid %d direction %d cipher %s mac %s compresion %s pfs %s from pid %ld uid %u",
|
|
+ (unsigned)geteuid(), ctos, enc, mac, compress, pfs, (long)pid,
|
|
+ (unsigned)uid);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This will be called on succesfull session key discard
|
|
+ */
|
|
+void
|
|
+audit_session_key_free_body(struct ssh *, int ctos, pid_t pid, uid_t uid)
|
|
+{
|
|
+ debug("audit session key discard euid %u direction %d from pid %ld uid %u",
|
|
+ (unsigned)geteuid(), ctos, (long)pid, (unsigned)uid);
|
|
+}
|
|
+
|
|
+/*
|
|
+ * This will be called on destroy private part of the server key
|
|
+ */
|
|
+void
|
|
+audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid)
|
|
+{
|
|
+ debug("audit destroy sensitive data euid %d fingerprint %s from pid %ld uid %u",
|
|
+ geteuid(), fp, (long)pid, (unsigned)uid);
|
|
}
|
|
# endif /* !defined CUSTOM_SSH_AUDIT_EVENTS */
|
|
#endif /* SSH_AUDIT_EVENTS */
|
|
Index: openssh-8.8p1/audit.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/audit.h
|
|
+++ openssh-8.8p1/audit.h
|
|
@@ -26,6 +26,7 @@
|
|
# define _SSH_AUDIT_H
|
|
|
|
#include "loginrec.h"
|
|
+#include "sshkey.h"
|
|
|
|
struct ssh;
|
|
|
|
@@ -45,13 +46,32 @@ enum ssh_audit_event_type {
|
|
SSH_CONNECTION_ABANDON, /* closed without completing auth */
|
|
SSH_AUDIT_UNKNOWN
|
|
};
|
|
+
|
|
+enum ssh_audit_kex {
|
|
+ SSH_AUDIT_UNSUPPORTED_CIPHER,
|
|
+ SSH_AUDIT_UNSUPPORTED_MAC,
|
|
+ SSH_AUDIT_UNSUPPORTED_COMPRESSION
|
|
+};
|
|
typedef enum ssh_audit_event_type ssh_audit_event_t;
|
|
|
|
+int listening_for_clients(void);
|
|
+
|
|
void audit_connection_from(const char *, int);
|
|
void audit_event(struct ssh *, ssh_audit_event_t);
|
|
+void audit_count_session_open(void);
|
|
void audit_session_open(struct logininfo *);
|
|
void audit_session_close(struct logininfo *);
|
|
-void audit_run_command(const char *);
|
|
+int audit_run_command(struct ssh *, const char *);
|
|
+void audit_end_command(struct ssh *, int, const char *);
|
|
ssh_audit_event_t audit_classify_auth(const char *);
|
|
+int audit_keyusage(struct ssh *, int, char *, int);
|
|
+void audit_key(struct ssh *, int, int *, const struct sshkey *);
|
|
+void audit_unsupported(struct ssh *, int);
|
|
+void audit_kex(struct ssh *, int, char *, char *, char *, char *);
|
|
+void audit_unsupported_body(struct ssh *, int);
|
|
+void audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t);
|
|
+void audit_session_key_free(struct ssh *, int ctos);
|
|
+void audit_session_key_free_body(struct ssh *, int ctos, pid_t, uid_t);
|
|
+void audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t);
|
|
|
|
#endif /* _SSH_AUDIT_H */
|
|
Index: openssh-8.8p1/auditstub.c
|
|
===================================================================
|
|
--- /dev/null
|
|
+++ openssh-8.8p1/auditstub.c
|
|
@@ -0,0 +1,52 @@
|
|
+/* $Id: auditstub.c,v 1.1 jfch Exp $ */
|
|
+
|
|
+/*
|
|
+ * Copyright 2010 Red Hat, Inc. All rights reserved.
|
|
+ * Use is subject to license terms.
|
|
+ *
|
|
+ * 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.
|
|
+ *
|
|
+ * Red Hat author: Jan F. Chadima <jchadima@redhat.com>
|
|
+ */
|
|
+
|
|
+#include <sys/types.h>
|
|
+
|
|
+struct ssh;
|
|
+
|
|
+void
|
|
+audit_unsupported(struct ssh *ssh, int n)
|
|
+{
|
|
+}
|
|
+
|
|
+void
|
|
+audit_kex(struct ssh *ssh, int ctos, char *enc, char *mac, char *comp, char *pfs)
|
|
+{
|
|
+}
|
|
+
|
|
+void
|
|
+audit_session_key_free(struct ssh *ssh, int ctos)
|
|
+{
|
|
+}
|
|
+
|
|
+void
|
|
+audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid)
|
|
+{
|
|
+}
|
|
Index: openssh-8.8p1/auth.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/auth.c
|
|
+++ openssh-8.8p1/auth.c
|
|
@@ -599,9 +599,6 @@ getpwnamallow(struct ssh *ssh, const cha
|
|
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))
|
|
Index: openssh-8.8p1/auth.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/auth.h
|
|
+++ openssh-8.8p1/auth.h
|
|
@@ -189,6 +189,8 @@ struct passwd * getpwnamallow(struct ssh
|
|
|
|
char *expand_authorized_keys(const char *, struct passwd *pw);
|
|
char *authorized_principals_file(struct passwd *);
|
|
+int user_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t,
|
|
+ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **);
|
|
|
|
FILE *auth_openkeyfile(const char *, struct passwd *, int);
|
|
FILE *auth_openprincipals(const char *, struct passwd *, int);
|
|
@@ -208,6 +210,8 @@ struct sshkey *get_hostkey_private_by_ty
|
|
int get_hostkey_index(struct sshkey *, int, struct ssh *);
|
|
int sshd_hostkey_sign(struct ssh *, struct sshkey *, struct sshkey *,
|
|
u_char **, size_t *, const u_char *, size_t, const char *);
|
|
+int hostbased_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t,
|
|
+ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **);
|
|
|
|
/* Key / cert options linkage to auth layer */
|
|
const struct sshauthopt *auth_options(struct ssh *);
|
|
Index: openssh-8.8p1/auth2-hostbased.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/auth2-hostbased.c
|
|
+++ openssh-8.8p1/auth2-hostbased.c
|
|
@@ -149,7 +149,7 @@ userauth_hostbased(struct ssh *ssh)
|
|
authenticated = 0;
|
|
if (PRIVSEP(hostbased_key_allowed(ssh, authctxt->pw, cuser,
|
|
chost, key)) &&
|
|
- PRIVSEP(sshkey_verify(key, sig, slen,
|
|
+ PRIVSEP(hostbased_key_verify(ssh, key, sig, slen,
|
|
sshbuf_ptr(b), sshbuf_len(b), pkalg, ssh->compat, NULL)) == 0)
|
|
authenticated = 1;
|
|
|
|
@@ -166,6 +166,19 @@ done:
|
|
return authenticated;
|
|
}
|
|
|
|
+int
|
|
+hostbased_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig,
|
|
+ size_t slen, const u_char *data, size_t datalen, const char *pkalg, u_int compat, struct sshkey_sig_details **sigdet)
|
|
+{
|
|
+ int rv;
|
|
+
|
|
+ rv = sshkey_verify(key, sig, slen, data, datalen, pkalg, compat, sigdet);
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ audit_key(ssh, 0, &rv, key);
|
|
+#endif
|
|
+ return rv;
|
|
+}
|
|
+
|
|
/* return 1 if given hostkey is allowed */
|
|
int
|
|
hostbased_key_allowed(struct ssh *ssh, struct passwd *pw,
|
|
Index: openssh-8.8p1/auth2-pubkey.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/auth2-pubkey.c
|
|
+++ openssh-8.8p1/auth2-pubkey.c
|
|
@@ -203,7 +203,7 @@ userauth_pubkey(struct ssh *ssh)
|
|
/* test for correct signature */
|
|
authenticated = 0;
|
|
if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) &&
|
|
- PRIVSEP(sshkey_verify(key, sig, slen,
|
|
+ PRIVSEP(user_key_verify(ssh, key, sig, slen,
|
|
sshbuf_ptr(b), sshbuf_len(b),
|
|
(ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL,
|
|
ssh->compat, &sig_details)) == 0) {
|
|
@@ -295,6 +295,19 @@ done:
|
|
return authenticated;
|
|
}
|
|
|
|
+int
|
|
+user_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig,
|
|
+ size_t slen, const u_char *data, size_t datalen, const char *pkalg, u_int compat, struct sshkey_sig_details **sigdet)
|
|
+{
|
|
+ int rv;
|
|
+
|
|
+ rv = sshkey_verify(key, sig, slen, data, datalen, pkalg, compat, sigdet);
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ audit_key(ssh, 1, &rv, key);
|
|
+#endif
|
|
+ return rv;
|
|
+}
|
|
+
|
|
static int
|
|
match_principals_option(const char *principal_list, struct sshkey_cert *cert)
|
|
{
|
|
Index: openssh-8.8p1/auth2.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/auth2.c
|
|
+++ openssh-8.8p1/auth2.c
|
|
@@ -290,9 +290,6 @@ input_userauth_request(int type, u_int32
|
|
} else {
|
|
/* Invalid user, fake password information */
|
|
authctxt->pw = fakepw();
|
|
-#ifdef SSH_AUDIT_EVENTS
|
|
- PRIVSEP(audit_event(ssh, SSH_INVALID_USER));
|
|
-#endif
|
|
}
|
|
#ifdef USE_PAM
|
|
if (options.use_pam)
|
|
Index: openssh-8.8p1/cipher.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/cipher.c
|
|
+++ openssh-8.8p1/cipher.c
|
|
@@ -58,25 +58,6 @@
|
|
#define EVP_CIPHER_CTX void
|
|
#endif
|
|
|
|
-struct sshcipher {
|
|
- char *name;
|
|
- u_int block_size;
|
|
- u_int key_len;
|
|
- u_int iv_len; /* defaults to block_size */
|
|
- u_int auth_len;
|
|
- u_int flags;
|
|
-#define CFLAG_CBC (1<<0)
|
|
-#define CFLAG_CHACHAPOLY (1<<1)
|
|
-#define CFLAG_AESCTR (1<<2)
|
|
-#define CFLAG_NONE (1<<3)
|
|
-#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */
|
|
-#ifdef WITH_OPENSSL
|
|
- const EVP_CIPHER *(*evptype)(void);
|
|
-#else
|
|
- void *ignored;
|
|
-#endif
|
|
-};
|
|
-
|
|
static const struct sshcipher ciphers_all[] = {
|
|
#ifdef WITH_OPENSSL
|
|
#ifndef OPENSSL_NO_DES
|
|
@@ -460,7 +441,7 @@ cipher_get_length(struct sshcipher_ctx *
|
|
void
|
|
cipher_free(struct sshcipher_ctx *cc)
|
|
{
|
|
- if (cc == NULL)
|
|
+ if (cc == NULL || cc->cipher == NULL)
|
|
return;
|
|
if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) {
|
|
chachapoly_free(cc->cp_ctx);
|
|
Index: openssh-8.8p1/cipher.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/cipher.h
|
|
+++ openssh-8.8p1/cipher.h
|
|
@@ -47,7 +47,25 @@
|
|
#define CIPHER_ENCRYPT 1
|
|
#define CIPHER_DECRYPT 0
|
|
|
|
-struct sshcipher;
|
|
+struct sshcipher {
|
|
+ char *name;
|
|
+ u_int block_size;
|
|
+ u_int key_len;
|
|
+ u_int iv_len; /* defaults to block_size */
|
|
+ u_int auth_len;
|
|
+ u_int flags;
|
|
+#define CFLAG_CBC (1<<0)
|
|
+#define CFLAG_CHACHAPOLY (1<<1)
|
|
+#define CFLAG_AESCTR (1<<2)
|
|
+#define CFLAG_NONE (1<<3)
|
|
+#define CFLAG_INTERNAL CFLAG_NONE /* Don't use "none" for packets */
|
|
+#ifdef WITH_OPENSSL
|
|
+ const EVP_CIPHER *(*evptype)(void);
|
|
+#else
|
|
+ void *ignored;
|
|
+#endif
|
|
+};
|
|
+
|
|
struct sshcipher_ctx {
|
|
int plaintext;
|
|
int encrypt;
|
|
Index: openssh-8.8p1/kex.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/kex.c
|
|
+++ openssh-8.8p1/kex.c
|
|
@@ -62,6 +62,7 @@
|
|
#include "ssherr.h"
|
|
#include "sshbuf.h"
|
|
#include "digest.h"
|
|
+#include "audit.h"
|
|
|
|
#ifdef GSSAPI
|
|
#include "ssh-gss.h"
|
|
@@ -859,12 +860,16 @@ kex_start_rekex(struct ssh *ssh)
|
|
}
|
|
|
|
static int
|
|
-choose_enc(struct sshenc *enc, char *client, char *server)
|
|
+choose_enc(struct ssh *ssh, struct sshenc *enc, char *client, char *server)
|
|
{
|
|
char *name = match_list(client, server, NULL);
|
|
|
|
- if (name == NULL)
|
|
+ if (name == NULL) {
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ audit_unsupported(ssh, SSH_AUDIT_UNSUPPORTED_CIPHER);
|
|
+#endif
|
|
return SSH_ERR_NO_CIPHER_ALG_MATCH;
|
|
+ }
|
|
if ((enc->cipher = cipher_by_name(name)) == NULL) {
|
|
error_f("unsupported cipher %s", name);
|
|
free(name);
|
|
@@ -885,8 +890,12 @@ choose_mac(struct ssh *ssh, struct sshma
|
|
{
|
|
char *name = match_list(client, server, NULL);
|
|
|
|
- if (name == NULL)
|
|
+ if (name == NULL) {
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ audit_unsupported(ssh, SSH_AUDIT_UNSUPPORTED_MAC);
|
|
+#endif
|
|
return SSH_ERR_NO_MAC_ALG_MATCH;
|
|
+ }
|
|
if (mac_setup(mac, name) < 0) {
|
|
error_f("unsupported MAC %s", name);
|
|
free(name);
|
|
@@ -899,12 +908,16 @@ choose_mac(struct ssh *ssh, struct sshma
|
|
}
|
|
|
|
static int
|
|
-choose_comp(struct sshcomp *comp, char *client, char *server)
|
|
+choose_comp(struct ssh *ssh, struct sshcomp *comp, char *client, char *server)
|
|
{
|
|
char *name = match_list(client, server, NULL);
|
|
|
|
- if (name == NULL)
|
|
+ if (name == NULL) {
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ audit_unsupported(ssh, SSH_AUDIT_UNSUPPORTED_COMPRESSION);
|
|
+#endif
|
|
return SSH_ERR_NO_COMPRESS_ALG_MATCH;
|
|
+ }
|
|
#ifdef WITH_ZLIB
|
|
if (strcmp(name, "zlib@openssh.com") == 0) {
|
|
comp->type = COMP_DELAYED;
|
|
@@ -1045,7 +1058,7 @@ kex_choose_conf(struct ssh *ssh)
|
|
nenc = ctos ? PROPOSAL_ENC_ALGS_CTOS : PROPOSAL_ENC_ALGS_STOC;
|
|
nmac = ctos ? PROPOSAL_MAC_ALGS_CTOS : PROPOSAL_MAC_ALGS_STOC;
|
|
ncomp = ctos ? PROPOSAL_COMP_ALGS_CTOS : PROPOSAL_COMP_ALGS_STOC;
|
|
- if ((r = choose_enc(&newkeys->enc, cprop[nenc],
|
|
+ if ((r = choose_enc(ssh, &newkeys->enc, cprop[nenc],
|
|
sprop[nenc])) != 0) {
|
|
kex->failed_choice = peer[nenc];
|
|
peer[nenc] = NULL;
|
|
@@ -1060,7 +1073,7 @@ kex_choose_conf(struct ssh *ssh)
|
|
peer[nmac] = NULL;
|
|
goto out;
|
|
}
|
|
- if ((r = choose_comp(&newkeys->comp, cprop[ncomp],
|
|
+ if ((r = choose_comp(ssh, &newkeys->comp, cprop[ncomp],
|
|
sprop[ncomp])) != 0) {
|
|
kex->failed_choice = peer[ncomp];
|
|
peer[ncomp] = NULL;
|
|
@@ -1083,6 +1096,10 @@ kex_choose_conf(struct ssh *ssh)
|
|
dh_need = MAXIMUM(dh_need, newkeys->enc.block_size);
|
|
dh_need = MAXIMUM(dh_need, newkeys->enc.iv_len);
|
|
dh_need = MAXIMUM(dh_need, newkeys->mac.key_len);
|
|
+ debug("kex: %s need=%d dh_need=%d", kex->name, need, dh_need);
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ audit_kex(ssh, mode, newkeys->enc.name, newkeys->mac.name, newkeys->comp.name, kex->name);
|
|
+#endif
|
|
}
|
|
/* XXX need runden? */
|
|
kex->we_need = need;
|
|
@@ -1250,6 +1267,36 @@ dump_digest(const char *msg, const u_cha
|
|
}
|
|
#endif
|
|
|
|
+static void
|
|
+enc_destroy(struct sshenc *enc)
|
|
+{
|
|
+ if (enc == NULL)
|
|
+ return;
|
|
+
|
|
+ if (enc->key) {
|
|
+ memset(enc->key, 0, enc->key_len);
|
|
+ free(enc->key);
|
|
+ }
|
|
+
|
|
+ if (enc->iv) {
|
|
+ memset(enc->iv, 0, enc->iv_len);
|
|
+ free(enc->iv);
|
|
+ }
|
|
+
|
|
+ memset(enc, 0, sizeof(*enc));
|
|
+}
|
|
+
|
|
+void
|
|
+newkeys_destroy(struct newkeys *newkeys)
|
|
+{
|
|
+ if (newkeys == NULL)
|
|
+ return;
|
|
+
|
|
+ enc_destroy(&newkeys->enc);
|
|
+ mac_destroy(&newkeys->mac);
|
|
+ memset(&newkeys->comp, 0, sizeof(newkeys->comp));
|
|
+}
|
|
+
|
|
/*
|
|
* Send a plaintext error message to the peer, suffixed by \r\n.
|
|
* Only used during banner exchange, and there only for the server.
|
|
Index: openssh-8.8p1/kex.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/kex.h
|
|
+++ openssh-8.8p1/kex.h
|
|
@@ -226,6 +226,8 @@ int kexgss_client(struct ssh *);
|
|
int kexgss_server(struct ssh *);
|
|
#endif
|
|
|
|
+void newkeys_destroy(struct newkeys *newkeys);
|
|
+
|
|
int kex_dh_keypair(struct kex *);
|
|
int kex_dh_enc(struct kex *, const struct sshbuf *, struct sshbuf **,
|
|
struct sshbuf **);
|
|
Index: openssh-8.8p1/mac.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/mac.c
|
|
+++ openssh-8.8p1/mac.c
|
|
@@ -277,6 +277,20 @@ mac_clear(struct sshmac *mac)
|
|
mac->umac_ctx = NULL;
|
|
}
|
|
|
|
+void
|
|
+mac_destroy(struct sshmac *mac)
|
|
+{
|
|
+ if (mac == NULL)
|
|
+ return;
|
|
+
|
|
+ if (mac->key) {
|
|
+ memset(mac->key, 0, mac->key_len);
|
|
+ free(mac->key);
|
|
+ }
|
|
+
|
|
+ memset(mac, 0, sizeof(*mac));
|
|
+}
|
|
+
|
|
/* XXX copied from ciphers_valid */
|
|
#define MAC_SEP ","
|
|
int
|
|
Index: openssh-8.8p1/mac.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/mac.h
|
|
+++ openssh-8.8p1/mac.h
|
|
@@ -49,5 +49,6 @@ int mac_compute(struct sshmac *, u_int3
|
|
int mac_check(struct sshmac *, u_int32_t, const u_char *, size_t,
|
|
const u_char *, size_t);
|
|
void mac_clear(struct sshmac *);
|
|
+void mac_destroy(struct sshmac *);
|
|
|
|
#endif /* SSHMAC_H */
|
|
Index: openssh-8.8p1/monitor.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/monitor.c
|
|
+++ openssh-8.8p1/monitor.c
|
|
@@ -93,6 +93,7 @@
|
|
#include "compat.h"
|
|
#include "ssh2.h"
|
|
#include "authfd.h"
|
|
+#include "audit.h"
|
|
#include "match.h"
|
|
#include "ssherr.h"
|
|
#include "sk-api.h"
|
|
@@ -107,6 +108,8 @@ extern u_int utmp_len;
|
|
extern struct sshbuf *loginmsg;
|
|
extern struct sshauthopt *auth_opts; /* XXX move to permanent ssh->authctxt? */
|
|
|
|
+extern void destroy_sensitive_data(struct ssh *, int);
|
|
+
|
|
/* State exported from the child */
|
|
static struct sshbuf *child_state;
|
|
|
|
@@ -152,6 +155,11 @@ int mm_answer_gss_updatecreds(struct ssh
|
|
#ifdef SSH_AUDIT_EVENTS
|
|
int mm_answer_audit_event(struct ssh *, int, struct sshbuf *);
|
|
int mm_answer_audit_command(struct ssh *, int, struct sshbuf *);
|
|
+int mm_answer_audit_end_command(struct ssh *, int, struct sshbuf *);
|
|
+int mm_answer_audit_unsupported_body(struct ssh *, int, struct sshbuf *);
|
|
+int mm_answer_audit_kex_body(struct ssh *, int, struct sshbuf *);
|
|
+int mm_answer_audit_session_key_free_body(struct ssh *, int, struct sshbuf *);
|
|
+int mm_answer_audit_server_key_free(struct ssh *, int, struct sshbuf *);
|
|
#endif
|
|
|
|
static Authctxt *authctxt;
|
|
@@ -207,6 +215,10 @@ struct mon_table mon_dispatch_proto20[]
|
|
#endif
|
|
#ifdef SSH_AUDIT_EVENTS
|
|
{MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
|
|
+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
|
|
+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
|
|
+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
|
|
+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
|
|
#endif
|
|
#ifdef BSD_AUTH
|
|
{MONITOR_REQ_BSDAUTHQUERY, MON_ISAUTH, mm_answer_bsdauthquery},
|
|
@@ -241,6 +253,11 @@ struct mon_table mon_dispatch_postauth20
|
|
#ifdef SSH_AUDIT_EVENTS
|
|
{MONITOR_REQ_AUDIT_EVENT, MON_PERMIT, mm_answer_audit_event},
|
|
{MONITOR_REQ_AUDIT_COMMAND, MON_PERMIT, mm_answer_audit_command},
|
|
+ {MONITOR_REQ_AUDIT_END_COMMAND, MON_PERMIT, mm_answer_audit_end_command},
|
|
+ {MONITOR_REQ_AUDIT_UNSUPPORTED, MON_PERMIT, mm_answer_audit_unsupported_body},
|
|
+ {MONITOR_REQ_AUDIT_KEX, MON_PERMIT, mm_answer_audit_kex_body},
|
|
+ {MONITOR_REQ_AUDIT_SESSION_KEY_FREE, MON_PERMIT, mm_answer_audit_session_key_free_body},
|
|
+ {MONITOR_REQ_AUDIT_SERVER_KEY_FREE, MON_PERMIT, mm_answer_audit_server_key_free},
|
|
#endif
|
|
{0, 0, NULL}
|
|
};
|
|
@@ -1403,8 +1420,10 @@ mm_answer_keyverify(struct ssh *ssh, int
|
|
int r, ret, req_presence = 0, req_verify = 0, valid_data = 0;
|
|
int encoded_ret;
|
|
struct sshkey_sig_details *sig_details = NULL;
|
|
+ int type = 0;
|
|
|
|
- if ((r = sshbuf_get_string_direct(m, &blob, &bloblen)) != 0 ||
|
|
+ if ((r = sshbuf_get_u32(m, &type)) != 0 ||
|
|
+ (r = sshbuf_get_string_direct(m, &blob, &bloblen)) != 0 ||
|
|
(r = sshbuf_get_string_direct(m, &signature, &signaturelen)) != 0 ||
|
|
(r = sshbuf_get_string_direct(m, &data, &datalen)) != 0 ||
|
|
(r = sshbuf_get_cstring(m, &sigalg, NULL)) != 0)
|
|
@@ -1413,6 +1432,8 @@ mm_answer_keyverify(struct ssh *ssh, int
|
|
if (hostbased_cuser == NULL || hostbased_chost == NULL ||
|
|
!monitor_allowed_key(blob, bloblen))
|
|
fatal_f("bad key, not previously allowed");
|
|
+ if (type != key_blobtype)
|
|
+ fatal_f("bad key type");
|
|
|
|
/* Empty signature algorithm means NULL. */
|
|
if (*sigalg == '\0') {
|
|
@@ -1428,14 +1449,19 @@ mm_answer_keyverify(struct ssh *ssh, int
|
|
case MM_USERKEY:
|
|
valid_data = monitor_valid_userblob(ssh, data, datalen);
|
|
auth_method = "publickey";
|
|
+ ret = user_key_verify(ssh, key, signature, signaturelen, data,
|
|
+ datalen, sigalg, ssh->compat, &sig_details);
|
|
break;
|
|
case MM_HOSTKEY:
|
|
valid_data = monitor_valid_hostbasedblob(data, datalen,
|
|
hostbased_cuser, hostbased_chost);
|
|
auth_method = "hostbased";
|
|
+ ret = hostbased_key_verify(ssh, key, signature, signaturelen, data,
|
|
+ datalen, sigalg, ssh->compat, &sig_details);
|
|
break;
|
|
default:
|
|
valid_data = 0;
|
|
+ ret = 0;
|
|
break;
|
|
}
|
|
if (!valid_data)
|
|
@@ -1447,8 +1473,6 @@ mm_answer_keyverify(struct ssh *ssh, int
|
|
SSH_FP_DEFAULT)) == NULL)
|
|
fatal_f("sshkey_fingerprint failed");
|
|
|
|
- ret = sshkey_verify(key, signature, signaturelen, data, datalen,
|
|
- sigalg, ssh->compat, &sig_details);
|
|
debug3_f("%s %s signature %s%s%s", auth_method, sshkey_type(key),
|
|
(ret == 0) ? "verified" : "unverified",
|
|
(ret != 0) ? ": " : "", (ret != 0) ? ssh_err(ret) : "");
|
|
@@ -1535,13 +1559,19 @@ mm_record_login(struct ssh *ssh, Session
|
|
}
|
|
|
|
static void
|
|
-mm_session_close(Session *s)
|
|
+mm_session_close(struct ssh *ssh, Session *s)
|
|
{
|
|
debug3_f("session %d pid %ld", s->self, (long)s->pid);
|
|
if (s->ttyfd != -1) {
|
|
debug3_f("tty %s ptyfd %d", s->tty, s->ptyfd);
|
|
session_pty_cleanup2(s);
|
|
}
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ if (s->command != NULL) {
|
|
+ debug3_f("command %d", s->command_handle);
|
|
+ session_end_command2(ssh, s);
|
|
+ }
|
|
+#endif
|
|
session_unused(s->self);
|
|
}
|
|
|
|
@@ -1608,7 +1638,7 @@ mm_answer_pty(struct ssh *ssh, int sock,
|
|
|
|
error:
|
|
if (s != NULL)
|
|
- mm_session_close(s);
|
|
+ mm_session_close(ssh, s);
|
|
if ((r = sshbuf_put_u32(m, 0)) != 0)
|
|
fatal_fr(r, "assemble 0");
|
|
mm_request_send(sock, MONITOR_ANS_PTY, m);
|
|
@@ -1627,7 +1657,7 @@ mm_answer_pty_cleanup(struct ssh *ssh, i
|
|
if ((r = sshbuf_get_cstring(m, &tty, NULL)) != 0)
|
|
fatal_fr(r, "parse tty");
|
|
if ((s = session_by_tty(tty)) != NULL)
|
|
- mm_session_close(s);
|
|
+ mm_session_close(ssh, s);
|
|
sshbuf_reset(m);
|
|
free(tty);
|
|
return (0);
|
|
@@ -1649,6 +1679,8 @@ mm_answer_term(struct ssh *ssh, int sock
|
|
sshpam_cleanup();
|
|
#endif
|
|
|
|
+ destroy_sensitive_data(ssh, 0);
|
|
+
|
|
while (waitpid(pmonitor->m_pid, &status, 0) == -1)
|
|
if (errno != EINTR)
|
|
exit(1);
|
|
@@ -1695,12 +1727,47 @@ mm_answer_audit_command(struct ssh *ssh,
|
|
{
|
|
char *cmd;
|
|
int r;
|
|
+ Session *s;
|
|
|
|
debug3("%s entering", __func__);
|
|
if ((r = sshbuf_get_cstring(m, &cmd, NULL)) != 0)
|
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+
|
|
/* sanity check command, if so how? */
|
|
- audit_run_command(cmd);
|
|
+ s = session_new();
|
|
+ if (s == NULL)
|
|
+ fatal("%s: error allocating a session", __func__);
|
|
+ s->command = cmd;
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ s->command_handle = audit_run_command(ssh, cmd);
|
|
+#endif
|
|
+
|
|
+ sshbuf_reset(m);
|
|
+ sshbuf_put_u32(m, s->self);
|
|
+
|
|
+ mm_request_send(socket, MONITOR_ANS_AUDIT_COMMAND, m);
|
|
+
|
|
+ return (0);
|
|
+}
|
|
+
|
|
+int
|
|
+mm_answer_audit_end_command(struct ssh *ssh, int socket, struct sshbuf *m)
|
|
+{
|
|
+ int handle, r;
|
|
+ size_t len;
|
|
+ u_char *cmd = NULL;
|
|
+ Session *s;
|
|
+
|
|
+ debug3("%s entering", __func__);
|
|
+ if ((r = sshbuf_get_u32(m, &handle)) != 0 ||
|
|
+ (r = sshbuf_get_string(m, &cmd, &len)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+
|
|
+ s = session_by_id(handle);
|
|
+ if (s == NULL || s->ttyfd != -1 || s->command == NULL ||
|
|
+ strcmp(s->command, cmd) != 0)
|
|
+ fatal("%s: invalid handle", __func__);
|
|
+ mm_session_close(ssh, s);
|
|
free(cmd);
|
|
return (0);
|
|
}
|
|
@@ -1772,6 +1839,7 @@ monitor_apply_keystate(struct ssh *ssh,
|
|
void
|
|
mm_get_keystate(struct ssh *ssh, struct monitor *pmonitor)
|
|
{
|
|
+ struct sshbuf *m;
|
|
debug3_f("Waiting for new keys");
|
|
|
|
if ((child_state = sshbuf_new()) == NULL)
|
|
@@ -1779,6 +1847,18 @@ mm_get_keystate(struct ssh *ssh, struct
|
|
mm_request_receive_expect(pmonitor->m_sendfd, MONITOR_REQ_KEYEXPORT,
|
|
child_state);
|
|
debug3_f("GOT new keys");
|
|
+
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ m = sshbuf_new();
|
|
+ mm_request_receive_expect(pmonitor->m_sendfd,
|
|
+ MONITOR_REQ_AUDIT_SESSION_KEY_FREE, m);
|
|
+ mm_answer_audit_session_key_free_body(ssh, pmonitor->m_sendfd, m);
|
|
+ sshbuf_free(m);
|
|
+#endif
|
|
+
|
|
+ /* Drain any buffered messages from the child */
|
|
+ while (pmonitor->m_log_recvfd >= 0 && monitor_read_log(pmonitor) == 0)
|
|
+ ;
|
|
}
|
|
|
|
|
|
@@ -2056,3 +2136,102 @@ mm_answer_gss_updatecreds(struct ssh *ss
|
|
|
|
#endif /* GSSAPI */
|
|
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+int
|
|
+mm_answer_audit_unsupported_body(struct ssh *ssh, int sock, struct sshbuf *m)
|
|
+{
|
|
+ int what, r;
|
|
+
|
|
+ if ((r = sshbuf_get_u32(m, &what)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+
|
|
+ audit_unsupported_body(ssh, what);
|
|
+
|
|
+ sshbuf_reset(m);
|
|
+
|
|
+ mm_request_send(sock, MONITOR_ANS_AUDIT_UNSUPPORTED, m);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+mm_answer_audit_kex_body(struct ssh *ssh, int sock, struct sshbuf *m)
|
|
+{
|
|
+ int ctos, r;
|
|
+ char *cipher, *mac, *compress, *pfs;
|
|
+ u_int64_t tmp;
|
|
+ pid_t pid;
|
|
+ uid_t uid;
|
|
+
|
|
+ if ((r = sshbuf_get_u32(m, &ctos)) != 0 ||
|
|
+ (r = sshbuf_get_cstring(m, &cipher, NULL)) != 0 ||
|
|
+ (r = sshbuf_get_cstring(m, &mac, NULL)) != 0 ||
|
|
+ (r = sshbuf_get_cstring(m, &compress, NULL)) != 0 ||
|
|
+ (r = sshbuf_get_cstring(m, &pfs, NULL)) != 0 ||
|
|
+ (r = sshbuf_get_u64(m, &tmp)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+ pid = (pid_t) tmp;
|
|
+ if ((r = sshbuf_get_u64(m, &tmp)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+ uid = (pid_t) tmp;
|
|
+
|
|
+ audit_kex_body(ssh, ctos, cipher, mac, compress, pfs, pid, uid);
|
|
+
|
|
+ free(cipher);
|
|
+ free(mac);
|
|
+ free(compress);
|
|
+ free(pfs);
|
|
+ sshbuf_reset(m);
|
|
+
|
|
+ mm_request_send(sock, MONITOR_ANS_AUDIT_KEX, m);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+mm_answer_audit_session_key_free_body(struct ssh *ssh, int sock, struct sshbuf *m)
|
|
+{
|
|
+ int ctos, r;
|
|
+ u_int64_t tmp;
|
|
+ pid_t pid;
|
|
+ uid_t uid;
|
|
+
|
|
+ if ((r = sshbuf_get_u32(m, &ctos)) != 0 ||
|
|
+ (r = sshbuf_get_u64(m, &tmp)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+ pid = (pid_t) tmp;
|
|
+ if ((r = sshbuf_get_u64(m, &tmp)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+ uid = (uid_t) tmp;
|
|
+
|
|
+ audit_session_key_free_body(ssh, ctos, pid, uid);
|
|
+
|
|
+ sshbuf_reset(m);
|
|
+
|
|
+ mm_request_send(sock, MONITOR_ANS_AUDIT_SESSION_KEY_FREE, m);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+int
|
|
+mm_answer_audit_server_key_free(struct ssh *ssh, int sock, struct sshbuf *m)
|
|
+{
|
|
+ size_t len, r;
|
|
+ char *fp;
|
|
+ u_int64_t tmp;
|
|
+ pid_t pid;
|
|
+ uid_t uid;
|
|
+
|
|
+ if ((r = sshbuf_get_cstring(m, &fp, &len)) != 0 ||
|
|
+ (r = sshbuf_get_u64(m, &tmp)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+ pid = (pid_t) tmp;
|
|
+ if ((r = sshbuf_get_u64(m, &tmp)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+ uid = (uid_t) tmp;
|
|
+
|
|
+ audit_destroy_sensitive_data(ssh, fp, pid, uid);
|
|
+
|
|
+ free(fp);
|
|
+ sshbuf_reset(m);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif /* SSH_AUDIT_EVENTS */
|
|
Index: openssh-8.8p1/monitor.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/monitor.h
|
|
+++ openssh-8.8p1/monitor.h
|
|
@@ -61,7 +61,13 @@ enum monitor_reqtype {
|
|
MONITOR_REQ_PAM_QUERY = 106, MONITOR_ANS_PAM_QUERY = 107,
|
|
MONITOR_REQ_PAM_RESPOND = 108, MONITOR_ANS_PAM_RESPOND = 109,
|
|
MONITOR_REQ_PAM_FREE_CTX = 110, MONITOR_ANS_PAM_FREE_CTX = 111,
|
|
- MONITOR_REQ_AUDIT_EVENT = 112, MONITOR_REQ_AUDIT_COMMAND = 113,
|
|
+ MONITOR_REQ_AUDIT_EVENT = 112,
|
|
+ MONITOR_REQ_AUDIT_COMMAND = 114, MONITOR_ANS_AUDIT_COMMAND = 115,
|
|
+ MONITOR_REQ_AUDIT_END_COMMAND = 116,
|
|
+ MONITOR_REQ_AUDIT_UNSUPPORTED = 118, MONITOR_ANS_AUDIT_UNSUPPORTED = 119,
|
|
+ MONITOR_REQ_AUDIT_KEX = 120, MONITOR_ANS_AUDIT_KEX = 121,
|
|
+ MONITOR_REQ_AUDIT_SESSION_KEY_FREE = 122, MONITOR_ANS_AUDIT_SESSION_KEY_FREE = 123,
|
|
+ MONITOR_REQ_AUDIT_SERVER_KEY_FREE = 124,
|
|
|
|
MONITOR_REQ_GSSSIGN = 150, MONITOR_ANS_GSSSIGN = 151,
|
|
MONITOR_REQ_GSSUPCREDS = 152, MONITOR_ANS_GSSUPCREDS = 153,
|
|
Index: openssh-8.8p1/monitor_wrap.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/monitor_wrap.c
|
|
+++ openssh-8.8p1/monitor_wrap.c
|
|
@@ -499,7 +499,7 @@ mm_key_allowed(enum mm_keytype type, con
|
|
*/
|
|
|
|
int
|
|
-mm_sshkey_verify(const struct sshkey *key, const u_char *sig, size_t siglen,
|
|
+mm_sshkey_verify(enum mm_keytype type, const struct sshkey *key, const u_char *sig, size_t siglen,
|
|
const u_char *data, size_t datalen, const char *sigalg, u_int compat,
|
|
struct sshkey_sig_details **sig_detailsp)
|
|
{
|
|
@@ -515,7 +515,8 @@ mm_sshkey_verify(const struct sshkey *ke
|
|
*sig_detailsp = NULL;
|
|
if ((m = sshbuf_new()) == NULL)
|
|
fatal_f("sshbuf_new failed");
|
|
- if ((r = sshkey_puts(key, m)) != 0 ||
|
|
+ if ((r = sshbuf_put_u32(m, type)) != 0 ||
|
|
+ (r = sshkey_puts(key, m)) != 0 ||
|
|
(r = sshbuf_put_string(m, sig, siglen)) != 0 ||
|
|
(r = sshbuf_put_string(m, data, datalen)) != 0 ||
|
|
(r = sshbuf_put_cstring(m, sigalg == NULL ? "" : sigalg)) != 0)
|
|
@@ -548,6 +549,20 @@ mm_sshkey_verify(const struct sshkey *ke
|
|
return 0;
|
|
}
|
|
|
|
+int
|
|
+mm_hostbased_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, size_t siglen,
|
|
+ const u_char *data, size_t datalen, const char *pkalg, u_int compat, struct sshkey_sig_details **sigdet)
|
|
+{
|
|
+ return mm_sshkey_verify(MM_HOSTKEY, key, sig, siglen, data, datalen, pkalg, compat, sigdet);
|
|
+}
|
|
+
|
|
+int
|
|
+mm_user_key_verify(struct ssh *ssh, const struct sshkey *key, const u_char *sig, size_t siglen,
|
|
+ const u_char *data, size_t datalen, const char *pkalg, u_int compat, struct sshkey_sig_details **sigdet)
|
|
+{
|
|
+ return mm_sshkey_verify(MM_USERKEY, key, sig, siglen, data, datalen, pkalg, compat, sigdet);
|
|
+}
|
|
+
|
|
void
|
|
mm_send_keystate(struct ssh *ssh, struct monitor *monitor)
|
|
{
|
|
@@ -900,11 +915,12 @@ mm_audit_event(struct ssh *ssh, ssh_audi
|
|
sshbuf_free(m);
|
|
}
|
|
|
|
-void
|
|
-mm_audit_run_command(const char *command)
|
|
+int
|
|
+mm_audit_run_command(struct ssh *ssh, const char *command)
|
|
{
|
|
struct sshbuf *m;
|
|
int r;
|
|
+ int handle;
|
|
|
|
debug3("%s entering command %s", __func__, command);
|
|
|
|
@@ -914,6 +930,30 @@ mm_audit_run_command(const char *command
|
|
fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
|
|
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_COMMAND, m);
|
|
+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_COMMAND, m);
|
|
+
|
|
+ if ((r = sshbuf_get_u32(m, &handle)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+ sshbuf_free(m);
|
|
+
|
|
+ return (handle);
|
|
+}
|
|
+
|
|
+void
|
|
+mm_audit_end_command(struct ssh *ssh, int handle, const char *command)
|
|
+{
|
|
+ int r;
|
|
+ struct sshbuf *m;
|
|
+
|
|
+ debug3("%s entering command %s", __func__, command);
|
|
+
|
|
+ if ((m = sshbuf_new()) == NULL)
|
|
+ fatal("%s: sshbuf_new failed", __func__);
|
|
+ if ((r = sshbuf_put_u32(m, handle)) != 0 ||
|
|
+ (r = sshbuf_put_cstring(m, command)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+
|
|
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_END_COMMAND, m);
|
|
sshbuf_free(m);
|
|
}
|
|
#endif /* SSH_AUDIT_EVENTS */
|
|
@@ -1074,3 +1114,83 @@ mm_ssh_gssapi_update_creds(ssh_gssapi_cc
|
|
}
|
|
|
|
#endif /* GSSAPI */
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+void
|
|
+mm_audit_unsupported_body(struct ssh *ssh, int what)
|
|
+{
|
|
+ int r;
|
|
+ struct sshbuf *m;
|
|
+
|
|
+ if ((m = sshbuf_new()) == NULL)
|
|
+ fatal("%s: sshbuf_new failed", __func__);
|
|
+ if ((r = sshbuf_put_u32(m, what)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+
|
|
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_UNSUPPORTED, m);
|
|
+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_UNSUPPORTED,
|
|
+ m);
|
|
+
|
|
+ sshbuf_free(m);
|
|
+}
|
|
+
|
|
+void
|
|
+mm_audit_kex_body(struct ssh *ssh, int ctos, char *cipher, char *mac, char *compress, char *fps, pid_t pid,
|
|
+ uid_t uid)
|
|
+{
|
|
+ int r;
|
|
+ struct sshbuf *m;
|
|
+
|
|
+ if ((m = sshbuf_new()) == NULL)
|
|
+ fatal("%s: sshbuf_new failed", __func__);
|
|
+ if ((r = sshbuf_put_u32(m, ctos)) != 0 ||
|
|
+ (r = sshbuf_put_cstring(m, cipher)) != 0 ||
|
|
+ (r = sshbuf_put_cstring(m, (mac ? mac : "<implicit>"))) != 0 ||
|
|
+ (r = sshbuf_put_cstring(m, compress)) != 0 ||
|
|
+ (r = sshbuf_put_cstring(m, fps)) != 0 ||
|
|
+ (r = sshbuf_put_u64(m, pid)) != 0 ||
|
|
+ (r = sshbuf_put_u64(m, uid)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+
|
|
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_KEX, m);
|
|
+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_KEX,
|
|
+ m);
|
|
+
|
|
+ sshbuf_free(m);
|
|
+}
|
|
+
|
|
+void
|
|
+mm_audit_session_key_free_body(struct ssh *ssh, int ctos, pid_t pid, uid_t uid)
|
|
+{
|
|
+ int r;
|
|
+ struct sshbuf *m;
|
|
+
|
|
+ if ((m = sshbuf_new()) == NULL)
|
|
+ fatal("%s: sshbuf_new failed", __func__);
|
|
+ if ((r = sshbuf_put_u32(m, ctos)) != 0 ||
|
|
+ (r = sshbuf_put_u64(m, pid)) != 0 ||
|
|
+ (r = sshbuf_put_u64(m, uid)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+
|
|
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SESSION_KEY_FREE, m);
|
|
+ mm_request_receive_expect(pmonitor->m_recvfd, MONITOR_ANS_AUDIT_SESSION_KEY_FREE,
|
|
+ m);
|
|
+ sshbuf_free(m);
|
|
+}
|
|
+
|
|
+void
|
|
+mm_audit_destroy_sensitive_data(struct ssh *ssh, const char *fp, pid_t pid, uid_t uid)
|
|
+{
|
|
+ int r;
|
|
+ struct sshbuf *m;
|
|
+
|
|
+ if ((m = sshbuf_new()) == NULL)
|
|
+ fatal("%s: sshbuf_new failed", __func__);
|
|
+ if ((r = sshbuf_put_cstring(m, fp)) != 0 ||
|
|
+ (r = sshbuf_put_u64(m, pid)) != 0 ||
|
|
+ (r = sshbuf_put_u64(m, uid)) != 0)
|
|
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
|
+
|
|
+ mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_AUDIT_SERVER_KEY_FREE, m);
|
|
+ sshbuf_free(m);
|
|
+}
|
|
+#endif /* SSH_AUDIT_EVENTS */
|
|
Index: openssh-8.8p1/monitor_wrap.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/monitor_wrap.h
|
|
+++ openssh-8.8p1/monitor_wrap.h
|
|
@@ -58,7 +58,9 @@ int mm_user_key_allowed(struct ssh *, st
|
|
struct sshauthopt **);
|
|
int mm_hostbased_key_allowed(struct ssh *, struct passwd *, const char *,
|
|
const char *, struct sshkey *);
|
|
-int mm_sshkey_verify(const struct sshkey *, const u_char *, size_t,
|
|
+int mm_hostbased_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t,
|
|
+ const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **);
|
|
+int mm_user_key_verify(struct ssh *, const struct sshkey *, const u_char *, size_t,
|
|
const u_char *, size_t, const char *, u_int, struct sshkey_sig_details **);
|
|
|
|
#ifdef GSSAPI
|
|
@@ -83,7 +85,12 @@ void mm_sshpam_free_ctx(void *);
|
|
#ifdef SSH_AUDIT_EVENTS
|
|
#include "audit.h"
|
|
void mm_audit_event(struct ssh *, ssh_audit_event_t);
|
|
-void mm_audit_run_command(const char *);
|
|
+int mm_audit_run_command(struct ssh *ssh, const char *);
|
|
+void mm_audit_end_command(struct ssh *ssh, int, const char *);
|
|
+void mm_audit_unsupported_body(struct ssh *, int);
|
|
+void mm_audit_kex_body(struct ssh *, int, char *, char *, char *, char *, pid_t, uid_t);
|
|
+void mm_audit_session_key_free_body(struct ssh *, int, pid_t, uid_t);
|
|
+void mm_audit_destroy_sensitive_data(struct ssh *, const char *, pid_t, uid_t);
|
|
#endif
|
|
|
|
struct Session;
|
|
Index: openssh-8.8p1/packet.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/packet.c
|
|
+++ openssh-8.8p1/packet.c
|
|
@@ -81,6 +81,7 @@
|
|
#endif
|
|
|
|
#include "xmalloc.h"
|
|
+#include "audit.h"
|
|
#include "compat.h"
|
|
#include "ssh2.h"
|
|
#include "cipher.h"
|
|
@@ -506,6 +507,13 @@ ssh_packet_get_connection_out(struct ssh
|
|
return ssh->state->connection_out;
|
|
}
|
|
|
|
+static int
|
|
+packet_state_has_keys (const struct session_state *state)
|
|
+{
|
|
+ return state != NULL &&
|
|
+ (state->newkeys[MODE_IN] != NULL || state->newkeys[MODE_OUT] != NULL);
|
|
+}
|
|
+
|
|
/*
|
|
* Returns the IP-address of the remote host as a string. The returned
|
|
* string must not be freed.
|
|
@@ -583,22 +591,19 @@ ssh_packet_close_internal(struct ssh *ss
|
|
{
|
|
struct session_state *state = ssh->state;
|
|
u_int mode;
|
|
+ u_int had_keys = packet_state_has_keys(state);
|
|
|
|
if (!state->initialized)
|
|
return;
|
|
state->initialized = 0;
|
|
- if (do_close) {
|
|
- if (state->connection_in == state->connection_out) {
|
|
- close(state->connection_out);
|
|
- } else {
|
|
- close(state->connection_in);
|
|
- close(state->connection_out);
|
|
- }
|
|
- }
|
|
sshbuf_free(state->input);
|
|
+ state->input = NULL;
|
|
sshbuf_free(state->output);
|
|
+ state->output = NULL;
|
|
sshbuf_free(state->outgoing_packet);
|
|
+ state->outgoing_packet = NULL;
|
|
sshbuf_free(state->incoming_packet);
|
|
+ state->incoming_packet = NULL;
|
|
for (mode = 0; mode < MODE_MAX; mode++) {
|
|
kex_free_newkeys(state->newkeys[mode]); /* current keys */
|
|
state->newkeys[mode] = NULL;
|
|
@@ -634,8 +639,18 @@ ssh_packet_close_internal(struct ssh *ss
|
|
#endif /* WITH_ZLIB */
|
|
cipher_free(state->send_context);
|
|
cipher_free(state->receive_context);
|
|
+ if (had_keys && state->server_side) {
|
|
+ /* Assuming this is called only from privsep child */
|
|
+ audit_session_key_free(ssh, MODE_MAX);
|
|
+ }
|
|
state->send_context = state->receive_context = NULL;
|
|
if (do_close) {
|
|
+ if (state->connection_in == state->connection_out) {
|
|
+ close(state->connection_out);
|
|
+ } else {
|
|
+ close(state->connection_in);
|
|
+ close(state->connection_out);
|
|
+ }
|
|
free(ssh->local_ipaddr);
|
|
ssh->local_ipaddr = NULL;
|
|
free(ssh->remote_ipaddr);
|
|
@@ -892,6 +907,7 @@ ssh_set_newkeys(struct ssh *ssh, int mod
|
|
(unsigned long long)state->p_send.bytes,
|
|
(unsigned long long)state->p_send.blocks);
|
|
kex_free_newkeys(state->newkeys[mode]);
|
|
+ audit_session_key_free(ssh, mode);
|
|
state->newkeys[mode] = NULL;
|
|
}
|
|
/* note that both bytes and the seqnr are not reset */
|
|
@@ -2178,6 +2194,73 @@ ssh_packet_get_output(struct ssh *ssh)
|
|
return (void *)ssh->state->output;
|
|
}
|
|
|
|
+static void
|
|
+newkeys_destroy_and_free(struct newkeys *newkeys)
|
|
+{
|
|
+ if (newkeys == NULL)
|
|
+ return;
|
|
+
|
|
+ free(newkeys->enc.name);
|
|
+
|
|
+ if (newkeys->mac.enabled) {
|
|
+ mac_clear(&newkeys->mac);
|
|
+ free(newkeys->mac.name);
|
|
+ }
|
|
+
|
|
+ free(newkeys->comp.name);
|
|
+
|
|
+ newkeys_destroy(newkeys);
|
|
+ free(newkeys);
|
|
+}
|
|
+
|
|
+static void
|
|
+packet_destroy_state(struct session_state *state)
|
|
+{
|
|
+ if (state == NULL)
|
|
+ return;
|
|
+
|
|
+ cipher_free(state->receive_context);
|
|
+ state->receive_context = NULL;
|
|
+ cipher_free(state->send_context);
|
|
+ state->send_context = NULL;
|
|
+
|
|
+ sshbuf_free(state->input);
|
|
+ state->input = NULL;
|
|
+ sshbuf_free(state->output);
|
|
+ state->output = NULL;
|
|
+ sshbuf_free(state->outgoing_packet);
|
|
+ state->outgoing_packet = NULL;
|
|
+ sshbuf_free(state->incoming_packet);
|
|
+ state->incoming_packet = NULL;
|
|
+ if (state->compression_buffer) {
|
|
+ sshbuf_free(state->compression_buffer);
|
|
+ state->compression_buffer = NULL;
|
|
+ }
|
|
+ newkeys_destroy_and_free(state->newkeys[MODE_IN]);
|
|
+ state->newkeys[MODE_IN] = NULL;
|
|
+ newkeys_destroy_and_free(state->newkeys[MODE_OUT]);
|
|
+ state->newkeys[MODE_OUT] = NULL;
|
|
+ mac_destroy(state->packet_discard_mac);
|
|
+// TAILQ_HEAD(, packet) outgoing;
|
|
+// memset(state, 0, sizeof(state));
|
|
+}
|
|
+
|
|
+void
|
|
+packet_destroy_all(struct ssh *ssh, int audit_it, int privsep)
|
|
+{
|
|
+ if (audit_it)
|
|
+ audit_it = packet_state_has_keys(ssh->state);
|
|
+ packet_destroy_state(ssh->state);
|
|
+ if (audit_it) {
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ if (privsep)
|
|
+ audit_session_key_free(ssh, MODE_MAX);
|
|
+ else
|
|
+ audit_session_key_free_body(ssh, MODE_MAX, getpid(), getuid());
|
|
+#endif
|
|
+ }
|
|
+}
|
|
+
|
|
/* Reset after_authentication and reset compression in post-auth privsep */
|
|
static int
|
|
ssh_packet_set_postauth(struct ssh *ssh)
|
|
Index: openssh-8.8p1/packet.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/packet.h
|
|
+++ openssh-8.8p1/packet.h
|
|
@@ -219,4 +219,5 @@ const u_char *sshpkt_ptr(struct ssh *, s
|
|
# undef EC_POINT
|
|
#endif
|
|
|
|
+void packet_destroy_all(struct ssh *, int, int);
|
|
#endif /* PACKET_H */
|
|
Index: openssh-8.8p1/session.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/session.c
|
|
+++ openssh-8.8p1/session.c
|
|
@@ -136,7 +136,7 @@ extern char *__progname;
|
|
extern int debug_flag;
|
|
extern u_int utmp_len;
|
|
extern int startup_pipe;
|
|
-extern void destroy_sensitive_data(void);
|
|
+extern void destroy_sensitive_data(struct ssh *, int);
|
|
extern struct sshbuf *loginmsg;
|
|
extern struct sshauthopt *auth_opts;
|
|
extern char *tun_fwd_ifnames; /* serverloop.c */
|
|
@@ -643,6 +643,14 @@ do_exec_pty(struct ssh *ssh, Session *s,
|
|
/* Parent. Close the slave side of the pseudo tty. */
|
|
close(ttyfd);
|
|
|
|
+#if !defined(HAVE_OSF_SIA) && defined(SSH_AUDIT_EVENTS)
|
|
+ /* do_login in the child did not affect state in this process,
|
|
+ compensate. From an architectural standpoint, this is extremely
|
|
+ ugly. */
|
|
+ if (command != NULL)
|
|
+ audit_count_session_open();
|
|
+#endif
|
|
+
|
|
/* Enter interactive session. */
|
|
s->ptymaster = ptymaster;
|
|
ssh_packet_set_interactive(ssh, 1,
|
|
@@ -707,15 +715,19 @@ do_exec(struct ssh *ssh, Session *s, con
|
|
s->self);
|
|
|
|
#ifdef SSH_AUDIT_EVENTS
|
|
+ if (s->command != NULL || s->command_handle != -1)
|
|
+ fatal("do_exec: command already set");
|
|
if (command != NULL)
|
|
- PRIVSEP(audit_run_command(command));
|
|
+ s->command = xstrdup(command);
|
|
else if (s->ttyfd == -1) {
|
|
char *shell = s->pw->pw_shell;
|
|
|
|
if (shell[0] == '\0') /* empty shell means /bin/sh */
|
|
shell =_PATH_BSHELL;
|
|
- PRIVSEP(audit_run_command(shell));
|
|
+ s->command = xstrdup(shell);
|
|
}
|
|
+ if (s->command != NULL && s->ptyfd == -1)
|
|
+ s->command_handle = PRIVSEP(audit_run_command(ssh, s->command));
|
|
#endif
|
|
if (s->ttyfd != -1)
|
|
ret = do_exec_pty(ssh, s, command);
|
|
@@ -1534,8 +1546,11 @@ do_child(struct ssh *ssh, Session *s, co
|
|
sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
|
|
|
|
/* remove hostkey from the child's memory */
|
|
- destroy_sensitive_data();
|
|
+ destroy_sensitive_data(ssh, 1);
|
|
ssh_packet_clear_keys(ssh);
|
|
+ /* Don't audit this - both us and the parent would be talking to the
|
|
+ monitor over a single socket, with no synchronization. */
|
|
+ packet_destroy_all(ssh, 0, 1);
|
|
|
|
/* Force a password change */
|
|
if (s->authctxt->force_pwchange) {
|
|
@@ -1744,6 +1759,9 @@ session_unused(int id)
|
|
sessions[id].ttyfd = -1;
|
|
sessions[id].ptymaster = -1;
|
|
sessions[id].x11_chanids = NULL;
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ sessions[id].command_handle = -1;
|
|
+#endif
|
|
sessions[id].next_unused = sessions_first_unused;
|
|
sessions_first_unused = id;
|
|
}
|
|
@@ -1823,6 +1841,19 @@ session_open(Authctxt *authctxt, int cha
|
|
}
|
|
|
|
Session *
|
|
+session_by_id(int id)
|
|
+{
|
|
+ if (id >= 0 && id < sessions_nalloc) {
|
|
+ Session *s = &sessions[id];
|
|
+ if (s->used)
|
|
+ return s;
|
|
+ }
|
|
+ debug("%s: unknown id %d", __func__, id);
|
|
+ session_dump();
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+Session *
|
|
session_by_tty(char *tty)
|
|
{
|
|
int i;
|
|
@@ -2430,6 +2461,32 @@ session_exit_message(struct ssh *ssh, Se
|
|
chan_write_failed(ssh, c);
|
|
}
|
|
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+void
|
|
+session_end_command2(struct ssh *ssh, Session *s)
|
|
+{
|
|
+ if (s->command != NULL) {
|
|
+ if (s->command_handle != -1)
|
|
+ audit_end_command(ssh, s->command_handle, s->command);
|
|
+ free(s->command);
|
|
+ s->command = NULL;
|
|
+ s->command_handle = -1;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+session_end_command(struct ssh *ssh, Session *s)
|
|
+{
|
|
+ if (s->command != NULL) {
|
|
+ if (s->command_handle != -1)
|
|
+ PRIVSEP(audit_end_command(ssh, s->command_handle, s->command));
|
|
+ free(s->command);
|
|
+ s->command = NULL;
|
|
+ s->command_handle = -1;
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
void
|
|
session_close(struct ssh *ssh, Session *s)
|
|
{
|
|
@@ -2471,6 +2528,10 @@ session_close(struct ssh *ssh, Session *
|
|
|
|
if (s->ttyfd != -1)
|
|
session_pty_cleanup(s);
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ if (s->command)
|
|
+ session_end_command(ssh, s);
|
|
+#endif
|
|
free(s->term);
|
|
free(s->display);
|
|
free(s->x11_chanids);
|
|
@@ -2545,14 +2606,14 @@ session_close_by_channel(struct ssh *ssh
|
|
}
|
|
|
|
void
|
|
-session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *))
|
|
+session_destroy_all(struct ssh *ssh, void (*closefunc)(struct ssh *ssh, Session *))
|
|
{
|
|
int i;
|
|
for (i = 0; i < sessions_nalloc; i++) {
|
|
Session *s = &sessions[i];
|
|
if (s->used) {
|
|
if (closefunc != NULL)
|
|
- closefunc(s);
|
|
+ closefunc(ssh, s);
|
|
else
|
|
session_close(ssh, s);
|
|
}
|
|
@@ -2678,6 +2739,15 @@ do_authenticated2(struct ssh *ssh, Authc
|
|
server_loop2(ssh, authctxt);
|
|
}
|
|
|
|
+static void
|
|
+do_cleanup_one_session(struct ssh *ssh, Session *s)
|
|
+{
|
|
+ session_pty_cleanup2(s);
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ session_end_command2(ssh, s);
|
|
+#endif
|
|
+}
|
|
+
|
|
void
|
|
do_cleanup(struct ssh *ssh, Authctxt *authctxt)
|
|
{
|
|
@@ -2741,7 +2811,7 @@ do_cleanup(struct ssh *ssh, Authctxt *au
|
|
* or if running in monitor.
|
|
*/
|
|
if (!use_privsep || mm_is_monitor())
|
|
- session_destroy_all(ssh, session_pty_cleanup2);
|
|
+ session_destroy_all(ssh, do_cleanup_one_session);
|
|
}
|
|
|
|
/* Return a name for the remote host that fits inside utmp_size */
|
|
Index: openssh-8.8p1/session.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/session.h
|
|
+++ openssh-8.8p1/session.h
|
|
@@ -61,6 +61,12 @@ struct Session {
|
|
char *name;
|
|
char *val;
|
|
} *env;
|
|
+
|
|
+ /* exec */
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ int command_handle;
|
|
+ char *command;
|
|
+#endif
|
|
};
|
|
|
|
void do_authenticated(struct ssh *, Authctxt *);
|
|
@@ -71,10 +77,12 @@ void session_unused(int);
|
|
int session_input_channel_req(struct ssh *, Channel *, const char *);
|
|
void session_close_by_pid(struct ssh *ssh, pid_t, int);
|
|
void session_close_by_channel(struct ssh *, int, void *);
|
|
-void session_destroy_all(struct ssh *, void (*)(Session *));
|
|
+void session_destroy_all(struct ssh *, void (*)(struct ssh*, Session *));
|
|
void session_pty_cleanup2(Session *);
|
|
+void session_end_command2(struct ssh *ssh, Session *);
|
|
|
|
Session *session_new(void);
|
|
+Session *session_by_id(int);
|
|
Session *session_by_tty(char *);
|
|
void session_close(struct ssh *, Session *);
|
|
void do_setusercontext(struct passwd *);
|
|
Index: openssh-8.8p1/sshd.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/sshd.c
|
|
+++ openssh-8.8p1/sshd.c
|
|
@@ -122,6 +122,7 @@
|
|
#include "ssh-gss.h"
|
|
#endif
|
|
#include "monitor_wrap.h"
|
|
+#include "audit.h"
|
|
#include "ssh-sandbox.h"
|
|
#include "auth-options.h"
|
|
#include "version.h"
|
|
@@ -262,8 +263,8 @@ struct sshbuf *loginmsg;
|
|
struct passwd *privsep_pw = NULL;
|
|
|
|
/* Prototypes for various functions defined later in this file. */
|
|
-void destroy_sensitive_data(void);
|
|
-void demote_sensitive_data(void);
|
|
+void destroy_sensitive_data(struct ssh *, int);
|
|
+void demote_sensitive_data(struct ssh *);
|
|
static void do_ssh2_kex(struct ssh *);
|
|
|
|
static char *listener_proctitle;
|
|
@@ -281,6 +282,15 @@ close_listen_socks(void)
|
|
num_listen_socks = -1;
|
|
}
|
|
|
|
+/*
|
|
+ * Is this process listening for clients (i.e. not specific to any specific
|
|
+ * client connection?)
|
|
+ */
|
|
+int listening_for_clients(void)
|
|
+{
|
|
+ return num_listen_socks >= 0;
|
|
+}
|
|
+
|
|
static void
|
|
close_startup_pipes(void)
|
|
{
|
|
@@ -386,18 +396,45 @@ grace_alarm_handler(int sig)
|
|
}
|
|
}
|
|
|
|
-/* Destroy the host and server keys. They will no longer be needed. */
|
|
+/*
|
|
+ * Destroy the host and server keys. They will no longer be needed. Careful,
|
|
+ * this can be called from cleanup_exit() - i.e. from just about anywhere.
|
|
+ */
|
|
void
|
|
-destroy_sensitive_data(void)
|
|
+destroy_sensitive_data(struct ssh *ssh, int privsep)
|
|
{
|
|
u_int i;
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ pid_t pid;
|
|
+ uid_t uid;
|
|
|
|
+ pid = getpid();
|
|
+ uid = getuid();
|
|
+#endif
|
|
for (i = 0; i < options.num_host_key_files; i++) {
|
|
if (sensitive_data.host_keys[i]) {
|
|
+ char *fp;
|
|
+
|
|
+ if (sshkey_is_private(sensitive_data.host_keys[i]))
|
|
+ fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX);
|
|
+ else
|
|
+ fp = NULL;
|
|
sshkey_free(sensitive_data.host_keys[i]);
|
|
sensitive_data.host_keys[i] = NULL;
|
|
+ if (fp != NULL) {
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ if (privsep)
|
|
+ PRIVSEP(audit_destroy_sensitive_data(ssh, fp,
|
|
+ pid, uid));
|
|
+ else
|
|
+ audit_destroy_sensitive_data(ssh, fp,
|
|
+ pid, uid);
|
|
+#endif
|
|
+ free(fp);
|
|
+ }
|
|
}
|
|
- if (sensitive_data.host_certificates[i]) {
|
|
+ if (sensitive_data.host_certificates
|
|
+ && sensitive_data.host_certificates[i]) {
|
|
sshkey_free(sensitive_data.host_certificates[i]);
|
|
sensitive_data.host_certificates[i] = NULL;
|
|
}
|
|
@@ -406,20 +443,38 @@ destroy_sensitive_data(void)
|
|
|
|
/* Demote private to public keys for network child */
|
|
void
|
|
-demote_sensitive_data(void)
|
|
+demote_sensitive_data(struct ssh *ssh)
|
|
{
|
|
struct sshkey *tmp;
|
|
u_int i;
|
|
int r;
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ pid_t pid;
|
|
+ uid_t uid;
|
|
|
|
+ pid = getpid();
|
|
+ uid = getuid();
|
|
+#endif
|
|
for (i = 0; i < options.num_host_key_files; i++) {
|
|
if (sensitive_data.host_keys[i]) {
|
|
+ char *fp;
|
|
+
|
|
+ if (sshkey_is_private(sensitive_data.host_keys[i]))
|
|
+ fp = sshkey_fingerprint(sensitive_data.host_keys[i], options.fingerprint_hash, SSH_FP_HEX);
|
|
+ else
|
|
+ fp = NULL;
|
|
if ((r = sshkey_from_private(
|
|
sensitive_data.host_keys[i], &tmp)) != 0)
|
|
fatal_r(r, "could not demote host %s key",
|
|
sshkey_type(sensitive_data.host_keys[i]));
|
|
sshkey_free(sensitive_data.host_keys[i]);
|
|
sensitive_data.host_keys[i] = tmp;
|
|
+ if (fp != NULL) {
|
|
+#ifdef SSH_AUDIT_EVENTS
|
|
+ audit_destroy_sensitive_data(ssh, fp, pid, uid);
|
|
+#endif
|
|
+ free(fp);
|
|
+ }
|
|
}
|
|
/* Certs do not need demotion */
|
|
}
|
|
@@ -447,7 +502,7 @@ reseed_prngs(void)
|
|
}
|
|
|
|
static void
|
|
-privsep_preauth_child(void)
|
|
+privsep_preauth_child(struct ssh *ssh)
|
|
{
|
|
gid_t gidset[1];
|
|
|
|
@@ -462,7 +517,7 @@ privsep_preauth_child(void)
|
|
reseed_prngs();
|
|
|
|
/* Demote the private keys to public keys. */
|
|
- demote_sensitive_data();
|
|
+ demote_sensitive_data(ssh);
|
|
|
|
/* Demote the child */
|
|
if (privsep_chroot) {
|
|
@@ -497,7 +552,7 @@ privsep_preauth(struct ssh *ssh)
|
|
|
|
if (use_privsep == PRIVSEP_ON)
|
|
box = ssh_sandbox_init(pmonitor);
|
|
- pid = fork();
|
|
+ pmonitor->m_pid = pid = fork();
|
|
if (pid == -1) {
|
|
fatal("fork of unprivileged child failed");
|
|
} else if (pid != 0) {
|
|
@@ -542,7 +597,7 @@ privsep_preauth(struct ssh *ssh)
|
|
/* Arrange for logging to be sent to the monitor */
|
|
set_log_handler(mm_log_handler, pmonitor);
|
|
|
|
- privsep_preauth_child();
|
|
+ privsep_preauth_child(ssh);
|
|
setproctitle("%s", "[net]");
|
|
if (box != NULL)
|
|
ssh_sandbox_child(box);
|
|
@@ -586,7 +641,7 @@ privsep_postauth(struct ssh *ssh, Authct
|
|
pmonitor->m_sendfd = -1;
|
|
|
|
/* Demote the private keys to public keys. */
|
|
- demote_sensitive_data();
|
|
+ demote_sensitive_data(ssh);
|
|
|
|
reseed_prngs();
|
|
|
|
@@ -1140,7 +1195,7 @@ server_listen(void)
|
|
* from this function are in a forked subprocess.
|
|
*/
|
|
static void
|
|
-server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s)
|
|
+server_accept_loop(struct ssh *ssh, int *sock_in, int *sock_out, int *newsock, int *config_s)
|
|
{
|
|
fd_set *fdset;
|
|
int i, j, ret, maxfd;
|
|
@@ -1186,6 +1241,7 @@ server_accept_loop(int *sock_in, int *so
|
|
if (received_sigterm) {
|
|
logit("Received signal %d; terminating.",
|
|
(int) received_sigterm);
|
|
+ destroy_sensitive_data(ssh, 0);
|
|
close_listen_socks();
|
|
if (options.pid_file != NULL)
|
|
unlink(options.pid_file);
|
|
@@ -2091,7 +2147,7 @@ main(int ac, char **av)
|
|
#endif
|
|
|
|
/* Accept a connection and return in a forked child */
|
|
- server_accept_loop(&sock_in, &sock_out,
|
|
+ server_accept_loop(ssh, &sock_in, &sock_out,
|
|
&newsock, config_s);
|
|
}
|
|
|
|
@@ -2321,6 +2377,9 @@ main(int ac, char **av)
|
|
do_authenticated(ssh, authctxt);
|
|
|
|
/* The connection has been terminated. */
|
|
+ packet_destroy_all(ssh, 1, 1);
|
|
+ destroy_sensitive_data(ssh, 1);
|
|
+
|
|
ssh_packet_get_bytes(ssh, &ibytes, &obytes);
|
|
verbose("Transferred: sent %llu, received %llu bytes",
|
|
(unsigned long long)obytes, (unsigned long long)ibytes);
|
|
@@ -2501,6 +2560,15 @@ do_ssh2_kex(struct ssh *ssh)
|
|
void
|
|
cleanup_exit(int i)
|
|
{
|
|
+ static int in_cleanup = 0;
|
|
+ int is_privsep_child;
|
|
+
|
|
+ /* cleanup_exit can be called at the very least from the privsep
|
|
+ wrappers used for auditing. Make sure we don't recurse
|
|
+ indefinitely. */
|
|
+ if (in_cleanup)
|
|
+ _exit(i);
|
|
+ in_cleanup = 1;
|
|
if (the_active_state != NULL && the_authctxt != NULL) {
|
|
do_cleanup(the_active_state, the_authctxt);
|
|
if (use_privsep && privsep_is_preauth &&
|
|
@@ -2513,9 +2581,16 @@ cleanup_exit(int i)
|
|
}
|
|
}
|
|
}
|
|
+ is_privsep_child = use_privsep && pmonitor != NULL && pmonitor->m_pid == 0;
|
|
+ if (sensitive_data.host_keys != NULL && the_active_state != NULL)
|
|
+ destroy_sensitive_data(the_active_state, is_privsep_child);
|
|
+ if (the_active_state != NULL)
|
|
+ packet_destroy_all(the_active_state, 1, is_privsep_child);
|
|
#ifdef SSH_AUDIT_EVENTS
|
|
/* done after do_cleanup so it can cancel the PAM auth 'thread' */
|
|
- if (the_active_state != NULL && (!use_privsep || mm_is_monitor()))
|
|
+ if (the_active_state != NULL &&
|
|
+ (the_authctxt == NULL || !the_authctxt->authenticated) &&
|
|
+ (!use_privsep || mm_is_monitor()))
|
|
audit_event(the_active_state, SSH_CONNECTION_ABANDON);
|
|
#endif
|
|
_exit(i);
|
|
Index: openssh-8.8p1/sshkey.c
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/sshkey.c
|
|
+++ openssh-8.8p1/sshkey.c
|
|
@@ -371,6 +371,38 @@ sshkey_type_is_valid_ca(int type)
|
|
}
|
|
|
|
int
|
|
+sshkey_is_private(const struct sshkey *k)
|
|
+{
|
|
+ switch (k->type) {
|
|
+#ifdef WITH_OPENSSL
|
|
+ case KEY_RSA_CERT:
|
|
+ case KEY_RSA: {
|
|
+ const BIGNUM *d;
|
|
+ RSA_get0_key(k->rsa, NULL, NULL, &d);
|
|
+ return d != NULL;
|
|
+ }
|
|
+ case KEY_DSA_CERT:
|
|
+ case KEY_DSA: {
|
|
+ const BIGNUM *priv_key;
|
|
+ DSA_get0_key(k->dsa, NULL, &priv_key);
|
|
+ return priv_key != NULL;
|
|
+ }
|
|
+#ifdef OPENSSL_HAS_ECC
|
|
+ case KEY_ECDSA_CERT:
|
|
+ case KEY_ECDSA:
|
|
+ return EC_KEY_get0_private_key(k->ecdsa) != NULL;
|
|
+#endif /* OPENSSL_HAS_ECC */
|
|
+#endif /* WITH_OPENSSL */
|
|
+ case KEY_ED25519_CERT:
|
|
+ case KEY_ED25519:
|
|
+ return (k->ed25519_pk != NULL);
|
|
+ default:
|
|
+ /* fatal("key_is_private: bad key type %d", k->type); */
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+
|
|
+int
|
|
sshkey_is_cert(const struct sshkey *k)
|
|
{
|
|
if (k == NULL)
|
|
Index: openssh-8.8p1/sshkey.h
|
|
===================================================================
|
|
--- openssh-8.8p1.orig/sshkey.h
|
|
+++ openssh-8.8p1/sshkey.h
|
|
@@ -189,6 +189,7 @@ int sshkey_shield_private(struct sshke
|
|
int sshkey_unshield_private(struct sshkey *);
|
|
|
|
int sshkey_type_from_name(const char *);
|
|
+int sshkey_is_private(const struct sshkey *);
|
|
int sshkey_is_cert(const struct sshkey *);
|
|
int sshkey_is_sk(const struct sshkey *);
|
|
int sshkey_type_is_cert(int);
|