1 From b60fe491735349ba901b371dc8a0d1cd5ab163da Mon Sep 17 00:00:00 2001
   2 From: oracle <solaris@oracle.com>
   3 Date: Mon, 3 Aug 2015 14:37:01 -0700
   4 Subject: [PATCH 15/36] Solaris Auditing support
   5 
   6 #
   7 # Add Solaris Auditing configuration (--with-audit=solaris) to openssh-6.5p1.
   8 #
   9 # Add phase 1 Solaris Auditing of sshd login/logout to openssh-6.5p1.
  10 #
  11 # Additional Solaris Auditing should include audit of password
  12 #  change.
  13 # Presuming it is appropriate, this patch should/will be updated
  14 #  with additional files and updates to sources/audit-solaris.c
  15 #
  16 # Code is developed by the Solaris Audit team.
  17 # It should/will likely be contributed up stream when done.
  18 # This patch relies on sources/audit-solaris.c being copied into
  19 #  the openssh source directory by the Makefile that configures
  20 #  using --with-audit=solaris.
  21 #
  22 # The up stream community has been contacted about the plans.
  23 #  No reply has yet been received.
  24 #
  25 # An additional patch relying on the --with-audit=solaris configuration
  26 #  should/will be created for sftp Solaris Audit and password change.
  27 #
  28 ---
  29  INSTALL         |  15 +-
  30  Makefile.in     |   2 +-
  31  README.platform |   7 +-
  32  audit-solaris.c | 562 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  33  configure.ac    |   9 +-
  34  defines.h       |   5 +
  35  sshd.c          |   6 +
  36  7 files changed, 597 insertions(+), 9 deletions(-)
  37  create mode 100644 audit-solaris.c
  38 
  39 diff --git a/INSTALL b/INSTALL
  40 index cbbb2df..765d4aa 100644
  41 --- a/INSTALL
  42 +++ b/INSTALL
  43 @@ -92,9 +92,13 @@ http://www.gnu.org/software/autoconf/
  44  
  45  Basic Security Module (BSM):
  46  
  47 -Native BSM support is know to exist in Solaris from at least 2.5.1,
  48 -FreeBSD 6.1 and OS X.  Alternatively, you may use the OpenBSM
  49 -implementation (http://www.openbsm.org).
  50 +Native BSM support is known to exist in Solaris from at least 2.5.1
  51 +to Solaris 10.  From Solaris 11 the previously documented BSM (libbsm)
  52 +interfaces are no longer public and are unsupported.  While not public
  53 +interfaces, audit-solaris.c implements Solaris Audit from Solaris 11.
  54 +Native BSM support is known to exist in FreeBSD 6.1 and OS X.
  55 +Alternatively, you may use the OpenBSM implementation
  56 +(http://www.openbsm.org).
  57  
  58  
  59  2. Building / Installation
  60 @@ -147,8 +151,9 @@ name).
  61  There are a few other options to the configure script:
  62  
  63  --with-audit=[module] enable additional auditing via the specified module.
  64 -Currently, drivers for "debug" (additional info via syslog) and "bsm"
  65 -(Sun's Basic Security Module) are supported.
  66 +Currently, drivers for "debug" (additional info via syslog), and "bsm"
  67 +(Sun's Legacy Basic Security Module prior to Solaris 11), and "solaris"
  68 +(Sun's Audit infrastructure from Solaris 11) are supported.
  69  
  70  --with-pam enables PAM support. If PAM support is compiled in, it must
  71  also be enabled in sshd_config (refer to the UsePAM directive).
  72 diff --git a/Makefile.in b/Makefile.in
  73 index 121a261..62e6a84 100644
  74 --- a/Makefile.in
  75 +++ b/Makefile.in
  76 @@ -101,7 +101,7 @@ SSHOBJS= ssh.o readconf.o clientloop.o sshtty.o \
  77         roaming_common.o roaming_client.o
  78  
  79  SSHDOBJS=sshd.o auth-rhosts.o auth-passwd.o auth-rsa.o auth-rh-rsa.o \
  80 -       audit.o audit-bsm.o audit-linux.o platform.o \
  81 +       audit.o audit-bsm.o audit-linux.o audit-solaris.o platform.o \
  82         sshpty.o sshlogin.o servconf.o serverloop.o \
  83         auth.o auth1.o auth2.o auth-options.o session.o \
  84         auth-chall.o auth2-chall.o groupaccess.o \
  85 diff --git a/README.platform b/README.platform
  86 index d198232..6949998 100644
  87 --- a/README.platform
  88 +++ b/README.platform
  89 @@ -68,8 +68,8 @@ zlib-devel and pam-devel, on Debian based distros these may be
  90  libssl-dev, libz-dev and libpam-dev.
  91  
  92  
  93 -Solaris
  94 --------
  95 +Prior to Solaris 11
  96 +-------------------
  97  If you enable BSM auditing on Solaris, you need to update audit_event(4)
  98  for praudit(1m) to give sensible output.  The following line needs to be
  99  added to /etc/security/audit_event:
 100 @@ -82,6 +82,9 @@ There is no official registry of 3rd party event numbers, so if this
 101  number is already in use on your system, you may change it at build time
 102  by configure'ing --with-cflags=-DAUE_openssh=32801 then rebuilding.
 103  
 104 +From Solaris 11
 105 +---------------
 106 +Solaris Audit is supported by configuring --with-audit=solaris.
 107  
 108  Platforms using PAM
 109  -------------------
 110 diff --git a/audit-solaris.c b/audit-solaris.c
 111 new file mode 100644
 112 index 0000000..abf870c
 113 --- /dev/null
 114 +++ b/audit-solaris.c
 115 @@ -0,0 +1,562 @@
 116 +/*
 117 + * CDDL HEADER START
 118 + *
 119 + * The contents of this file are subject to the terms of the
 120 + * Common Development and Distribution License (the "License").
 121 + * You may not use this file except in compliance with the License.
 122 + *
 123 + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 124 + * or http://www.opensolaris.org/os/licensing.
 125 + * See the License for the specific language governing permissions
 126 + * and limitations under the License.
 127 + *
 128 + * When distributing Covered Code, include this CDDL HEADER in each
 129 + * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 130 + * If applicable, add the following below this CDDL HEADER, with the
 131 + * fields enclosed by brackets "[]" replaced with your own identifying
 132 + * information: Portions Copyright [yyyy] [name of copyright owner]
 133 + *
 134 + * CDDL HEADER END
 135 + */
 136 +
 137 +/*
 138 + * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
 139 + */
 140 +
 141 +#include "includes.h"
 142 +#if defined(USE_SOLARIS_AUDIT)
 143 +
 144 +#include "audit.h"
 145 +#include "buffer.h"
 146 +#include "key.h"
 147 +#include "hostfile.h"
 148 +#include "auth.h"
 149 +#include "log.h"
 150 +#include "packet.h"
 151 +
 152 +#include <errno.h>
 153 +#include <pwd.h>
 154 +#include <string.h>
 155 +
 156 +#include <bsm/adt.h>
 157 +#include <bsm/adt_event.h>
 158 +
 159 +#ifdef ADT_DEBUG
 160 +#include <bsm/audit.h>
 161 +#include <arpa/inet.h>
 162 +#include <netinet/in.h>
 163 +#include <values.h>
 164 +#include <errno.h>
 165 +#include <pwd.h>
 166 +#include <stdio.h>
 167 +#include <unistd.h>
 168 +#include <stdarg.h>
 169 +#include <string.h>
 170 +#include <ucred.h>
 171 +#include <values.h>
 172 +
 173 +#include <bsm/adt.h>
 174 +#include <bsm/audit.h>
 175 +
 176 +#include <sys/types.h>
 177 +#include <sys/stat.h>
 178 +
 179 +/* semi private adt functions to extract information */
 180 +
 181 +extern void adt_get_asid(const adt_session_data_t *, au_asid_t *);
 182 +extern void adt_get_auid(const adt_session_data_t *, au_id_t *);
 183 +extern void adt_get_mask(const adt_session_data_t *, au_mask_t *);
 184 +extern void adt_get_termid(const adt_session_data_t *, au_tid_addr_t *);
 185 +
 186 +extern void __auditd_debug(char *, ...);
 187 +
 188 +void
 189 +__audit_pidinfo(void)
 190 +{
 191 +       adt_session_data_t *ah = NULL;
 192 +       au_id_t auid;
 193 +       char *auid_name = "badname";
 194 +       struct passwd *pwd;
 195 +       au_asid_t asid;
 196 +       au_mask_t mask;
 197 +       char flags[512];
 198 +       au_tid_addr_t tid;
 199 +       char    pbuf[INET6_ADDRSTRLEN];
 200 +       int     af = AF_INET;
 201 +       int     remote;
 202 +       int     local;
 203 +
 204 +       if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
 205 +               __auditd_debug("cannot start session %s\n", strerror(errno));
 206 +               return;
 207 +       }
 208 +       if (ah == NULL) {
 209 +               __auditd_debug("ah is NULL\n");
 210 +               return;
 211 +       }
 212 +       adt_get_auid(ah, &auid);
 213 +       if ((pwd = getpwuid((uid_t)auid)) != NULL) {
 214 +               auid_name = pwd->pw_name;
 215 +       }
 216 +       __auditd_debug("audit id = %s(%d)\n", auid_name, auid);
 217 +
 218 +       adt_get_mask(ah, &mask);
 219 +       if (getauditflagschar(flags, &mask, NULL) < 0) {
 220 +               (void) strlcpy(flags, "badflags", sizeof (flags));
 221 +       }
 222 +#ifdef _LP64
 223 +       __auditd_debug("preselection mask = %s(0x%lx,0x%lx)\n", flags,
 224 +           mask.am_success, mask.am_failure);
 225 +#else  /* _ILP32 */
 226 +       __auditd_debug("preselection mask = %s(0x%llx,0x%llx)\n", flags,
 227 +           mask.am_success, mask.am_failure);
 228 +#endif /* _LP64 */
 229 +
 230 +       adt_get_termid(ah, &tid);
 231 +       __auditd_debug("tid type=%d, maj=%u, min=%u, addr=%x:%x:%x:%x\n",
 232 +           tid.at_type,
 233 +           (uint16_t)((tid.at_port) >> BITS(uint16_t)),
 234 +           (uint16_t)(tid.at_port & UINT16_MAX),
 235 +           tid.at_addr[0],
 236 +           tid.at_addr[1],
 237 +           tid.at_addr[2],
 238 +           tid.at_addr[3]);
 239 +       if (tid.at_type == AU_IPv6) {
 240 +               af = AF_INET6;
 241 +       }
 242 +       (void) inet_ntop(af, (void *)(tid.at_addr), pbuf,
 243 +           sizeof (pbuf));
 244 +       remote = (tid.at_port >> BITS(uint16_t));
 245 +       local = (tid.at_port & UINT16_MAX);
 246 +       __auditd_debug("tid type-%d (remote,local,host)= %u,%u,%s\n",
 247 +           tid.at_type, remote, local, pbuf);
 248 +       adt_get_asid(ah, &asid);
 249 +       __auditd_debug("audit session id = %u\n",  asid);
 250 +       (void) adt_end_session(ah);
 251 +}
 252 +#else  /* !ADT_DEBUG */
 253 +/*ARGSUSED*/
 254 +/*PRINTFLIKE1*/
 255 +static void
 256 +__auditd_debug(char *fmt, ...)
 257 +{
 258 +}
 259 +static void
 260 +__audit_pidinfo()
 261 +{
 262 +}
 263 +#endif /* ADT_DEBUG */
 264 +
 265 +#include <security/pam_appl.h>
 266 +
 267 +#include <sys/types.h>
 268 +
 269 +extern Authctxt *the_authctxt;
 270 +
 271 +extern const char *audit_username(void);
 272 +extern const char *audit_event_lookup(ssh_audit_event_t);
 273 +
 274 +static adt_session_data_t *ah = NULL;          /* audit session handle */
 275 +static adt_termid_t    *tid = NULL;            /* peer terminal id */
 276 +
 277 +static void audit_login(void);
 278 +static void audit_logout(void);
 279 +static void audit_fail(int);
 280 +
 281 +/* Below is the sshd audit API Solaris adt interpretation */
 282 +
 283 +/*
 284 + * Called after a connection has been accepted but before any authentication
 285 + * has been attempted.
 286 + */
 287 +/* ARGSUSED */
 288 +void
 289 +audit_connection_from(const char *host, int port)
 290 +{
 291 +       int peer = packet_get_connection_in();
 292 +       adt_session_data_t      *ah;
 293 +
 294 +       if (adt_load_termid(peer, &tid) != 0) {
 295 +               error("adt audit_connection_from: unable to load tid for %d:%s",
 296 +                   peer, strerror(errno));
 297 +       }
 298 +       if (adt_start_session(&ah, NULL, 0) != 0) {
 299 +               error("adt audit_connection_from: unable to start session "
 300 +                   "for %s:%d:%s", host, port, strerror(errno));
 301 +       }
 302 +       if (adt_set_user(ah, ADT_NO_AUDIT, ADT_NO_AUDIT, 0,
 303 +           ADT_NO_AUDIT, tid, ADT_SETTID) != 0) {
 304 +               error("adt audit_connection_from: unable to set user "
 305 +                   "for %s:%d:%s", host, port, strerror(errno));
 306 +               (void) adt_end_session(ah);
 307 +               ah = NULL;
 308 +       }
 309 +       if (adt_set_proc(ah) != 0) {
 310 +               error("adt audit_connection_from: unable to set proc "
 311 +                   "for %s:%d:%s", host, port, strerror(errno));
 312 +       }
 313 +       (void) adt_end_session(ah);
 314 +       debug("adt audit_connection_from(%s, %d): peerfd=%d", host, port,
 315 +           peer);
 316 +       __auditd_debug("%d/%d:%d-adt audit_connection_from(%s, %d)ctxt=%p: "
 317 +           "peerfd=%d\n", getpid(), getuid(), geteuid(), host, port,
 318 +           (void *)the_authctxt, peer);
 319 +       __audit_pidinfo();
 320 +}
 321 +
 322 +/*
 323 + * Called when various events occur (see audit.h for a list of possible
 324 + * events and what they mean).
 325 + *
 326 + *     Entry   the_authcntxt
 327 + */
 328 +void
 329 +audit_event(ssh_audit_event_t event)
 330 +{
 331 +       static boolean_t logged_in = B_FALSE;   /* if user did login */
 332 +       int fail = PAM_IGNORE;          /* default unset */
 333 +       static boolean_t did_maxtries = B_FALSE; /* if interactive and abort */
 334 +
 335 +       debug("adt audit_event(%s)", audit_event_lookup(event));
 336 +       __auditd_debug("%d/%d:%d-adt audit_event(%s/%s)ctxt=%p\n",
 337 +           getpid(), getuid(), geteuid(), audit_event_lookup(event),
 338 +           audit_username(), (void *)the_authctxt);
 339 +       __audit_pidinfo();
 340 +
 341 +       switch (event) {
 342 +       case SSH_AUTH_SUCCESS:          /* authentication success */
 343 +               logged_in = B_TRUE;
 344 +               audit_login();          /* ADT_ssh; */
 345 +               return;
 346 +
 347 +       case SSH_CONNECTION_CLOSE:      /* connection closed, all done */
 348 +               if (logged_in) {
 349 +                       audit_logout();         /* ADT_logout; */
 350 +                       logged_in = B_FALSE;
 351 +               } else {
 352 +                       error("adt audit_event logout without login");
 353 +               }
 354 +               return;
 355 +
 356 +       /* Translate fail events to Solaris PAM errors */
 357 +
 358 +       /* auth2.c: userauth_finish as audit_event(SSH_LOGIN_EXCEED_MAXTRIES) */
 359 +       /* auth1.c:do_authloop audit_event(SSH_LOGIN_EXCEED_MAXTRIES) */
 360 +       case SSH_LOGIN_EXCEED_MAXTRIES:
 361 +               fail = PAM_MAXTRIES;
 362 +               did_maxtries = B_TRUE;
 363 +               break;
 364 +
 365 +       /* auth2.c: userauth_finish as audit_event(SSH_LOGIN_ROOT_DENIED) */
 366 +       /* auth1.c:do_authloop audit_event(SSH_LOGIN_ROOT_DENIED) */
 367 +       case SSH_LOGIN_ROOT_DENIED:
 368 +               fail = PAM_PERM_DENIED;
 369 +               break;
 370 +
 371 +       /* auth2.c: input_userauth_request as audit_event(SSH_INVALID_USER) */
 372 +       /* auth.c: getpwnamallow as audit_event(SSH_INVALID_USER) */
 373 +       case SSH_INVALID_USER:
 374 +               fail = PAM_USER_UNKNOWN;
 375 +               break;
 376 +
 377 +       /* seems unused, but translate to the Solaris PAM error */
 378 +       case SSH_NOLOGIN:
 379 +               fail = PAM_ACCT_EXPIRED;
 380 +               break;
 381 +
 382 +       /*
 383 +        * auth.c in auth_log as it's walking through methods calls
 384 +        * audit_classify_method(method) which maps
 385 +        *
 386 +        * none         -> SSH_AUTH_FAIL_NONE
 387 +        * password     -> SSH_AUTH_FAIL_PASSWD
 388 +        *
 389 +        * publickey    -> SSH_AUTH_FAIL_PUBKEY
 390 +        * rsa          -> SSH_AUTH_FAIL_PUBKEY
 391 +        *
 392 +        * keyboard-interactive -> SSH_AUTH_FAIL_KBDINT
 393 +        * challenge-response   -> SSH_AUTH_FAIL_KBDINT
 394 +        *
 395 +        * hostbased    -> SSH_AUTH_FAIL_HOSTBASED
 396 +        * rhosts-rsa   -> SSH_AUTH_FAIL_HOSTBASED
 397 +        *
 398 +        * gssapi-with-mic      -> SSH_AUTH_FAIL_GSSAPI
 399 +        *
 400 +        * unknown method       -> SSH_AUDIT_UNKNOWN
 401 +        */
 402 +       /*
 403 +        * see mon_table mon_dispatch_proto20[], mon_dispatch_postauth20[],
 404 +        * mon_dispatch_proto15[], mon_dispatch_postauth15[]:
 405 +        * MONITOR_REQ_AUDIT_EVENT
 406 +        * called from monitor.c:mm_answer_audit_event()
 407 +        * SSH_AUTH_FAIL_PUBKEY, SSH_AUTH_FAIL_HOSTBASED,
 408 +        * SSH_AUTH_FAIL_GSSAPI, SSH_LOGIN_EXCEED_MAXTRIES,
 409 +        * SSH_LOGIN_ROOT_DENIED, SSH_CONNECTION_CLOSE SSH_INVALID_USER
 410 +        * monitor_wrap.c: mm_audit_event()
 411 +        */
 412 +       case SSH_AUTH_FAIL_NONE:        /* auth type none */
 413 +       case SSH_AUTH_FAIL_PUBKEY:      /* authtype publickey */
 414 +               break;
 415 +
 416 +       case SSH_AUTH_FAIL_PASSWD:      /* auth type password */
 417 +       case SSH_AUTH_FAIL_KBDINT:      /* authtype keyboard-interactive */
 418 +       case SSH_AUTH_FAIL_HOSTBASED:   /* auth type hostbased */
 419 +       case SSH_AUTH_FAIL_GSSAPI:      /* auth type gssapi-with-mic */
 420 +       case SSH_AUDIT_UNKNOWN:         /* auth type unknown */
 421 +               fail = PAM_AUTH_ERR;
 422 +               break;
 423 +
 424 +       /* sshd.c: cleanup_exit: server specific fatal cleanup */
 425 +       case SSH_CONNECTION_ABANDON:    /* bailing with fatal error */
 426 +               /*
 427 +                * This seems to occur with OpenSSH client when
 428 +                * the user login shell exits.
 429 +                */
 430 +               if (logged_in) {
 431 +                       audit_logout();         /* ADT_logout; */
 432 +                       logged_in = B_FALSE;
 433 +                       return;
 434 +               } else if (!did_maxtries) {
 435 +                       fail = PAM_AUTHINFO_UNAVAIL;
 436 +               } else {
 437 +                       /* reset saw max tries */
 438 +                       did_maxtries = FALSE;
 439 +               }
 440 +               break;
 441 +
 442 +       default:
 443 +               error("adt audit_event: unknown event %d", event);
 444 +               __auditd_debug("%d/%d:%d-unknown event %d",
 445 +                   getpid(), getuid(), geteuid(), event);
 446 +               __audit_pidinfo();
 447 +               break;
 448 +       }
 449 +       audit_fail(fail);
 450 +}
 451 +
 452 +/*
 453 + * Called when a user session is started.  Argument is the tty allocated to
 454 + * the session, or NULL if no tty was allocated.
 455 + *
 456 + * Note that this may be called multiple times if multiple sessions are used
 457 + * within a single connection.
 458 + */
 459 +/* ARGSUSED */
 460 +void
 461 +audit_session_open(struct logininfo *li)
 462 +{
 463 +       const char *t = li->line ? li->line : "(no tty)";
 464 +
 465 +       debug("adt audit_session_open: user=%s:tty=%s", audit_username(),
 466 +           t);
 467 +       __auditd_debug("%d/%d:%d-adt audit_session_open:ctxt=%p "
 468 +           "user=%s:tty=%s\n", getpid(), getuid(), geteuid(),
 469 +           (void *)the_authctxt, audit_username(), t);
 470 +       __audit_pidinfo();
 471 +}
 472 +
 473 +/*
 474 + * Called when a user session is closed.  Argument is the tty allocated to
 475 + * the session, or NULL if no tty was allocated.
 476 + *
 477 + * Note that this may be called multiple times if multiple sessions are used
 478 + * within a single connection.
 479 + */
 480 +/* ARGSUSED */
 481 +void
 482 +audit_session_close(struct logininfo *li)
 483 +{
 484 +       const char *t = li->line ? li->line : "(no tty)";
 485 +
 486 +       debug("adt audit_session_close: user=%s:tty=%s", audit_username(),
 487 +           t);
 488 +       __auditd_debug("%d/%d:%d-adt audit_session_close:ctxt=%p "
 489 +           "user=%s:tty=%s\n", getpid(), getuid(), geteuid(),
 490 +           (void *)the_authctxt, audit_username(), t);
 491 +       __audit_pidinfo();
 492 +}
 493 +
 494 +/*
 495 + * This will be called when a user runs a non-interactive command.  Note that
 496 + * it may be called multiple times for a single connection since SSH2 allows
 497 + * multiple sessions within a single connection.
 498 + */
 499 +/* ARGSUSED */
 500 +void
 501 +audit_run_command(const char *command)
 502 +{
 503 +       debug("adt audit_run_command: \"%s\"", command);
 504 +       __auditd_debug("%d/%d:%d-adt audit_run_command:ctxt=%p \"%s\"\n",
 505 +           getpid(), getuid(), geteuid(), (void *)the_authctxt, command);
 506 +       __audit_pidinfo();
 507 +}
 508 +
 509 +/*
 510 + * audit_login - audit successful login
 511 + *
 512 + *     Entry   the_authctxt should be valid ;-)
 513 + *             and pam_setcred called.
 514 + *             adt_info &  ADT_INFO_PW_SUCCESS if successful
 515 + *             password change.
 516 + *
 517 + *     Exit    ah = audit session established for audit_logout();
 518 + */
 519 +static void
 520 +audit_login(void)
 521 +{
 522 +       adt_event_data_t *event;
 523 +       uid_t uid = ADT_NO_ATTRIB;
 524 +       gid_t gid = (gid_t)ADT_NO_ATTRIB;
 525 +       au_id_t auid;
 526 +
 527 +       if ((the_authctxt != NULL) && (the_authctxt->valid != 0)) {
 528 +               uid = the_authctxt->pw->pw_uid;
 529 +               gid = the_authctxt->pw->pw_gid;
 530 +       }
 531 +
 532 +       if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA) != 0) {
 533 +               error("adt_start_session: %s", strerror(errno));
 534 +               return;
 535 +       }
 536 +
 537 +       adt_get_auid(ah, &auid);
 538 +
 539 +       if (adt_set_user(ah, uid, gid, uid, gid, NULL,
 540 +           auid == AU_NOAUDITID ? ADT_NEW : ADT_USER)) {
 541 +               error("adt_set_user auid=%d, uid=%d", auid, uid);
 542 +               (void) adt_end_session(ah);
 543 +               ah = NULL;
 544 +               free(tid);
 545 +               tid = NULL;
 546 +               return;
 547 +       }
 548 +       if ((event = adt_alloc_event(ah, ADT_ssh)) == NULL) {
 549 +               error("adt_alloc_event(ADT_ssh): %s", strerror(errno));
 550 +               return;
 551 +       }
 552 +       if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
 553 +               error("adt_put_event(ADT_ssh, ADT_SUCCESS): %s",
 554 +                   strerror(errno));
 555 +       }
 556 +       /* should audit successful password change here */
 557 +       adt_free_event(event);
 558 +}
 559 +
 560 +/*
 561 + * audit_logout - audit the logout
 562 + *
 563 + *     Entry   ah = audit session.
 564 + */
 565 +static void
 566 +audit_logout(void)
 567 +{
 568 +       adt_event_data_t *event;
 569 +
 570 +       if ((event = adt_alloc_event(ah, ADT_logout)) == NULL) {
 571 +               error("adt_alloc_event(ADT_logout): %s", strerror(errno));
 572 +               return;
 573 +       }
 574 +       if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS) != 0) {
 575 +               error("adt_put_event(ADT_logout, ADT_SUCCESS): %s",
 576 +                   strerror(errno));
 577 +       }
 578 +       adt_free_event(event);
 579 +       (void) adt_end_session(ah);
 580 +       ah = NULL;
 581 +       free(tid);
 582 +       tid = NULL;
 583 +}
 584 +
 585 +/*
 586 + * audit_fail - audit login failure.
 587 + *
 588 + *     Entry   the_authctxt assumed to have some info.
 589 + *                     user = user who asked to be authenticated.
 590 + *             tid = connection audit TID set by audit_connect_from();
 591 + *
 592 + *     N.B.    pam_strerror() prototype takes a pam handle and error number.
 593 + *             At least on Solaris, pam_strerror never uses the pam handle.
 594 + *             Since there doesn't seem to be a pam handle available, this
 595 + *             code just uses NULL.
 596 + */
 597 +static void
 598 +audit_fail(int pamerr)
 599 +{
 600 +       adt_session_data_t *ah = NULL;
 601 +       adt_event_data_t *event;
 602 +       uid_t   uid = ADT_NO_ATTRIB;
 603 +       gid_t   gid = (gid_t)ADT_NO_ATTRIB;
 604 +
 605 +       __auditd_debug("%d/%d:%d-audit_fail(%s) ctxt=%p\n",
 606 +           getpid(), getuid(), geteuid(), pam_strerror(NULL, pamerr),
 607 +           (void *)the_authctxt);
 608 +       if (the_authctxt != NULL) {
 609 +               uid_t   pwuid = ADT_NO_ATTRIB;
 610 +
 611 +               if (the_authctxt->pw != NULL) {
 612 +                       pwuid = the_authctxt->pw->pw_uid;
 613 +               }
 614 +               __auditd_debug("valid=%d, user=%s, uid=%d\n",
 615 +                   the_authctxt->valid, audit_username(), pwuid);
 616 +       } else {
 617 +               __auditd_debug("\tNo autxctxt\n");
 618 +       }
 619 +       __audit_pidinfo();
 620 +       if (pamerr == PAM_IGNORE) {
 621 +               return;
 622 +       }
 623 +       if ((the_authctxt != NULL) && (the_authctxt->valid != 0)) {
 624 +               uid = the_authctxt->pw->pw_uid;
 625 +               gid = the_authctxt->pw->pw_gid;
 626 +       } else if ((the_authctxt != NULL) && (the_authctxt->user != NULL)) {
 627 +               struct passwd *pw;
 628 +
 629 +               if ((pw = getpwnam(the_authctxt->user)) != NULL) {
 630 +                       uid = pw->pw_uid;
 631 +                       gid = pw->pw_gid;
 632 +               }
 633 +       }
 634 +       if (adt_start_session(&ah, NULL, 0) != 0) {
 635 +               error("adt_start_session(ADT_ssh, 0, fail=%s):"
 636 +                   " %s", pam_strerror(NULL, pamerr), strerror(errno));
 637 +               __auditd_debug("%d/%d:%d-adt_start_session(ADT_ssh, "
 638 +                   "PROC_DATA, fail=%s): %s", getpid(), getuid(),
 639 +                   geteuid(), pam_strerror(NULL, pamerr),
 640 +                   strerror(errno));
 641 +               return;
 642 +       }
 643 +       __auditd_debug("%d/%d:%d-audit_fail+start_session() ah=%p\n",
 644 +           getpid(), getuid(), geteuid(), (void *)ah);
 645 +       if (adt_set_user(ah, uid, gid, uid, gid, tid, ADT_NEW) != 0) {
 646 +               error("adt_set_user(ADT_ssh, PROC_DATA, fail=%s): %s",
 647 +                   pam_strerror(NULL, pamerr), strerror(errno));
 648 +               __auditd_debug("%d/%d:%d-adt_set_user(ADT_ssh, "
 649 +                   "PROC_DATA, fail=%s): %s", getpid(), getuid(),
 650 +                   geteuid(), pam_strerror(NULL, pamerr),
 651 +                   strerror(errno));
 652 +               goto done;
 653 +       }
 654 +       __auditd_debug("%d/%d:%d-audit_fail+set_user() ah=%p\n", getpid(),
 655 +           getuid(), geteuid(), (void *)ah);
 656 +       if ((event = adt_alloc_event(ah, ADT_ssh)) == NULL) {
 657 +               error("adt_alloc_event(ADT_ssh, fail=%s): %s",
 658 +                   pam_strerror(NULL, pamerr), strerror(errno));
 659 +               __auditd_debug("%d/%d:%d-adt_set_user(ADT_ssh, 0, "
 660 +                   "fail=%s): %s", getpid(), getuid(), geteuid(),
 661 +                   pam_strerror(NULL, pamerr), strerror(errno));
 662 +       } else if (adt_put_event(event, ADT_FAILURE,
 663 +           ADT_FAIL_PAM + pamerr) != 0) {
 664 +               error("adt_put_event(ADT_ssh, fail=%s): %s",
 665 +                   pam_strerror(NULL, pamerr), strerror(errno));
 666 +               __auditd_debug("%d/%d:%d-adt_put_event(ADT_ssh, fail=%s): %s",
 667 +                   getpid(), getuid(), geteuid(), pam_strerror(NULL, pamerr),
 668 +                   strerror(errno));
 669 +       }
 670 +       __auditd_debug("%d/%d:%d-audit_fail+put_event() ah=%p\n", getpid(),
 671 +           getuid(), geteuid(), (void *)ah);
 672 +       /* should audit authentication with failed password change here. */
 673 +       adt_free_event(event);
 674 +done:
 675 +       (void) adt_end_session(ah);
 676 +}
 677 +#endif /* USE_SOLARIS_AUDIT */
 678 diff --git a/configure.ac b/configure.ac
 679 index 2985819..b38b1b3 100644
 680 --- a/configure.ac
 681 +++ b/configure.ac
 682 @@ -1547,7 +1547,7 @@ AC_ARG_WITH([libedit],
 683  
 684  AUDIT_MODULE=none
 685  AC_ARG_WITH([audit],
 686 -       [  --with-audit=module     Enable audit support (modules=debug,bsm,linux)],
 687 +       [  --with-audit=module     Enable audit support (modules=debug,bsm,linux,solaris)],
 688         [
 689           AC_MSG_CHECKING([for supported audit module])
 690           case "$withval" in
 691 @@ -1584,6 +1584,13 @@ AC_ARG_WITH([audit],
 692                 SSHDLIBS="$SSHDLIBS -laudit"
 693                 AC_DEFINE([USE_LINUX_AUDIT], [1], [Use Linux audit module])
 694                 ;;
 695 +      solaris)
 696 +        AC_MSG_RESULT([solaris])
 697 +        AUDIT_MODULE=solaris
 698 +        AC_CHECK_HEADERS([bsm/adt.h])
 699 +        SSHDLIBS="$SSHDLIBS -lbsm"
 700 +        AC_DEFINE([USE_SOLARIS_AUDIT], [1], [Use Solaris audit module])
 701 +        ;;
 702           debug)
 703                 AUDIT_MODULE=debug
 704                 AC_MSG_RESULT([debug])
 705 diff --git a/defines.h b/defines.h
 706 index fa0ccba..f2c1678 100644
 707 --- a/defines.h
 708 +++ b/defines.h
 709 @@ -635,6 +635,11 @@ struct winsize {
 710  # define CUSTOM_SSH_AUDIT_EVENTS
 711  #endif
 712  
 713 +#ifdef USE_SOLARIS_AUDIT
 714 +# define SSH_AUDIT_EVENTS
 715 +# define CUSTOM_SSH_AUDIT_EVENTS
 716 +#endif
 717 +
 718  #if !defined(HAVE___func__) && defined(HAVE___FUNCTION__)
 719  #  define __func__ __FUNCTION__
 720  #elif !defined(HAVE___func__)
 721 diff --git a/sshd.c b/sshd.c
 722 index 7e519d4..87032ec 100644
 723 --- a/sshd.c
 724 +++ b/sshd.c
 725 @@ -2234,7 +2234,9 @@ main(int ac, char **av)
 726         }
 727  
 728  #ifdef SSH_AUDIT_EVENTS
 729 +#ifndef        USE_SOLARIS_AUDIT
 730         audit_event(SSH_AUTH_SUCCESS);
 731 +#endif /* !USE_SOLARIS_AUDIT */
 732  #endif
 733  
 734  #ifdef GSSAPI
 735 @@ -2264,6 +2266,10 @@ main(int ac, char **av)
 736                 do_pam_session();
 737         }
 738  #endif
 739 +#ifdef USE_SOLARIS_AUDIT
 740 +       /* Audit should take place after all successful pam */
 741 +       audit_event(SSH_AUTH_SUCCESS);
 742 +#endif /* USE_SOLARIS_AUDIT */
 743  
 744         /*
 745          * In privilege separation, we fork another child and prepare
 746 -- 
 747 2.5.4 (Apple Git-61)
 748