19629847 OpenSSH does not support Solaris Audit for login/logout.
authorgww <gary.winiger@oracle.com>
Thu, 04 Dec 2014 16:14:22 -0800
changeset 3513 37c4496b7ed3
parent 3508 fdf76823ed00
child 3514 2e61fec590f9
19629847 OpenSSH does not support Solaris Audit for login/logout.
components/openssh/Makefile
components/openssh/patches/018-cannot_audit-mising.patch
components/openssh/patches/022-solaris_audit.patch
components/openssh/sources/audit-solaris.c
--- a/components/openssh/Makefile	Wed Dec 03 15:30:29 2014 +0100
+++ b/components/openssh/Makefile	Thu Dec 04 16:14:22 2014 -0800
@@ -50,7 +50,6 @@
 CFLAGS += -DSET_USE_PAM
 CFLAGS += -DDEPRECATE_SUNSSH_OPT
 CFLAGS += -DKRB5_BUILD_FIX
-CFLAGS += -DAUE_openssh=6172
 CFLAGS += -DDTRACE_SFTP
 CFLAGS += -DDISABLE_BANNER
 CFLAGS += -DPAM_ENHANCEMENT
@@ -70,13 +69,7 @@
 # CONFIGURE_OPTIONS.64.
 CONFIGURE_OPTIONS.64 += LDFLAGS="$(LDFLAGS) -m64"
 
-# Build with BSM audit. Do not check if getaudit and getaudit_addr are in
-# libbsm, because they are no longer in libbsm and not needed any way.
-CONFIGURE_OPTIONS += --with-audit=bsm
-CONFIGURE_OPTIONS += "ac_cv_lib_bsm_getaudit=yes"       
-CONFIGURE_OPTIONS += "ac_cv_func_getaudit=yes"
-CONFIGURE_OPTIONS += "ac_cv_func_getaudit_addr=yes"
-     
+CONFIGURE_OPTIONS += --with-audit=solaris
 CONFIGURE_OPTIONS += --with-libedit
 CONFIGURE_OPTIONS += --with-kerberos5
 CONFIGURE_OPTIONS += --with-pam
@@ -98,6 +91,9 @@
       $(LN) -fs $(COMPONENT_DIR)/dtrace_sftp/*.[dh] $(SOURCE_DIR); \
     )
 
+# Copy source files that are not yet part of a patch
+COMPONENT_PREP_ACTION += ($(CP) sources/*.c $(@D)/)
+
 # common targets
 configure:	$(CONFIGURE_64)
 
--- a/components/openssh/patches/018-cannot_audit-mising.patch	Wed Dec 03 15:30:29 2014 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,56 +0,0 @@
-#
-# Private symbol cannot_audit() was demoted to local in libbsm.so and is no
-# longer available to its consumers. For OpenSSH sshd this was causing runtime
-# linker errors at accepting connections from clients.
-#
-# On S12 audit is always enabled. As an interim solution to unbreak OpenSSH
-# with S12_57+ libbsm.so, we remove the calls to cannot_audit().
-#
-# Symbol aug_get_machine was demoted to local too. OpenSSH configure checks
-# for aug_get_machine in libbsm.so and provides its own implementation if not
-# present. To avoid OpenSSH built on an S12_56- build machine failing with
-# run-time liker error on S12_57+ system, we overrule configure's
-# HAVE_AUG_GET_MACHINE directly in the code.
-#
-# This patch will be removed once 19629847 is integrated.
-#
-diff -ur old/audit-bsm.c new/audit-bsm.c
---- old/audit-bsm.c	2012-02-23 15:40:43.000000000 -0800
-+++ new/audit-bsm.c	2014-09-18 05:16:43.210289238 -0700
-@@ -81,9 +81,6 @@
- #define AUToReturnFunc(a,b)	au_to_return((a), (u_int)(b))
- #endif
- 
--#ifndef cannot_audit
--extern int	cannot_audit(int);
--#endif
- extern void	aug_init(void);
- extern void	aug_save_auid(au_id_t);
- extern void	aug_save_uid(uid_t);
-@@ -126,6 +123,8 @@
- 
- /* Below is the low-level BSM interface code */
- 
-+/* Force local definition of aug_get_machine */
-+#undef HAVE_AUG_GET_MACHINE
- /*
-  * aug_get_machine is only required on IPv6 capable machines, we use a
-  * different mechanism in audit_connection_from() for IPv4-only machines.
-@@ -355,8 +354,6 @@
- 	AuditInfoTermID *tid = &ssh_bsm_tid;
- 	char buf[1024];
- 
--	if (cannot_audit(0))
--		return;
- 	debug3("BSM audit: connection from %.100s port %d", host, port);
- 
- 	/* populate our terminal id structure */
-@@ -400,8 +397,6 @@
- 	static int logged_in = 0;
- 	const char *user = the_authctxt ? the_authctxt->user : "(unknown user)";
- 
--	if (cannot_audit(0))
--		return;
- 
- 	switch(event) {
- 	case SSH_AUTH_SUCCESS:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openssh/patches/022-solaris_audit.patch	Thu Dec 04 16:14:22 2014 -0800
@@ -0,0 +1,175 @@
+#
+# Add Solaris Auditing configuration (--with-audit=solaris) to openssh-6.5p1.
+#
+# Add phase 1 Solaris Auditing of sshd login/logout to openssh-6.5p1.
+#
+# Additional Solaris Auditing should include audit of password
+#  change.
+# Presuming it is appropriate, this patch should/will be updated
+#  with additional files and updates to sources/audit-solaris.c 
+#
+# Code is developed by the Solaris Audit team.
+# It should/will likely be contributed up stream when done.
+# This patch relies on sources/audit-solaris.c being copied into
+#  the openssh source directory by the Makefile that configures
+#  using --with-audit=solaris.
+#
+# The up stream community has been contacted about the plans.
+#  No reply has yet been received.
+#
+# An additional patch relying on the --with-audit=solaris configuration
+#  should/will be created for sftp Solaris Audit and password change.
+#
+--- orig/config.h.in	2014-11-05 13:11:59.968745838 -0800
++++ new/config.h.in	2014-10-13 14:00:31.117475979 -0700
+@@ -1628,6 +1628,9 @@
+ /* Use Linux audit module */
+ #undef USE_LINUX_AUDIT
+ 
++/* Use Solaris audit module */
++#undef USE_SOLARIS_AUDIT
++
+ /* Enable OpenSSL engine support */
+ #undef USE_OPENSSL_ENGINE
+ 
+--- orig/configure	2014-11-05 13:11:59.971959419 -0800
++++ new/configure	2014-12-04 08:43:59.945675841 -0800
+@@ -1420,7 +1420,7 @@
+   --with-tcp-wrappers[=PATH] Enable tcpwrappers support (optionally in PATH)
+   --with-ldns[=PATH]      Use ldns for DNSSEC support (optionally in PATH)
+   --with-libedit[=PATH]   Enable libedit support for sftp
+-  --with-audit=module     Enable audit support (modules=debug,bsm,linux)
++  --with-audit=module     Enable audit support (modules=debug,bsm,linux,solaris)
+   --with-pie           Build Position Independent Executables if possible
+   --with-ssl-dir=PATH     Specify path to OpenSSL installation
+   --without-openssl-header-check Disable OpenSSL version consistency check
+@@ -10185,6 +10185,27 @@
+ $as_echo "#define USE_LINUX_AUDIT 1" >>confdefs.h
+ 
+ 		;;
++	  solaris)
++		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: solaris" >&5
++$as_echo "solaris" >&6; }
++		AUDIT_MODULE=solaris
++				for ac_header in bsm/adt.h
++do :
++  ac_fn_c_check_header_compile "$LINENO" "bsm/adt.h" "ac_cv_header_bsm_adt_h" ""
++if test "x$ac_cv_header_bsm_adt_h" = xyes; then :
++  cat >>confdefs.h <<_ACEOF
++#define HAVE_ADT_H 1
++_ACEOF
++
++else
++  as_fn_error $? "Solaris Audit enabled and bsm/adt.h not found" "$LINENO" 5
++fi
++
++done
++
++		SSHDLIBS="$SSHDLIBS -lbsm"
++$as_echo "#define USE_SOLARIS_AUDIT 1" >>confdefs.h
++	  	;;
+ 	  debug)
+ 		AUDIT_MODULE=debug
+ 		{ $as_echo "$as_me:${as_lineno-$LINENO}: result: debug" >&5
+--- orig/defines.h	2014-01-17 05:12:38.000000000 -0800
++++ new/defines.h	2014-09-12 10:09:27.000000000 -0700
+@@ -622,6 +622,11 @@
+ # define CUSTOM_SSH_AUDIT_EVENTS
+ #endif
+ 
++#ifdef USE_SOLARIS_AUDIT
++# define SSH_AUDIT_EVENTS
++# define CUSTOM_SSH_AUDIT_EVENTS
++#endif
++
+ #if !defined(HAVE___func__) && defined(HAVE___FUNCTION__)
+ #  define __func__ __FUNCTION__
+ #elif !defined(HAVE___func__)
+--- orig/INSTALL	2013-03-06 17:33:35.000000000 -0800
++++ new/INSTALL	2014-12-04 08:41:24.369920230 -0800
+@@ -97,9 +97,13 @@
+ 
+ Basic Security Module (BSM):
+ 
+-Native BSM support is know to exist in Solaris from at least 2.5.1,
+-FreeBSD 6.1 and OS X.  Alternatively, you may use the OpenBSM
+-implementation (http://www.openbsm.org).
++Native BSM support is known to exist in Solaris from at least 2.5.1
++to Solaris 10.  From Solaris 11 the previously documented BSM (libbsm)
++interfaces are no longer public and are unsupported.  While not public
++interfaces, audit-solaris.c implements Solaris Audit from Solaris 11.
++Native BSM support is known to exist in FreeBSD 6.1 and OS X.
++Alternatively, you may use the OpenBSM implementation
++(http://www.openbsm.org).
+ 
+ 
+ 2. Building / Installation
+@@ -152,8 +156,9 @@
+ There are a few other options to the configure script:
+ 
+ --with-audit=[module] enable additional auditing via the specified module.
+-Currently, drivers for "debug" (additional info via syslog) and "bsm"
+-(Sun's Basic Security Module) are supported.
++Currently, drivers for "debug" (additional info via syslog), and "bsm"
++(Sun's Legacy Basic Security Module prior to Solaris 11), and "solaris"
++(Sun's Audit infrastructure from Solaris 11) are supported.
+ 
+ --with-pam enables PAM support. If PAM support is compiled in, it must
+ also be enabled in sshd_config (refer to the UsePAM directive).
+--- orig/Makefile.in	2014-11-12 15:18:05.366726810 -0800
++++ new/Makefile.in	2014-11-12 15:22:36.825227512 -0800
+@@ -84,7 +84,7 @@
+ 	roaming_common.o roaming_client.o
+ 
+ SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
+-	audit.o audit-bsm.o audit-linux.o platform.o \
++	audit.o audit-bsm.o audit-linux.o audit-solaris.o platform.o \
+ 	sshpty.o sshlogin.o servconf.o serverloop.o \
+ 	auth.o auth1.o auth2.o auth-options.o session.o \
+ 	auth-chall.o auth2-chall.o groupaccess.o \
+--- orig/README.platform	2009-08-28 16:14:48.000000000 -0700
++++ new/README.platform	2014-09-12 09:45:50.000000000 -0700
+@@ -68,8 +68,8 @@
+ libssl-dev, libz-dev and libpam-dev.
+ 
+ 
+-Solaris
+--------
++Prior to Solaris 11
++-------------------
+ If you enable BSM auditing on Solaris, you need to update audit_event(4)
+ for praudit(1m) to give sensible output.  The following line needs to be
+ added to /etc/security/audit_event:
+@@ -82,6 +82,9 @@
+ number is already in use on your system, you may change it at build time
+ by configure'ing --with-cflags=-DAUE_openssh=32801 then rebuilding.
+ 
++From Solaris 11
++---------------
++Solaris Audit is supported by configuring --with-audit=solaris.
+ 
+ Platforms using PAM
+ -------------------
+--- orig/sshd.c	2014-11-05 13:11:59.974945893 -0800
++++ new/sshd.c	2014-11-10 13:33:12.279354856 -0800
+@@ -2139,7 +2139,9 @@
+ #endif 
+ 
+ #ifdef SSH_AUDIT_EVENTS
++#ifndef	USE_SOLARIS_AUDIT
+ 	audit_event(SSH_AUTH_SUCCESS);
++#endif	/* !USE_SOLARIS_AUDIT */
+ #endif
+ 
+ #ifdef GSSAPI
+@@ -2169,6 +2171,10 @@
+ 		do_pam_session();
+ 	}
+ #endif
++#ifdef	USE_SOLARIS_AUDIT
++	/* Audit should take place after all successful pam */
++	audit_event(SSH_AUTH_SUCCESS);
++#endif	/* USE_SOLARIS_AUDIT */
+ 
+ 	/*
+ 	 * In privilege separation, we fork another child and prepare
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/openssh/sources/audit-solaris.c	Thu Dec 04 16:14:22 2014 -0800
@@ -0,0 +1,557 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ */
+
+#include "includes.h"
+#if defined(USE_SOLARIS_AUDIT)
+
+#include "audit.h"
+#include "buffer.h"
+#include "key.h"
+#include "hostfile.h"
+#include "auth.h"
+#include "log.h"
+#include "packet.h"
+
+#include <errno.h>
+#include <pwd.h>
+#include <string.h>
+
+#include <bsm/adt.h>
+#include <bsm/adt_event.h>
+
+#ifdef	ADT_DEBUG
+#include <bsm/audit.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <values.h>
+#include <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ucred.h>
+#include <values.h>
+
+#include <bsm/adt.h>
+#include <bsm/audit.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/* semi private adt functions to extract information */
+
+extern void adt_get_asid(const adt_session_data_t *, au_asid_t *);
+extern void adt_get_auid(const adt_session_data_t *, au_id_t *);
+extern void adt_get_mask(const adt_session_data_t *, au_mask_t *);
+extern void adt_get_termid(const adt_session_data_t *, au_tid_addr_t *);
+
+extern void __auditd_debug(char *, ...);
+
+void
+__audit_pidinfo(void)
+{
+	adt_session_data_t *ah = NULL;
+	au_id_t	auid;
+	char *auid_name = "badname";
+	struct passwd *pwd;
+	au_asid_t asid;
+	au_mask_t mask;
+	char flags[512];
+	au_tid_addr_t tid;
+	char	pbuf[INET6_ADDRSTRLEN];
+	int	af = AF_INET;
+	int	remote;
+	int	local;
+
+	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
+		__auditd_debug("cannot start session %s\n", strerror(errno));
+		return;
+	}
+	if (ah == NULL) {
+		__auditd_debug("ah is NULL\n");
+		return;
+	}
+	adt_get_auid(ah, &auid);
+	if ((pwd = getpwuid((uid_t)auid)) != NULL) {
+		auid_name = pwd->pw_name;
+	}
+	__auditd_debug("audit id = %s(%d)\n", auid_name, auid);
+
+	adt_get_mask(ah, &mask);
+	if (getauditflagschar(flags, &mask, NULL) < 0) {
+		(void) strlcpy(flags, "badflags", sizeof (flags));
+	}
+#ifdef	_LP64
+	__auditd_debug("preselection mask = %s(0x%lx,0x%lx)\n", flags,
+	    mask.am_success, mask.am_failure);
+#else	/* _ILP32 */
+	__auditd_debug("preselection mask = %s(0x%llx,0x%llx)\n", flags,
+	    mask.am_success, mask.am_failure);
+#endif	/* _LP64 */
+
+	adt_get_termid(ah, &tid);
+	__auditd_debug("tid type=%d, maj=%u, min=%u, addr=%x:%x:%x:%x\n",
+	    tid.at_type,
+	    (uint16_t)((tid.at_port) >> BITS(uint16_t)),
+	    (uint16_t)(tid.at_port & UINT16_MAX),
+	    tid.at_addr[0],
+	    tid.at_addr[1],
+	    tid.at_addr[2],
+	    tid.at_addr[3]);
+	if (tid.at_type == AU_IPv6) {
+		af = AF_INET6;
+	}
+	(void) inet_ntop(af, (void *)(tid.at_addr), pbuf,
+	    sizeof (pbuf));
+	remote = (tid.at_port >> BITS(uint16_t));
+	local = (tid.at_port & UINT16_MAX);
+	__auditd_debug("tid type-%d (remote,local,host)= %u,%u,%s\n",
+	    tid.at_type, remote, local, pbuf);
+	adt_get_asid(ah, &asid);
+	__auditd_debug("audit session id = %u\n",  asid);
+	(void) adt_end_session(ah);
+}
+#else	/* !ADT_DEBUG */
+/*ARGSUSED*/
+/*PRINTFLIKE1*/
+static void
+__auditd_debug(char *fmt, ...)
+{
+}
+static void
+__audit_pidinfo()
+{
+}
+#endif	/* ADT_DEBUG */
+
+#include <security/pam_appl.h>
+
+#include <sys/types.h>
+
+extern Authctxt *the_authctxt;
+
+extern const char *audit_username(void);
+extern const char *audit_event_lookup(ssh_audit_event_t);
+
+static adt_session_data_t *ah = NULL;		/* audit session handle */
+static adt_termid_t	*tid = NULL;		/* peer terminal id */
+
+static void audit_login(void);
+static void audit_logout(void);
+static void audit_fail(int);
+
+/* Below is the sshd audit API Solaris adt interpretation */
+
+/*
+ * Called after a connection has been accepted but before any authentication
+ * has been attempted.
+ */
+/* ARGSUSED */
+void
+audit_connection_from(const char *host, int port)
+{
+	int peer = packet_get_connection_in();
+	adt_session_data_t	*ah;
+
+	if (adt_load_termid(peer, &tid) != 0) {
+		error("adt audit_connection_from: unable to load tid for %d:%s",
+		    peer, strerror(errno));
+	}
+	if (adt_start_session(&ah, NULL, 0) != 0) {
+		error("adt audit_connection_from: unable to start session "
+		    "for %s:%d:%s", host, port, strerror(errno));
+	}
+	if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT, 0,
+	    ADT_NO_AUDIT, tid, ADT_SETTID) != 0) {
+		error("adt audit_connection_from: unable to set user "
+		    "for %s:%d:%s", host, port, strerror(errno));
+		(void) adt_end_session(ah);
+		ah = NULL;
+	}
+	if (adt_set_proc(ah) != 0) {
+		error("adt audit_connection_from: unable to set proc "
+		    "for %s:%d:%s", host, port, strerror(errno));
+	}
+	(void) adt_end_session(ah);
+	debug("adt audit_connection_from(%s, %d): peerfd=%d", host, port,
+	    peer);
+	__auditd_debug("%d/%d:%d-adt audit_connection_from(%s, %d)ctxt=%p: "
+	    "peerfd=%d\n", getpid(), getuid(), geteuid(), host, port,
+	    (void *)the_authctxt, peer);
+	__audit_pidinfo();
+}
+
+/*
+ * Called when various events occur (see audit.h for a list of possible
+ * events and what they mean).
+ *
+ *	Entry	the_authcntxt
+ */
+void
+audit_event(ssh_audit_event_t event)
+{
+	static boolean_t logged_in = B_FALSE;	/* if user did login */
+	int fail = PAM_IGNORE;		/* default unset */
+	static boolean_t did_maxtries = B_FALSE; /* if interactive and abort */
+
+	debug("adt audit_event(%s)", audit_event_lookup(event));
+	__auditd_debug("%d/%d:%d-adt audit_event(%s/%s)ctxt=%p\n",
+	    getpid(), getuid(), geteuid(), audit_event_lookup(event),
+	    audit_username(), (void *)the_authctxt);
+	__audit_pidinfo();
+
+	switch (event) {
+	case SSH_AUTH_SUCCESS:		/* authentication success */
+		logged_in = B_TRUE;
+		audit_login(); 		/* ADT_ssh; */
+		return;
+
+	case SSH_CONNECTION_CLOSE:	/* connection closed, all done */
+		if (logged_in) {
+			audit_logout();		/* ADT_logout; */
+			logged_in = B_FALSE;
+		} else {
+			error("adt audit_event logout without login");
+		}
+		return;
+
+	/* Translate fail events to Solaris PAM errors */
+
+	/* auth2.c: userauth_finish as audit_event(SSH_LOGIN_EXCEED_MAXTRIES) */
+	/* auth1.c:do_authloop audit_event(SSH_LOGIN_EXCEED_MAXTRIES) */
+	case SSH_LOGIN_EXCEED_MAXTRIES:
+		fail = PAM_MAXTRIES;
+		did_maxtries = B_TRUE;
+		break;
+
+	/* auth2.c: userauth_finish as audit_event(SSH_LOGIN_ROOT_DENIED) */
+	/* auth1.c:do_authloop audit_event(SSH_LOGIN_ROOT_DENIED) */
+	case SSH_LOGIN_ROOT_DENIED:
+		fail = PAM_PERM_DENIED;
+		break;
+
+	/* auth2.c: input_userauth_request as audit_event(SSH_INVALID_USER) */
+	/* auth.c: getpwnamallow as audit_event(SSH_INVALID_USER) */
+	case SSH_INVALID_USER:
+		fail = PAM_USER_UNKNOWN;
+		break;
+
+	/* seems unused, but translate to the Solaris PAM error */
+	case SSH_NOLOGIN:
+		fail = PAM_LOGINS_DISABLED;
+		break;
+
+	/*
+	 * auth.c in auth_log as it's walking through methods calls
+	 * audit_classify_method(method) which maps
+	 *
+	 * none		-> SSH_AUTH_FAIL_NONE
+	 * password	-> SSH_AUTH_FAIL_PASSWD
+	 *
+	 * publickey	-> SSH_AUTH_FAIL_PUBKEY
+	 * rsa		-> SSH_AUTH_FAIL_PUBKEY
+	 *
+	 * keyboard-interactive	-> SSH_AUTH_FAIL_KBDINT
+	 * challenge-response	-> SSH_AUTH_FAIL_KBDINT
+	 *
+	 * hostbased	-> SSH_AUTH_FAIL_HOSTBASED
+	 * rhosts-rsa	-> SSH_AUTH_FAIL_HOSTBASED
+	 *
+	 * gssapi-with-mic	-> SSH_AUTH_FAIL_GSSAPI
+	 *
+	 * unknown method	-> SSH_AUDIT_UNKNOWN
+	 */
+	/*
+	 * see mon_table mon_dispatch_proto20[], mon_dispatch_postauth20[],
+	 * mon_dispatch_proto15[], mon_dispatch_postauth15[]:
+	 * MONITOR_REQ_AUDIT_EVENT
+	 * called from monitor.c:mm_answer_audit_event()
+	 * SSH_AUTH_FAIL_PUBKEY, SSH_AUTH_FAIL_HOSTBASED,
+	 * SSH_AUTH_FAIL_GSSAPI, SSH_LOGIN_EXCEED_MAXTRIES,
+	 * SSH_LOGIN_ROOT_DENIED, SSH_CONNECTION_CLOSE SSH_INVALID_USER
+	 * monitor_wrap.c: mm_audit_event()
+	 */
+	case SSH_AUTH_FAIL_NONE:	/* auth type none */
+	case SSH_AUTH_FAIL_PUBKEY:	/* authtype publickey */
+		break;
+
+	case SSH_AUTH_FAIL_PASSWD:	/* auth type password */
+	case SSH_AUTH_FAIL_KBDINT:	/* authtype keyboard-interactive */
+	case SSH_AUTH_FAIL_HOSTBASED:	/* auth type hostbased */
+	case SSH_AUTH_FAIL_GSSAPI:	/* auth type gssapi-with-mic */
+	case SSH_AUDIT_UNKNOWN:		/* auth type unknown */
+		fail = PAM_AUTH_ERR;
+		break;
+
+	/* sshd.c: cleanup_exit: server specific fatal cleanup */
+	case SSH_CONNECTION_ABANDON:	/* bailing with fatal error */
+		/*
+		 * This seems to occur with OpenSSH client when
+		 * the user login shell exits.
+		 */
+		if (logged_in) {
+			audit_logout();		/* ADT_logout; */
+			logged_in = B_FALSE;
+			return;
+		} else if (!did_maxtries) {
+			fail = PAM_AUTHINFO_UNAVAIL;
+		} else {
+			/* reset saw max tries */
+			did_maxtries = FALSE;
+		}
+		break;
+
+	default:
+		error("adt audit_event: unknown event %d", event);
+		__auditd_debug("%d/%d:%d-unknown event %d",
+		    getpid(), getuid(), geteuid(), event);
+		__audit_pidinfo();
+		break;
+	}
+	audit_fail(fail);
+}
+
+/*
+ * Called when a user session is started.  Argument is the tty allocated to
+ * the session, or NULL if no tty was allocated.
+ *
+ * Note that this may be called multiple times if multiple sessions are used
+ * within a single connection.
+ */
+/* ARGSUSED */
+void
+audit_session_open(struct logininfo *li)
+{
+	const char *t = li->line ? li->line : "(no tty)";
+
+	debug("adt audit_session_open: user=%s:tty=%s", audit_username(),
+	    t);
+	__auditd_debug("%d/%d:%d-adt audit_session_open:ctxt=%p "
+	    "user=%s:tty=%s\n", getpid(), getuid(), geteuid(),
+	    (void *)the_authctxt, audit_username(), t);
+	__audit_pidinfo();
+}
+
+/*
+ * Called when a user session is closed.  Argument is the tty allocated to
+ * the session, or NULL if no tty was allocated.
+ *
+ * Note that this may be called multiple times if multiple sessions are used
+ * within a single connection.
+ */
+/* ARGSUSED */
+void
+audit_session_close(struct logininfo *li)
+{
+	const char *t = li->line ? li->line : "(no tty)";
+
+	debug("adt audit_session_close: user=%s:tty=%s", audit_username(),
+	    t);
+	__auditd_debug("%d/%d:%d-adt audit_session_close:ctxt=%p "
+	    "user=%s:tty=%s\n", getpid(), getuid(), geteuid(),
+	    (void *)the_authctxt, audit_username(), t);
+	__audit_pidinfo();
+}
+
+/*
+ * 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.
+ */
+/* ARGSUSED */
+void
+audit_run_command(const char *command)
+{
+	debug("adt audit_run_command: \"%s\"", command);
+	__auditd_debug("%d/%d:%d-adt audit_run_command:ctxt=%p \"%s\"\n",
+	    getpid(), getuid(), geteuid(), (void *)the_authctxt, command);
+	__audit_pidinfo();
+}
+
+/*
+ * audit_login - audit successful login
+ *
+ *	Entry	the_authctxt should be valid ;-)
+ *		and pam_setcred called.
+ *		adt_info &  ADT_INFO_PW_SUCCESS if successful
+ *		password change.
+ *
+ *	Exit	ah = audit session established for audit_logout();
+ */
+static void
+audit_login(void)
+{
+	adt_event_data_t *event;
+	uid_t uid = ADT_NO_ATTRIB;
+	gid_t gid = (gid_t)ADT_NO_ATTRIB;
+	au_id_t	auid;
+
+	if ((the_authctxt != NULL) && (the_authctxt->valid != 0)) {
+		uid = the_authctxt->pw->pw_uid;
+		gid = the_authctxt->pw->pw_gid;
+	}
+
+	if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
+		error("adt_start_session: %s", strerror(errno));
+		return;
+	}
+
+	adt_get_auid(ah, &auid);
+
+	if (adt_set_user(ah, uid, gid, uid, gid, NULL,
+	    auid == AU_NOAUDITID ? ADT_NEW : ADT_USER)) {
+		error("adt_set_user auid=%d, uid=%d", auid, uid);
+		(void) adt_end_session(ah);
+		ah = NULL;
+		free(tid);
+		tid = NULL;
+		return;
+	}
+	if ((event = adt_alloc_event(ah, ADT_ssh)) == NULL) {
+		error("adt_alloc_event(ADT_ssh): %s", strerror(errno));
+		return;
+	}
+	if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
+		error("adt_put_event(ADT_ssh, ADT_SUCCESS): %s",
+		    strerror(errno));
+	}
+	/* should audit successful password change here */
+	adt_free_event(event);
+}
+
+/*
+ * audit_logout - audit the logout
+ *
+ *	Entry	ah = audit session.
+ */
+static void
+audit_logout(void)
+{
+	adt_event_data_t *event;
+
+	if ((event = adt_alloc_event(ah, ADT_logout)) == NULL) {
+		error("adt_alloc_event(ADT_logout): %s", strerror(errno));
+		return;
+	}
+	if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
+		error("adt_put_event(ADT_logout, ADT_SUCCESS): %s",
+		    strerror(errno));
+	}
+	adt_free_event(event);
+	(void) adt_end_session(ah);
+	ah = NULL;
+	free(tid);
+	tid = NULL;
+}
+
+/*
+ * audit_fail - audit login failure.
+ *
+ *	Entry	the_authctxt assumed to have some info.
+ *			user = user who asked to be authenticated.
+ *		tid = connection audit TID set by audit_connect_from();
+ *
+ *	N.B.	pam_strerror() prototype takes a pam handle and error number.
+ *		At least on Solaris, pam_strerror never uses the pam handle.
+ *		Since there doesn't seem to be a pam handle available, this
+ *		code just uses NULL.
+ */
+static void
+audit_fail(int pamerr)
+{
+	adt_session_data_t *ah = NULL;
+	adt_event_data_t *event;
+	uid_t	uid = ADT_NO_ATTRIB;
+	gid_t	gid = (gid_t)ADT_NO_ATTRIB;
+
+	__auditd_debug("%d/%d:%d-audit_fail(%s) ctxt=%p\n",
+	    getpid(), getuid(), geteuid(), pam_strerror(NULL, pamerr),
+	    (void *)the_authctxt);
+	if (the_authctxt != NULL) {
+		__auditd_debug("valid=%d, user=%s, uid=%d\n",
+		    the_authctxt->valid, the_authctxt->user,
+		    the_authctxt->pw->pw_uid);
+	} else {
+		__auditd_debug("\tNo autxctxt\n");
+	}
+	__audit_pidinfo();
+	if (pamerr == PAM_IGNORE) {
+		return;
+	}
+	if ((the_authctxt != NULL) || (the_authctxt->valid != 0)) {
+		uid = the_authctxt->pw->pw_uid;
+		gid = the_authctxt->pw->pw_gid;
+	} else if ((the_authctxt != NULL) || (the_authctxt->user != NULL)) {
+		struct passwd *pw;
+
+		if ((pw = getpwnam(the_authctxt->user)) != NULL) {
+			uid = pw->pw_uid;
+			gid = pw->pw_gid;
+		}
+	}
+	if (adt_start_session(&ah, NULL, 0) != 0) {
+		error("adt_start_session(ADT_ssh, 0, fail=%s):"
+		    " %s", pam_strerror(NULL, pamerr), strerror(errno));
+		__auditd_debug("%d/%d:%d-adt_start_session(ADT_ssh, "
+		    "PROC_DATA, fail=%s): %s", getpid(), getuid(),
+		    geteuid(), pam_strerror(NULL, pamerr),
+		    strerror(errno));
+		return;
+	}
+	__auditd_debug("%d/%d:%d-audit_fail+start_session() ah=%p\n",
+	    getpid(), getuid(), geteuid(), (void *)ah);
+	if (adt_set_user(ah, uid, gid, uid, gid, tid, ADT_NEW) != 0) {
+		error("adt_set_user(ADT_ssh, PROC_DATA, fail=%s): %s",
+		    pam_strerror(NULL, pamerr), strerror(errno));
+		__auditd_debug("%d/%d:%d-adt_set_user(ADT_ssh, "
+		    "PROC_DATA, fail=%s): %s", getpid(), getuid(),
+		    geteuid(), pam_strerror(NULL, pamerr),
+		    strerror(errno));
+		goto done;
+	}
+	__auditd_debug("%d/%d:%d-audit_fail+set_user() ah=%p\n", getpid(),
+	    getuid(), geteuid(), (void *)ah);
+	if ((event = adt_alloc_event(ah, ADT_ssh)) == NULL) {
+		error("adt_alloc_event(ADT_ssh, fail=%s): %s",
+		    pam_strerror(NULL, pamerr), strerror(errno));
+		__auditd_debug("%d/%d:%d-adt_set_user(ADT_ssh, 0, "
+		    "fail=%s): %s", getpid(), getuid(), geteuid(),
+		    pam_strerror(NULL, pamerr), strerror(errno));
+	} else if (adt_put_event(event, ADT_FAILURE,
+	    ADT_FAIL_PAM + pamerr) != 0) {
+		error("adt_put_event(ADT_ssh, fail=%s): %s",
+		    pam_strerror(NULL, pamerr), strerror(errno));
+		__auditd_debug("%d/%d:%d-adt_put_event(ADT_ssh, fail=%s): %s",
+		    getpid(), getuid(), geteuid(), pam_strerror(NULL, pamerr),
+		    strerror(errno));
+	}
+	__auditd_debug("%d/%d:%d-audit_fail+put_event() ah=%p\n", getpid(),
+	    getuid(), geteuid(), (void *)ah);
+	/* should audit authentication with failed password change here. */
+	adt_free_event(event);
+done:
+	(void) adt_end_session(ah);
+}
+#endif	/* USE_SOLARIS_AUDIT */