1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  *
  25  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
  26  */
  27 
  28 
  29 #define _REENTRANT
  30 
  31 #include <ctype.h>
  32 #include <errno.h>
  33 #include <grp.h>
  34 #include <libintl.h>
  35 #include <netdb.h>
  36 #include <time.h>
  37 #include <pwd.h>
  38 #include <stdio.h>
  39 #include <stdlib.h>
  40 #include <string.h>
  41 #include <wchar.h>
  42 
  43 #include <arpa/inet.h>
  44 
  45 #include <bsm/audit.h>
  46 #include <bsm/audit_record.h>
  47 #include <bsm/libbsm.h>
  48 #include <security/pam_appl.h>
  49 
  50 #include <sys/inttypes.h>
  51 #include <sys/mkdev.h>
  52 #include <sys/types.h>
  53 #include <aclutils.h>
  54 #include <smbsrv/libsmb.h>
  55 
  56 #include "praudit.h"
  57 #include "toktable.h"
  58 #include "adt_xlate.h"
  59 
  60 static void     convertascii(char *p, char *c, int size);
  61 static int      convertbinary(char *p, char *c, int size);
  62 static void     eventmodifier2string(au_emod_t emodifier, char *modstring,
  63     size_t modlen);
  64 static int      do_mtime32(pr_context_t *context, int status, int flag,
  65     uint32_t scale);
  66 static int      do_mtime64(pr_context_t *context, int status, int flag,
  67     uint64_t scale);
  68 
  69 /*
  70  * ------------------------------------------------------
  71  * field widths for arbitrary data token type
  72  * ------------------------------------------------------
  73  */
  74 static struct fw {
  75         char    basic_unit;
  76         struct {
  77                 char    print_base;
  78                 int     field_width;
  79         } pwidth[5];
  80 } fwidth[] = {
  81         /* character data type, 8 bits */
  82                 AUR_CHAR,       AUP_BINARY,     12,
  83                                 AUP_OCTAL,       6,
  84                                 AUP_DECIMAL,     6,
  85                                 AUP_HEX,         6,
  86                                 AUP_STRING,      1,
  87                 AUR_BYTE,       AUP_BINARY,     12,
  88                                 AUP_OCTAL,       6,
  89                                 AUP_DECIMAL,     6,
  90                                 AUP_HEX,         6,
  91                                 AUP_STRING,      1,
  92                 AUR_SHORT,      AUP_BINARY,     20,
  93                                 AUP_OCTAL,      10,
  94                                 AUP_DECIMAL,    10,
  95                                 AUP_HEX,         8,
  96                                 AUP_STRING,      6,
  97                 AUR_INT32,      AUP_BINARY,     36,
  98                                 AUP_OCTAL,      18,
  99                                 AUP_DECIMAL,    18,
 100                                 AUP_HEX,        12,
 101                                 AUP_STRING,     10,
 102                 AUR_INT64,      AUP_BINARY,     68,
 103                                 AUP_OCTAL,      34,
 104                                 AUP_DECIMAL,    34,
 105                                 AUP_HEX,        20,
 106                                 AUP_STRING,     20};
 107 
 108 
 109 static int      numwidthentries = sizeof (fwidth)
 110                         / sizeof (struct fw);
 111 
 112 
 113 /*
 114  * -----------------------------------------------------------------------
 115  * do_newline:
 116  *                Print a newline, if needed according to various formatting
 117  *                rules.
 118  * return codes :   0 - success
 119  *              :  -1 - error
 120  * -----------------------------------------------------------------------
 121  */
 122 int
 123 do_newline(pr_context_t *context, int flag)
 124 {
 125         int     retstat = 0;
 126 
 127         if (!(context->format & PRF_ONELINE) && (flag == 1))
 128                 retstat = pr_putchar(context, '\n');
 129         else if (!(context->format & PRF_XMLM))
 130                 retstat = pr_printf(context, "%s", context->SEPARATOR);
 131 
 132         return (retstat);
 133 }
 134 
 135 int
 136 open_tag(pr_context_t *context, int tagnum)
 137 {
 138         int             err = 0;
 139         token_desc_t    *tag;
 140 
 141         /* no-op if not doing XML format */
 142         if (!(context->format & PRF_XMLM))
 143                 return (0);
 144 
 145         tag = &tokentable[tagnum];
 146 
 147         /*
 148          * First if needed do an implicit finish of a pending open for an
 149          * extended tag.  I.e., for the extended tag xxx:
 150          *      <xxx a=".." b=".."> ...  </xxx>
 151          * -- insert a close bracket after the last attribute
 152          * (in other words, when the 1st non-attribute is opened while
 153          * this is pending). Note that only one tag could be pending at
 154          * a given time -- it couldn't be nested.
 155          */
 156         if (context->pending_flag && (tag->t_type != T_ATTRIBUTE)) {
 157                 /* complete pending extended open */
 158                 err = pr_putchar(context, '>');
 159                 if (err != 0)
 160                         return (err);
 161                 context->pending_flag = 0;
 162         }
 163 
 164         if (is_header_token(tagnum) || is_file_token(tagnum)) {
 165                 /* File token or new record on new line */
 166                 err = pr_putchar(context, '\n');
 167         } else if (is_token(tagnum)) {
 168                 /* Each token on new line if possible */
 169                 err = do_newline(context, 1);
 170         }
 171         if (err != 0)
 172                 return (err);
 173 
 174         switch (tag->t_type) {
 175         case T_ATTRIBUTE:
 176                 err = pr_printf(context, " %s=\"", tag->t_tagname);
 177                 break;
 178         case T_ELEMENT:
 179                 err = pr_printf(context, "<%s>", tag->t_tagname);
 180                 break;
 181         case T_ENCLOSED:
 182                 err = pr_printf(context, "<%s", tag->t_tagname);
 183                 break;
 184         case T_EXTENDED:
 185                 err = pr_printf(context, "<%s", tag->t_tagname);
 186                 if (err == 0)
 187                         context->pending_flag = tagnum;
 188                 break;
 189         default:
 190                 break;
 191         }
 192 
 193         if (is_header_token(tagnum) && (err == 0))
 194                 context->current_rec = tagnum;       /* set start of new record */
 195 
 196         return (err);
 197 }
 198 
 199 /*
 200  * Do an implicit close of a record when needed.
 201  */
 202 int
 203 check_close_rec(pr_context_t *context, int tagnum)
 204 {
 205         int     err = 0;
 206 
 207         /* no-op if not doing XML format */
 208         if (!(context->format & PRF_XMLM))
 209                 return (0);
 210 
 211         /*
 212          * If we're opening a header or the file token (i.e., starting a new
 213          * record), if there's a current record in progress do an implicit
 214          * close of it.
 215          */
 216         if ((is_header_token(tagnum) || is_file_token(tagnum)) &&
 217             context->current_rec) {
 218                 err = do_newline(context, 1);
 219                 if (err == 0)
 220                         err = close_tag(context, context->current_rec);
 221         }
 222 
 223         return (err);
 224 }
 225 
 226 /*
 227  * explicit finish of a pending open for an extended tag.
 228  */
 229 int
 230 finish_open_tag(pr_context_t *context)
 231 {
 232         int     err = 0;
 233 
 234         /* no-op if not doing XML format */
 235         if (!(context->format & PRF_XMLM))
 236                 return (0);
 237 
 238         if (context->pending_flag) {
 239                 /* complete pending extended open */
 240                 err = pr_putchar(context, '>');
 241                 if (err == 0)
 242                         context->pending_flag = 0;
 243         }
 244         return (err);
 245 }
 246 
 247 int
 248 close_tag(pr_context_t *context, int tagnum)
 249 {
 250         int             err = 0;
 251         token_desc_t    *tag;
 252 
 253         /* no-op if not doing XML format */
 254         if (!(context->format & PRF_XMLM))
 255                 return (0);
 256 
 257         tag = &tokentable[tagnum];
 258 
 259         switch (tag->t_type) {
 260         case T_ATTRIBUTE:
 261                 err = pr_putchar(context, '\"');
 262                 break;
 263         case T_ELEMENT:
 264                 err = pr_printf(context, "</%s>", tag->t_tagname);
 265                 break;
 266         case T_ENCLOSED:
 267                 err = pr_printf(context, "/>");
 268                 break;
 269         case T_EXTENDED:
 270                 err = pr_printf(context, "</%s>", tag->t_tagname);
 271                 break;
 272         default:
 273                 break;
 274         }
 275 
 276         if (is_header_token(tagnum) && (err == 0))
 277                 context->current_rec = 0;    /* closing rec; none current */
 278 
 279         return (err);
 280 }
 281 
 282 /*
 283  * -----------------------------------------------------------------------
 284  * process_tag:
 285  *                Calls the routine corresponding to the tag
 286  *                Note that to use this mechanism, all such routines must
 287  *                take 2 ints for their parameters; the first of these is
 288  *                the current status.
 289  *
 290  *                flag = 1 for newline / delimiter, else 0
 291  * return codes : -1 - error
 292  *              :  0 - successful
 293  * -----------------------------------------------------------------------
 294  */
 295 int
 296 process_tag(pr_context_t *context, int tagnum, int status, int flag)
 297 {
 298         int retstat;
 299 
 300         retstat = status;
 301 
 302         if (retstat)
 303                 return (retstat);
 304 
 305         if ((tagnum > 0) && (tagnum <= MAXTAG) &&
 306             (tokentable[tagnum].func != NOFUNC)) {
 307                 retstat = open_tag(context, tagnum);
 308                 if (!retstat)
 309                         retstat = (*tokentable[tagnum].func)(context, status,
 310                             flag);
 311                 if (!retstat)
 312                         retstat = close_tag(context, tagnum);
 313                 return (retstat);
 314         }
 315         /* here if token id is not in table */
 316         (void) fprintf(stderr, gettext("praudit: No code associated with "
 317             "tag id %d\n"), tagnum);
 318         return (0);
 319 }
 320 
 321 void
 322 get_Hname(uint32_t addr, char *buf, size_t buflen)
 323 {
 324         extern char     *inet_ntoa(const struct in_addr);
 325         struct hostent *phe;
 326         struct in_addr ia;
 327 
 328         phe = gethostbyaddr((const char *)&addr, 4, AF_INET);
 329         if (phe == (struct hostent *)0) {
 330                 ia.s_addr = addr;
 331                 (void) snprintf(buf, buflen, "%s", inet_ntoa(ia));
 332                 return;
 333         }
 334         ia.s_addr = addr;
 335         (void) snprintf(buf, buflen, "%s", phe->h_name);
 336 }
 337 
 338 void
 339 get_Hname_ex(uint32_t *addr, char *buf, size_t buflen)
 340 {
 341         struct hostent *phe;
 342         int err;
 343 
 344         phe = getipnodebyaddr((const void *)addr, 16, AF_INET6, &err);
 345 
 346         if (phe == (struct hostent *)0) {
 347                 (void) inet_ntop(AF_INET6, (void *)addr, buf, buflen);
 348         } else
 349                 (void) snprintf(buf, buflen, "%s", phe->h_name);
 350 
 351         if (phe)
 352                 freehostent(phe);
 353 }
 354 
 355 int
 356 pa_hostname(pr_context_t *context, int status, int flag)
 357 {
 358         int     returnstat;
 359         uint32_t        ip_addr;
 360         struct in_addr ia;
 361         uval_t uval;
 362         char    buf[256];
 363 
 364         if (status <  0)
 365                 return (status);
 366 
 367         if ((returnstat = pr_adr_char(context, (char *)&ip_addr, 4)) != 0)
 368                 return (returnstat);
 369 
 370         uval.uvaltype = PRA_STRING;
 371 
 372         if (!(context->format & PRF_RAWM)) {
 373                 uval.string_val = buf;
 374                 get_Hname(ip_addr, buf, sizeof (buf));
 375                 returnstat = pa_print(context, &uval, flag);
 376         } else {
 377                 ia.s_addr = ip_addr;
 378                 if ((uval.string_val = inet_ntoa(ia)) == NULL)
 379                         return (-1);
 380                 returnstat = pa_print(context, &uval, flag);
 381         }
 382         return (returnstat);
 383 }
 384 
 385 int
 386 pa_hostname_ex(pr_context_t *context, int status, int flag)
 387 {
 388         int     returnstat;
 389         uint32_t        ip_type;
 390         uint32_t        ip_addr[4];
 391         struct in_addr ia;
 392         char buf[256];
 393         uval_t uval;
 394 
 395         if (status <  0)
 396                 return (status);
 397 
 398         /* get ip type */
 399         if ((returnstat = pr_adr_int32(context, (int32_t *)&ip_type, 1)) != 0)
 400                 return (returnstat);
 401 
 402         /* only IPv4 and IPv6 addresses are legal */
 403         if ((ip_type != AU_IPv4) && (ip_type != AU_IPv6))
 404                 return (-1);
 405 
 406         /* get ip address */
 407         if ((returnstat = pr_adr_char(context, (char *)ip_addr, ip_type)) != 0)
 408                         return (returnstat);
 409 
 410         if ((returnstat = open_tag(context, TAG_HOSTID)) != 0)
 411                 return (returnstat);
 412 
 413         uval.uvaltype = PRA_STRING;
 414         if (ip_type == AU_IPv4) {               /* ipv4 address */
 415                 if (!(context->format & PRF_RAWM)) {
 416                         uval.string_val = buf;
 417                         get_Hname(ip_addr[0], buf, sizeof (buf));
 418                         returnstat = pa_print(context, &uval, flag);
 419                 } else {
 420                         ia.s_addr = ip_addr[0];
 421                         if ((uval.string_val = inet_ntoa(ia)) == NULL)
 422                                 return (-1);
 423                         returnstat = pa_print(context, &uval, flag);
 424                 }
 425         } else if (ip_type == AU_IPv6) {        /* IPv6 addresss (128 bits) */
 426                 if (!(context->format & PRF_RAWM)) {
 427                         uval.string_val = buf;
 428                         get_Hname_ex(ip_addr, buf, sizeof (buf));
 429                         returnstat = pa_print(context, &uval, flag);
 430                 } else {
 431                         uval.string_val = (char *)buf;
 432                         (void) inet_ntop(AF_INET6, (void *)ip_addr, buf,
 433                             sizeof (buf));
 434                         returnstat = pa_print(context, &uval, flag);
 435                 }
 436         }
 437 
 438         if (returnstat != 0)
 439                 return (returnstat);
 440         return (close_tag(context, TAG_HOSTID));
 441 }
 442 
 443 int
 444 pa_hostname_so(pr_context_t *context, int status, int flag)
 445 {
 446         int             returnstat;
 447         short           ip_type;
 448         ushort_t        ip_port;
 449         uint32_t        ip_addr[4];
 450         struct in_addr ia;
 451         char buf[256];
 452         uval_t uval;
 453 
 454         if (status <  0)
 455                 return (status);
 456 
 457         /* get ip type */
 458         if ((returnstat = pr_adr_short(context, &ip_type, 1)) != 0)
 459                 return (returnstat);
 460 
 461         /* only IPv4 and IPv6 addresses are legal */
 462         if ((ip_type != AU_IPv4) && (ip_type != AU_IPv6))
 463                 return (-1);
 464 
 465         /* get local ip port */
 466         if ((returnstat = pr_adr_u_short(context, &ip_port, 1)) != 0)
 467                 return (returnstat);
 468 
 469         if ((returnstat = open_tag(context, TAG_SOCKEXLPORT)) != 0)
 470                 return (returnstat);
 471 
 472         uval.uvaltype = PRA_STRING;
 473         uval.string_val = hexconvert((char *)&ip_port, sizeof (ip_port),
 474             sizeof (ip_port));
 475         if (uval.string_val) {
 476                 returnstat = pa_print(context, &uval, 0);
 477                 free(uval.string_val);
 478         } else
 479                 returnstat = -1;
 480         if (returnstat)
 481                 return (returnstat);
 482 
 483         if ((returnstat = close_tag(context, TAG_SOCKEXLPORT)) != 0)
 484                 return (returnstat);
 485 
 486         /* get local ip address */
 487         if ((returnstat = pr_adr_char(context, (char *)ip_addr, ip_type)) != 0)
 488                         return (returnstat);
 489 
 490         if ((returnstat = open_tag(context, TAG_SOCKEXLADDR)) != 0)
 491                 return (returnstat);
 492 
 493         if (ip_type == AU_IPv4) {               /* ipv4 address */
 494 
 495                 if (!(context->format & PRF_RAWM)) {
 496                         uval.string_val = buf;
 497                         get_Hname(ip_addr[0], buf, sizeof (buf));
 498                         returnstat = pa_print(context, &uval, 0);
 499                 } else {
 500                         ia.s_addr = ip_addr[0];
 501                         if ((uval.string_val = inet_ntoa(ia)) == NULL)
 502                                 return (-1);
 503                         returnstat = pa_print(context, &uval, 0);
 504                 }
 505 
 506         } else if (ip_type == AU_IPv6) {        /* IPv6 addresss (128 bits) */
 507 
 508                 if (!(context->format & PRF_RAWM)) {
 509                         uval.string_val = buf;
 510                         get_Hname_ex(ip_addr, buf, sizeof (buf));
 511                         returnstat = pa_print(context, &uval, 0);
 512                 } else {
 513                         uval.string_val = (char *)buf;
 514                         (void) inet_ntop(AF_INET6, (void *)ip_addr, buf,
 515                             sizeof (buf));
 516                         returnstat = pa_print(context, &uval, 0);
 517                 }
 518         } else
 519                 returnstat = -1;
 520 
 521         if (returnstat)
 522                 return (returnstat);
 523 
 524         if ((returnstat = close_tag(context, TAG_SOCKEXLADDR)) != 0)
 525                 return (returnstat);
 526 
 527         /* get foreign ip port */
 528         if ((returnstat = pr_adr_u_short(context, &ip_port, 1)) != 0)
 529                 return (returnstat);
 530 
 531         if ((returnstat = open_tag(context, TAG_SOCKEXFPORT)) != 0)
 532                 return (returnstat);
 533 
 534         uval.string_val = hexconvert((char *)&ip_port, sizeof (ip_port),
 535             sizeof (ip_port));
 536         if (uval.string_val) {
 537                 returnstat = pa_print(context, &uval, 0);
 538                 free(uval.string_val);
 539         } else
 540                 returnstat = -1;
 541 
 542         if (returnstat)
 543                 return (returnstat);
 544 
 545         if ((returnstat = close_tag(context, TAG_SOCKEXFPORT)) != 0)
 546                 return (returnstat);
 547 
 548         /* get foreign ip address */
 549         if ((returnstat = pr_adr_char(context, (char *)ip_addr, ip_type)) != 0)
 550                         return (returnstat);
 551 
 552         if ((returnstat = open_tag(context, TAG_SOCKEXFADDR)) != 0)
 553                 return (returnstat);
 554 
 555         if (ip_type == AU_IPv4) {               /* ipv4 address */
 556 
 557                 if (!(context->format & PRF_RAWM)) {
 558                         uval.string_val = buf;
 559                         get_Hname(ip_addr[0], buf, sizeof (buf));
 560                         returnstat = pa_print(context, &uval, flag);
 561                 } else {
 562                         ia.s_addr = ip_addr[0];
 563                         if ((uval.string_val = inet_ntoa(ia)) == NULL)
 564                                 return (-1);
 565                         returnstat = pa_print(context, &uval, flag);
 566                 }
 567 
 568         } else if (ip_type == AU_IPv6) {        /* IPv6 addresss (128 bits) */
 569 
 570                 if (!(context->format & PRF_RAWM)) {
 571                         uval.string_val = buf;
 572                         get_Hname_ex(ip_addr, buf, sizeof (buf));
 573                         returnstat = pa_print(context, &uval, flag);
 574                 } else {
 575                         uval.string_val = (char *)buf;
 576                         (void) inet_ntop(AF_INET6, (void *)ip_addr, buf,
 577                             sizeof (buf));
 578                         returnstat = pa_print(context, &uval, flag);
 579                 }
 580         } else
 581                 returnstat = -1;
 582 
 583         if (returnstat)
 584                 return (returnstat);
 585 
 586         if ((returnstat = close_tag(context, TAG_SOCKEXFADDR)) != 0)
 587                 return (returnstat);
 588 
 589         return (returnstat);
 590 }
 591 
 592 
 593 #define NBITSMAJOR64    32      /* # of major device bits in 64-bit Solaris */
 594 #define NBITSMINOR64    32      /* # of minor device bits in 64-bit Solaris */
 595 #define MAXMAJ64        0xfffffffful    /* max major value */
 596 #define MAXMIN64        0xfffffffful    /* max minor value */
 597 
 598 #define NBITSMAJOR32    14      /* # of SVR4 major device bits */
 599 #define NBITSMINOR32    18      /* # of SVR4 minor device bits */
 600 #define NMAXMAJ32       0x3fff  /* SVR4 max major value */
 601 #define NMAXMIN32       0x3ffff /* MAX minor for 3b2 software drivers. */
 602 
 603 
 604 static int32_t
 605 minor_64(uint64_t dev)
 606 {
 607         if (dev == NODEV) {
 608                 errno = EINVAL;
 609                 return (NODEV);
 610         }
 611         return (int32_t)(dev & MAXMIN64);
 612 }
 613 
 614 static int32_t
 615 major_64(uint64_t dev)
 616 {
 617         uint32_t maj;
 618 
 619         maj = (uint32_t)(dev >> NBITSMINOR64);
 620 
 621         if (dev == NODEV || maj > MAXMAJ64) {
 622                 errno = EINVAL;
 623                 return (NODEV);
 624         }
 625         return (int32_t)(maj);
 626 }
 627 
 628 static int32_t
 629 minor_32(uint32_t dev)
 630 {
 631         if (dev == NODEV) {
 632                 errno = EINVAL;
 633                 return (NODEV);
 634         }
 635         return (int32_t)(dev & MAXMIN32);
 636 }
 637 
 638 static int32_t
 639 major_32(uint32_t dev)
 640 {
 641         uint32_t maj;
 642 
 643         maj = (uint32_t)(dev >> NBITSMINOR32);
 644 
 645         if (dev == NODEV || maj > MAXMAJ32) {
 646                 errno = EINVAL;
 647                 return (NODEV);
 648         }
 649         return (int32_t)(maj);
 650 }
 651 
 652 
 653 /*
 654  * -----------------------------------------------------------------------
 655  * pa_tid()     : Process terminal id and display contents
 656  * return codes : -1 - error
 657  *              :  0 - successful
 658  *
 659  *      terminal id port                adr_int32
 660  *      terminal id machine             adr_int32
 661  * -----------------------------------------------------------------------
 662  */
 663 int
 664 pa_tid32(pr_context_t *context, int status, int flag)
 665 {
 666         int     returnstat;
 667         int32_t dev_maj_min;
 668         uint32_t        ip_addr;
 669         struct in_addr ia;
 670         char    *ipstring;
 671         char    buf[256];
 672         uval_t  uval;
 673 
 674         if (status <  0)
 675                 return (status);
 676 
 677         if ((returnstat = pr_adr_int32(context, &dev_maj_min, 1)) != 0)
 678                 return (returnstat);
 679 
 680         if ((returnstat = pr_adr_char(context, (char *)&ip_addr, 4)) != 0)
 681                 return (returnstat);
 682 
 683         uval.uvaltype = PRA_STRING;
 684         uval.string_val = buf;
 685 
 686         if (!(context->format & PRF_RAWM)) {
 687                 char    hostname[256];
 688 
 689                 get_Hname(ip_addr, hostname, sizeof (hostname));
 690                 (void) snprintf(buf, sizeof (buf), "%d %d %s",
 691                     major_32(dev_maj_min),
 692                     minor_32(dev_maj_min),
 693                     hostname);
 694                 return (pa_print(context, &uval, flag));
 695         }
 696 
 697         ia.s_addr = ip_addr;
 698         if ((ipstring = inet_ntoa(ia)) == NULL)
 699                 return (-1);
 700 
 701         (void) snprintf(buf, sizeof (buf), "%d %d %s", major_32(dev_maj_min),
 702             minor_32(dev_maj_min),
 703             ipstring);
 704 
 705         return (pa_print(context, &uval, flag));
 706 }
 707 
 708 int
 709 pa_tid32_ex(pr_context_t *context, int status, int flag)
 710 {
 711         int             returnstat;
 712         int32_t         dev_maj_min;
 713         uint32_t        ip_addr[16];
 714         uint32_t        ip_type;
 715         struct in_addr  ia;
 716         char            *ipstring;
 717         char            hostname[256];
 718         char            buf[256];
 719         char            tbuf[256];
 720         uval_t          uval;
 721 
 722         if (status <  0)
 723                 return (status);
 724 
 725         /* get port info */
 726         if ((returnstat = pr_adr_int32(context, &dev_maj_min, 1)) != 0)
 727                 return (returnstat);
 728 
 729         /* get address type */
 730         if ((returnstat = pr_adr_u_int32(context, &ip_type, 1)) != 0)
 731                 return (returnstat);
 732 
 733         /* legal address types are either AU_IPv4 or AU_IPv6 only */
 734         if ((ip_type != AU_IPv4) && (ip_type != AU_IPv6))
 735                 return (-1);
 736 
 737         /* get address (4/16) */
 738         if ((returnstat = pr_adr_char(context, (char *)ip_addr, ip_type)) != 0)
 739                 return (returnstat);
 740 
 741         uval.uvaltype = PRA_STRING;
 742         if (ip_type == AU_IPv4) {
 743                 uval.string_val = buf;
 744 
 745                 if (!(context->format & PRF_RAWM)) {
 746                         get_Hname(ip_addr[0], hostname, sizeof (hostname));
 747                         (void) snprintf(buf, sizeof (buf), "%d %d %s",
 748                             major_32(dev_maj_min), minor_32(dev_maj_min),
 749                             hostname);
 750                         return (pa_print(context, &uval, flag));
 751                 }
 752 
 753                 ia.s_addr = ip_addr[0];
 754                 if ((ipstring = inet_ntoa(ia)) == NULL)
 755                         return (-1);
 756 
 757                 (void) snprintf(buf, sizeof (buf), "%d %d %s",
 758                     major_32(dev_maj_min), minor_32(dev_maj_min), ipstring);
 759 
 760                 return (pa_print(context, &uval, flag));
 761         } else {
 762                 uval.string_val = buf;
 763 
 764                 if (!(context->format & PRF_RAWM)) {
 765                         get_Hname_ex(ip_addr, hostname, sizeof (hostname));
 766                         (void) snprintf(buf, sizeof (buf), "%d %d %s",
 767                             major_32(dev_maj_min), minor_32(dev_maj_min),
 768                             hostname);
 769                         return (pa_print(context, &uval, flag));
 770                 }
 771 
 772                 (void) inet_ntop(AF_INET6, (void *) ip_addr, tbuf,
 773                     sizeof (tbuf));
 774 
 775                 (void) snprintf(buf, sizeof (buf), "%d %d %s",
 776                     major_32(dev_maj_min), minor_32(dev_maj_min), tbuf);
 777 
 778                 return (pa_print(context, &uval, flag));
 779         }
 780 }
 781 
 782 int
 783 pa_ip_addr(pr_context_t *context, int status, int flag)
 784 {
 785         int             returnstat;
 786         uval_t          uval;
 787         uint32_t        ip_addr[4];
 788         uint32_t        ip_type;
 789         struct in_addr  ia;
 790         char            *ipstring;
 791         char            hostname[256];
 792         char            buf[256];
 793         char            tbuf[256];
 794 
 795         if (status <  0)
 796                 return (status);
 797 
 798         /* get address type */
 799         if ((returnstat = pr_adr_u_int32(context, &ip_type, 1)) != 0)
 800                 return (returnstat);
 801 
 802         /* legal address type is AU_IPv4 or AU_IPv6 */
 803         if ((ip_type != AU_IPv4) && (ip_type != AU_IPv6))
 804                 return (-1);
 805 
 806         /* get address (4/16) */
 807         if ((returnstat = pr_adr_char(context, (char *)ip_addr, ip_type)) != 0)
 808                 return (returnstat);
 809 
 810         uval.uvaltype = PRA_STRING;
 811         if (ip_type == AU_IPv4) {
 812                 uval.string_val = buf;
 813 
 814                 if (!(context->format & PRF_RAWM)) {
 815                         get_Hname(ip_addr[0], hostname, sizeof (hostname));
 816                         (void) snprintf(buf, sizeof (buf), "%s", hostname);
 817                         return (pa_print(context, &uval, flag));
 818                 }
 819 
 820                 ia.s_addr = ip_addr[0];
 821                 if ((ipstring = inet_ntoa(ia)) == NULL)
 822                         return (-1);
 823 
 824                 (void) snprintf(buf, sizeof (buf), "%s", ipstring);
 825 
 826                 return (pa_print(context, &uval, flag));
 827         } else {
 828                 uval.string_val = buf;
 829 
 830                 if (!(context->format & PRF_RAWM)) {
 831                         get_Hname_ex(ip_addr, hostname, sizeof (hostname));
 832                         (void) snprintf(buf, sizeof (buf), "%s",
 833                             hostname);
 834                         return (pa_print(context, &uval, flag));
 835                 }
 836 
 837                 (void) inet_ntop(AF_INET6, (void *) ip_addr, tbuf,
 838                     sizeof (tbuf));
 839 
 840                 (void) snprintf(buf, sizeof (buf), "%s", tbuf);
 841 
 842                 return (pa_print(context, &uval, flag));
 843         }
 844 
 845 }
 846 
 847 int
 848 pa_tid64(pr_context_t *context, int status, int flag)
 849 {
 850         int     returnstat;
 851         int64_t dev_maj_min;
 852         uint32_t        ip_addr;
 853         struct in_addr ia;
 854         char    *ipstring;
 855         char    buf[256];
 856         uval_t  uval;
 857 
 858         if (status <  0)
 859                 return (status);
 860 
 861         if ((returnstat = pr_adr_int64(context, &dev_maj_min, 1)) != 0)
 862                 return (returnstat);
 863 
 864         if ((returnstat = pr_adr_char(context, (char *)&ip_addr, 4)) != 0)
 865                 return (returnstat);
 866 
 867         uval.uvaltype = PRA_STRING;
 868         uval.string_val = buf;
 869 
 870         if (!(context->format & PRF_RAWM)) {
 871                 char    hostname[256];
 872 
 873                 get_Hname(ip_addr, hostname, sizeof (hostname));
 874                 (void) snprintf(buf, sizeof (buf), "%d %d %s",
 875                     major_64(dev_maj_min), minor_64(dev_maj_min), hostname);
 876                 return (pa_print(context, &uval, flag));
 877         }
 878 
 879         ia.s_addr = ip_addr;
 880         if ((ipstring = inet_ntoa(ia)) == NULL)
 881                 return (-1);
 882 
 883         (void) snprintf(buf, sizeof (buf), "%d %d %s",
 884             major_64(dev_maj_min), minor_64(dev_maj_min), ipstring);
 885 
 886         return (pa_print(context, &uval, flag));
 887 }
 888 
 889 int
 890 pa_tid64_ex(pr_context_t *context, int status, int flag)
 891 {
 892         int             returnstat;
 893         int64_t         dev_maj_min;
 894         uint32_t        ip_addr[4];
 895         uint32_t        ip_type;
 896         struct in_addr  ia;
 897         char            *ipstring;
 898         char            hostname[256];
 899         char            buf[256];
 900         char            tbuf[256];
 901         uval_t          uval;
 902 
 903         if (status <  0)
 904                 return (status);
 905 
 906         /* get port info */
 907         if ((returnstat = pr_adr_int64(context, &dev_maj_min, 1)) != 0)
 908                 return (returnstat);
 909 
 910         /* get address type */
 911         if ((returnstat = pr_adr_u_int32(context, &ip_type, 1)) != 0)
 912                 return (returnstat);
 913 
 914         /* legal address types are either AU_IPv4 or AU_IPv6 only */
 915         if ((ip_type != AU_IPv4) && (ip_type != AU_IPv6))
 916                 return (-1);
 917 
 918         /* get address (4/16) */
 919         if ((returnstat = pr_adr_char(context, (char *)&ip_addr, ip_type)) != 0)
 920                 return (returnstat);
 921 
 922         uval.uvaltype = PRA_STRING;
 923         if (ip_type == AU_IPv4) {
 924                 uval.string_val = buf;
 925 
 926                 if (!(context->format & PRF_RAWM)) {
 927                         get_Hname(ip_addr[0], hostname, sizeof (hostname));
 928                         uval.string_val = buf;
 929                         (void) snprintf(buf, sizeof (buf), "%d %d %s",
 930                             major_64(dev_maj_min), minor_64(dev_maj_min),
 931                             hostname);
 932                         return (pa_print(context, &uval, flag));
 933                 }
 934 
 935                 ia.s_addr = ip_addr[0];
 936                 if ((ipstring = inet_ntoa(ia)) == NULL)
 937                         return (-1);
 938 
 939                 (void) snprintf(buf, sizeof (buf), "%d %d %s",
 940                     major_64(dev_maj_min), minor_64(dev_maj_min), ipstring);
 941 
 942                 return (pa_print(context, &uval, flag));
 943         } else {
 944                 uval.string_val = buf;
 945 
 946                 if (!(context->format & PRF_RAWM)) {
 947                         get_Hname_ex(ip_addr, hostname, sizeof (hostname));
 948                         (void) snprintf(buf, sizeof (buf), "%d %d %s",
 949                             major_64(dev_maj_min), minor_64(dev_maj_min),
 950                             hostname);
 951                         return (pa_print(context, &uval, flag));
 952                 }
 953 
 954                 (void) inet_ntop(AF_INET6, (void *)ip_addr, tbuf,
 955                     sizeof (tbuf));
 956 
 957                 (void) snprintf(buf, sizeof (buf), "%d %d %s",
 958                     major_64(dev_maj_min), minor_64(dev_maj_min), tbuf);
 959 
 960                 return (pa_print(context, &uval, flag));
 961         }
 962 }
 963 
 964 
 965 /*
 966  * ----------------------------------------------------------------
 967  * findfieldwidth:
 968  * Returns the field width based on the basic unit and print mode.
 969  * This routine is called to determine the field width for the
 970  * data items in the arbitrary data token where the tokens are
 971  * to be printed in more than one line.  The field width can be
 972  * found in the fwidth structure.
 973  *
 974  * Input parameters:
 975  * basicunit    Can be one of AUR_CHAR, AUR_BYTE, AUR_SHORT,
 976  *              AUR_INT32, or AUR_INT64
 977  * howtoprint   Print mode. Can be one of AUP_BINARY, AUP_OCTAL,
 978  *              AUP_DECIMAL, or AUP_HEX.
 979  * ----------------------------------------------------------------
 980  */
 981 int
 982 findfieldwidth(char basicunit, char howtoprint)
 983 {
 984         int     i, j;
 985 
 986         for (i = 0; i < numwidthentries; i++) {
 987                 if (fwidth[i].basic_unit == basicunit) {
 988                         for (j = 0; j <= 4; j++) {
 989                                 if (fwidth[i].pwidth[j].print_base ==
 990                                     howtoprint) {
 991                                         return (
 992                                             fwidth[i].pwidth[j].field_width);
 993                                 }
 994                         }
 995                         /*
 996                          * if we got here, then we didn't get what we were after
 997                          */
 998                         return (0);
 999                 }
1000         }
1001         /* if we got here, we didn't get what we wanted either */
1002         return (0);
1003 }
1004 
1005 
1006 /*
1007  * -----------------------------------------------------------------------
1008  * pa_cmd: Retrieves the cmd item from the input stream.
1009  * return codes : -1 - error
1010  *              :  0 - successful
1011  * -----------------------------------------------------------------------
1012  */
1013 int
1014 pa_cmd(pr_context_t *context, int status, int flag)
1015 {
1016         char    *cmd;  /* cmd */
1017         short   length;
1018         int     returnstat;
1019         uval_t  uval;
1020 
1021         /*
1022          * We need to know how much space to allocate for our string, so
1023          * read the length first, then call pr_adr_char to read those bytes.
1024          */
1025         if (status >= 0) {
1026                 if (pr_adr_short(context, &length, 1) == 0) {
1027                         if ((cmd = (char *)malloc(length + 1)) == NULL)
1028                                 return (-1);
1029                         if (pr_adr_char(context, cmd, length) == 0) {
1030                                 uval.uvaltype = PRA_STRING;
1031                                 uval.string_val = cmd;
1032                                 returnstat = pa_print(context, &uval, flag);
1033                         } else {
1034                                 returnstat = -1;
1035                         }
1036                         free(cmd);
1037                         return (returnstat);
1038                 } else
1039                         return (-1);
1040         } else
1041                 return (status);
1042 }
1043 
1044 
1045 
1046 /*
1047  * -----------------------------------------------------------------------
1048  * pa_adr_byte  : Issues pr_adr_char to retrieve the next ADR item from
1049  *                the input stream pointed to by audit_adr, and prints it
1050  *                as an integer if status >= 0
1051  * return codes : -1 - error
1052  *              :  0 - successful
1053  * -----------------------------------------------------------------------
1054  */
1055 int
1056 pa_adr_byte(pr_context_t *context, int status, int flag)
1057 {
1058         char    c;
1059         uval_t  uval;
1060 
1061         if (status >= 0) {
1062                 if (pr_adr_char(context, &c, 1) == 0) {
1063                         uval.uvaltype = PRA_BYTE;
1064                         uval.char_val = c;
1065                         return (pa_print(context, &uval, flag));
1066                 } else
1067                         return (-1);
1068         } else
1069                 return (status);
1070 }
1071 
1072 /*
1073  * -----------------------------------------------------------------------
1074  * pa_adr_charhex: Issues pr_adr_char to retrieve the next ADR item from
1075  *                      the input stream pointed to by audit_adr, and prints it
1076  *                      in hexadecimal if status >= 0
1077  * return codes  : -1 - error
1078  *               :  0 - successful
1079  * -----------------------------------------------------------------------
1080  */
1081 int
1082 pa_adr_charhex(pr_context_t *context, int status, int flag)
1083 {
1084         char    p[2];
1085         int     returnstat;
1086         uval_t  uval;
1087 
1088         if (status >= 0) {
1089                 p[0] = p[1] = 0;
1090 
1091                 if ((returnstat = pr_adr_char(context, p, 1)) == 0) {
1092                         uval.uvaltype = PRA_STRING;
1093                         uval.string_val = hexconvert(p, sizeof (char),
1094                             sizeof (char));
1095                         if (uval.string_val) {
1096                                 returnstat = pa_print(context, &uval, flag);
1097                                 free(uval.string_val);
1098                         }
1099                 }
1100                 return (returnstat);
1101         } else
1102                 return (status);
1103 }
1104 
1105 /*
1106  * -----------------------------------------------------------------------
1107  * pa_adr_int32 : Issues pr_adr_int32 to retrieve the next ADR item from the
1108  *                input stream pointed to by audit_adr, and prints it
1109  *                if status >= 0
1110  * return codes : -1 - error
1111  *              :  0 - successful
1112  * -----------------------------------------------------------------------
1113  */
1114 int
1115 pa_adr_int32(pr_context_t *context, int status, int flag)
1116 {
1117         int32_t c;
1118         uval_t  uval;
1119 
1120         if (status >= 0) {
1121                 if (pr_adr_int32(context, &c, 1) == 0) {
1122                         uval.uvaltype = PRA_INT32;
1123                         uval.int32_val = c;
1124                         return (pa_print(context, &uval, flag));
1125                 } else
1126                         return (-1);
1127         } else
1128                 return (status);
1129 }
1130 
1131 
1132 
1133 
1134 /*
1135  * -----------------------------------------------------------------------
1136  * pa_adr_int64 : Issues pr_adr_int64 to retrieve the next ADR item from the
1137  *                input stream pointed to by audit_adr, and prints it
1138  *                if status >= 0
1139  * return codes : -1 - error
1140  *              :  0 - successful
1141  * -----------------------------------------------------------------------
1142  */
1143 int
1144 pa_adr_int64(pr_context_t *context, int status, int flag)
1145 {
1146         int64_t c;
1147         uval_t  uval;
1148 
1149         if (status >= 0) {
1150                 if (pr_adr_int64(context, &c, 1) == 0) {
1151                         uval.uvaltype = PRA_INT64;
1152                         uval.int64_val = c;
1153                         return (pa_print(context, &uval, flag));
1154                 } else
1155                         return (-1);
1156         } else
1157                 return (status);
1158 }
1159 
1160 /*
1161  * -----------------------------------------------------------------------
1162  * pa_adr_int64hex: Issues pr_adr_int64 to retrieve the next ADR item from the
1163  *                      input stream pointed to by audit_adr, and prints it
1164  *                      in hexadecimal if status >= 0
1165  * return codes  : -1 - error
1166  *              :  0 - successful
1167  * -----------------------------------------------------------------------
1168  */
1169 int
1170 pa_adr_int32hex(pr_context_t *context, int status, int flag)
1171 {
1172         int32_t l;
1173         int     returnstat;
1174         uval_t  uval;
1175 
1176         if (status >= 0) {
1177                 if ((returnstat = pr_adr_int32(context, &l, 1)) == 0) {
1178                         uval.uvaltype = PRA_HEX32;
1179                         uval.int32_val = l;
1180                         returnstat = pa_print(context, &uval, flag);
1181                 }
1182                 return (returnstat);
1183         } else
1184                 return (status);
1185 }
1186 
1187 /*
1188  * -----------------------------------------------------------------------
1189  * pa_adr_int64hex: Issues pr_adr_int64 to retrieve the next ADR item from the
1190  *                      input stream pointed to by audit_adr, and prints it
1191  *                      in hexadecimal if status >= 0
1192  * return codes  : -1 - error
1193  *              :  0 - successful
1194  * -----------------------------------------------------------------------
1195  */
1196 int
1197 pa_adr_int64hex(pr_context_t *context, int status, int flag)
1198 {
1199         int64_t l;
1200         int     returnstat;
1201         uval_t  uval;
1202 
1203         if (status >= 0) {
1204                 if ((returnstat = pr_adr_int64(context, &l, 1)) == 0) {
1205                         uval.uvaltype = PRA_HEX64;
1206                         uval.int64_val = l;
1207                         returnstat = pa_print(context, &uval, flag);
1208                 }
1209                 return (returnstat);
1210         } else
1211                 return (status);
1212 }
1213 
1214 
1215 /*
1216  * -------------------------------------------------------------------
1217  * bu2string: Maps a print basic unit type to a string.
1218  * returns  : The string mapping or "unknown basic unit type".
1219  * -------------------------------------------------------------------
1220  */
1221 char *
1222 bu2string(char basic_unit)
1223 {
1224         register int    i;
1225 
1226         struct bu_map_ent {
1227                 char    basic_unit;
1228                 char    *string;
1229         };
1230 
1231         /*
1232          * TRANSLATION_NOTE
1233          * These names are data units when displaying the arbitrary data
1234          * token.
1235          */
1236 
1237         static struct bu_map_ent bu_map[] = {
1238                                 { AUR_BYTE, "byte" },
1239                                 { AUR_CHAR, "char" },
1240                                 { AUR_SHORT, "short" },
1241                                 { AUR_INT32, "int32" },
1242                                 { AUR_INT64, "int64" }  };
1243 
1244         for (i = 0; i < sizeof (bu_map) / sizeof (struct bu_map_ent); i++)
1245                 if (basic_unit == bu_map[i].basic_unit)
1246                         return (gettext(bu_map[i].string));
1247 
1248         return (gettext("unknown basic unit type"));
1249 }
1250 
1251 
1252 /*
1253  * -------------------------------------------------------------------
1254  * eventmodifier2string: Maps event modifier flags to a readable string.
1255  * returns: The string mapping or "none".
1256  * -------------------------------------------------------------------
1257  */
1258 static void
1259 eventmodifier2string(au_emod_t emodifier, char *modstring, size_t modlen)
1260 {
1261         register int    i, j;
1262 
1263         struct em_map_ent {
1264                 int     mask;
1265                 char    *string;
1266         };
1267 
1268         /*
1269          * TRANSLATION_NOTE
1270          * These abbreviations represent the event modifier field of the
1271          * header token.  To gain a better understanding of each modifier,
1272          * read
1273          * System Administration Guide: Security Services >> Solaris Auditing
1274          * at http://docs.sun.com.
1275          */
1276 
1277         static struct em_map_ent em_map[] = {
1278                 { (int)PAD_READ,        "rd" }, /* data read from object */
1279                 { (int)PAD_WRITE,       "wr" }, /* data written to object */
1280                 { (int)PAD_SPRIVUSE,    "sp" }, /* successfully used priv */
1281                 { (int)PAD_FPRIVUSE,    "fp" }, /* failed use of priv */
1282                 { (int)PAD_NONATTR,     "na" }, /* non-attributable event */
1283                 { (int)PAD_FAILURE,     "fe" }  /* fail audit event */
1284         };
1285 
1286         modstring[0] = '\0';
1287 
1288         for (i = 0, j = 0; i < sizeof (em_map) / sizeof (struct em_map_ent);
1289             i++) {
1290                 if ((int)emodifier & em_map[i].mask) {
1291                         if (j++)
1292                                 (void) strlcat(modstring, ":", modlen);
1293                         (void) strlcat(modstring, em_map[i].string, modlen);
1294                 }
1295         }
1296 }
1297 
1298 
1299 /*
1300  * ---------------------------------------------------------
1301  * convert_char_to_string:
1302  *   Converts a byte to string depending on the print mode
1303  * input        : printmode, which may be one of AUP_BINARY,
1304  *                AUP_OCTAL, AUP_DECIMAL, and AUP_HEX
1305  *                c, which is the byte to convert
1306  * output       : p, which is a pointer to the location where
1307  *                the resulting string is to be stored
1308  *  ----------------------------------------------------------
1309  */
1310 
1311 int
1312 convert_char_to_string(char printmode, char c, char *p)
1313 {
1314         union {
1315                 char    c1[4];
1316                 int     c2;
1317         } dat;
1318 
1319         dat.c2 = 0;
1320         dat.c1[3] = c;
1321 
1322         if (printmode == AUP_BINARY)
1323                 (void) convertbinary(p, &c, sizeof (char));
1324         else if (printmode == AUP_OCTAL)
1325                 (void) sprintf(p, "%o", (int)dat.c2);
1326         else if (printmode == AUP_DECIMAL)
1327                 (void) sprintf(p, "%d", c);
1328         else if (printmode == AUP_HEX)
1329                 (void) sprintf(p, "0x%x", (int)dat.c2);
1330         else if (printmode == AUP_STRING)
1331                 convertascii(p, &c, sizeof (char));
1332         return (0);
1333 }
1334 
1335 /*
1336  * --------------------------------------------------------------
1337  * convert_short_to_string:
1338  * Converts a short integer to string depending on the print mode
1339  * input        : printmode, which may be one of AUP_BINARY,
1340  *              AUP_OCTAL, AUP_DECIMAL, and AUP_HEX
1341  *              c, which is the short integer to convert
1342  * output       : p, which is a pointer to the location where
1343  *              the resulting string is to be stored
1344  * ---------------------------------------------------------------
1345  */
1346 int
1347 convert_short_to_string(char printmode, short c, char *p)
1348 {
1349         union {
1350                 short   c1[2];
1351                 int     c2;
1352         } dat;
1353 
1354         dat.c2 = 0;
1355         dat.c1[1] = c;
1356 
1357         if (printmode == AUP_BINARY)
1358                 (void) convertbinary(p, (char *)&c, sizeof (short));
1359         else if (printmode == AUP_OCTAL)
1360                 (void) sprintf(p, "%o", (int)dat.c2);
1361         else if (printmode == AUP_DECIMAL)
1362                 (void) sprintf(p, "%hd", c);
1363         else if (printmode == AUP_HEX)
1364                 (void) sprintf(p, "0x%x", (int)dat.c2);
1365         else if (printmode == AUP_STRING)
1366                 convertascii(p, (char *)&c, sizeof (short));
1367         return (0);
1368 }
1369 
1370 /*
1371  * ---------------------------------------------------------
1372  * convert_int32_to_string:
1373  * Converts a integer to string depending on the print mode
1374  * input        : printmode, which may be one of AUP_BINARY,
1375  *              AUP_OCTAL, AUP_DECIMAL, and AUP_HEX
1376  *              c, which is the integer to convert
1377  * output       : p, which is a pointer to the location where
1378  *              the resulting string is to be stored
1379  * ----------------------------------------------------------
1380  */
1381 int
1382 convert_int32_to_string(char printmode, int32_t c, char *p)
1383 {
1384         if (printmode == AUP_BINARY)
1385                 (void) convertbinary(p, (char *)&c, sizeof (int32_t));
1386         else if (printmode == AUP_OCTAL)
1387                 (void) sprintf(p, "%o", c);
1388         else if (printmode == AUP_DECIMAL)
1389                 (void) sprintf(p, "%d", c);
1390         else if (printmode == AUP_HEX)
1391                 (void) sprintf(p, "0x%x", c);
1392         else if (printmode == AUP_STRING)
1393                 convertascii(p, (char *)&c, sizeof (int));
1394         return (0);
1395 }
1396 
1397 /*
1398  * ---------------------------------------------------------
1399  * convert_int64_to_string:
1400  * Converts a integer to string depending on the print mode
1401  * input        : printmode, which may be one of AUP_BINARY,
1402  *              AUP_OCTAL, AUP_DECIMAL, and AUP_HEX
1403  *              c, which is the integer to convert
1404  * output       : p, which is a pointer to the location where
1405  *              the resulting string is to be stored
1406  * ----------------------------------------------------------
1407  */
1408 int
1409 convert_int64_to_string(char printmode, int64_t c, char *p)
1410 {
1411         if (printmode == AUP_BINARY)
1412                 (void) convertbinary(p, (char *)&c, sizeof (int64_t));
1413         else if (printmode == AUP_OCTAL)
1414                 (void) sprintf(p, "%"PRIo64, c);
1415         else if (printmode == AUP_DECIMAL)
1416                 (void) sprintf(p, "%"PRId64, c);
1417         else if (printmode == AUP_HEX)
1418                 (void) sprintf(p, "0x%"PRIx64, c);
1419         else if (printmode == AUP_STRING)
1420                 convertascii(p, (char *)&c, sizeof (int64_t));
1421         return (0);
1422 }
1423 
1424 
1425 /*
1426  * -----------------------------------------------------------
1427  * convertbinary:
1428  * Converts a unit c of 'size' bytes long into a binary string
1429  * and returns it into the position pointed to by p
1430  * ------------------------------------------------------------
1431  */
1432 int
1433 convertbinary(char *p, char *c, int size)
1434 {
1435         char    *s, *t, *ss;
1436         int     i, j;
1437 
1438         if ((s = (char *)malloc(8 * size + 1)) == NULL)
1439                 return (0);
1440 
1441         ss = s;
1442 
1443         /* first convert to binary */
1444         t = s;
1445         for (i = 0; i < size; i++) {
1446                 for (j = 0; j < 8; j++)
1447                         (void) sprintf(t++, "%d", ((*c >> (7 - j)) & (0x01)));
1448                 c++;
1449         }
1450         *t = '\0';
1451 
1452         /* now string leading zero's if any */
1453         j = strlen(s) - 1;
1454         for (i = 0; i < j; i++) {
1455                 if (*s != '0')
1456                         break;
1457                         else
1458                         s++;
1459         }
1460 
1461         /* now copy the contents of s to p */
1462         t = p;
1463         for (i = 0; i < (8 * size + 1); i++) {
1464                 if (*s == '\0') {
1465                         *t = '\0';
1466                         break;
1467                 }
1468                 *t++ = *s++;
1469         }
1470         free(ss);
1471 
1472         return (1);
1473 }
1474 
1475 
1476 static char hex[] = "0123456789abcdef";
1477 /*
1478  * -------------------------------------------------------------------
1479  * hexconvert   : Converts a string of (size) bytes to hexadecimal, and
1480  *              returns the hexadecimal string.
1481  * returns      : - NULL if memory cannot be allocated for the string, or
1482  *              - pointer to the hexadecimal string if successful
1483  * -------------------------------------------------------------------
1484  */
1485 char *
1486 hexconvert(char *c, int size, int chunk)
1487 {
1488         register char   *s, *t;
1489         register int    i, j, k;
1490         int     numchunks;
1491         int     leftovers;
1492 
1493         if (size <= 0)
1494                 return (NULL);
1495 
1496         if ((s = (char *)malloc((size * 5) + 1)) == NULL)
1497                 return (NULL);
1498 
1499         if (chunk > size || chunk <= 0)
1500                 chunk = size;
1501 
1502         numchunks = size / chunk;
1503         leftovers = size % chunk;
1504 
1505         t = s;
1506         for (i = j = 0; i < numchunks; i++) {
1507                 if (j++) {
1508                         *t++ = ' ';
1509                 }
1510                 *t++ = '0';
1511                 *t++ = 'x';
1512                 for (k = 0; k < chunk; k++) {
1513                         *t++ = hex[(uint_t)((uchar_t)*c >> 4)];
1514                         *t++ = hex[(uint_t)((uchar_t)*c & 0xF)];
1515                         c++;
1516                 }
1517         }
1518 
1519         if (leftovers) {
1520                 *t++ = ' ';
1521                 *t++ = '0';
1522                 *t++ = 'x';
1523                 for (i = 0; i < leftovers; i++) {
1524                         *t++ = hex[(uint_t)((uchar_t)*c >> 4)];
1525                         *t++ = hex[(uint_t)((uchar_t)*c & 0xF)];
1526                         c++;
1527                 }
1528         }
1529 
1530         *t = '\0';
1531         return (s);
1532 }
1533 
1534 
1535 /*
1536  * -------------------------------------------------------------------
1537  * htp2string: Maps a print suggestion to a string.
1538  * returns   : The string mapping or "unknown print suggestion".
1539  * -------------------------------------------------------------------
1540  */
1541 char *
1542 htp2string(char print_sugg)
1543 {
1544         register int    i;
1545 
1546         struct htp_map_ent {
1547                 char    print_sugg;
1548                 char    *print_string;
1549         };
1550 
1551         /*
1552          * TRANSLATION_NOTE
1553          * These names are data types when displaying the arbitrary data
1554          * token.
1555          */
1556 
1557         static struct htp_map_ent htp_map[] = {
1558                                 { AUP_BINARY, "binary" },
1559                                 { AUP_OCTAL, "octal" },
1560                                 { AUP_DECIMAL, "decimal" },
1561                                 { AUP_HEX, "hexadecimal" },
1562                                 { AUP_STRING, "string" }        };
1563 
1564         for (i = 0; i < sizeof (htp_map) / sizeof (struct htp_map_ent); i++)
1565                 if (print_sugg == htp_map[i].print_sugg)
1566                         return (gettext(htp_map[i].print_string));
1567 
1568         return (gettext("unknown print suggestion"));
1569 }
1570 
1571 /*
1572  * ----------------------------------------------------------------------
1573  * pa_adr_short: Issues pr_adr_short to retrieve the next ADR item from the
1574  *              input stream pointed to by audit_adr, and prints it
1575  *              if status >= 0
1576  * return codes: -1 - error
1577  *              :  0 - successful
1578  * ----------------------------------------------------------------------
1579  */
1580 int
1581 pa_adr_short(pr_context_t *context, int status, int flag)
1582 {
1583         short   c;
1584         uval_t  uval;
1585 
1586         if (status >= 0) {
1587                 if (pr_adr_short(context, &c, 1) == 0) {
1588                         uval.uvaltype = PRA_SHORT;
1589                         uval.short_val = c;
1590                         return (pa_print(context, &uval, flag));
1591                 } else
1592                         return (-1);
1593         } else
1594                 return (status);
1595 }
1596 
1597 /*
1598  * -----------------------------------------------------------------------
1599  * pa_adr_shorthex: Issues pr_adr_short to retrieve the next ADR item from the
1600  *                      input stream pointed to by audit_adr, and prints it
1601  *                      in hexadecimal if status >= 0
1602  * return codes  : -1 - error
1603  *              :  0 - successful
1604  * -----------------------------------------------------------------------
1605  */
1606 int
1607 pa_adr_shorthex(pr_context_t *context, int status, int flag)
1608 {
1609         short   s;
1610         int     returnstat;
1611         uval_t  uval;
1612 
1613         if (status >= 0) {
1614                 if ((returnstat = pr_adr_short(context, &s, 1)) == 0) {
1615                         uval.uvaltype = PRA_STRING;
1616                         uval.string_val = hexconvert((char *)&s, sizeof (s),
1617                             sizeof (s));
1618                         if (uval.string_val) {
1619                                 returnstat = pa_print(context, &uval, flag);
1620                                 free(uval.string_val);
1621                         }
1622                 }
1623                 return (returnstat);
1624         } else
1625                 return (status);
1626 }
1627 
1628 
1629 /*
1630  * -----------------------------------------------------------------------
1631  * pa_adr_string: Retrieves a string from the input stream and prints it
1632  *                if status >= 0
1633  * return codes : -1 - error
1634  *              :  0 - successful
1635  * -----------------------------------------------------------------------
1636  */
1637 int
1638 pa_adr_string(pr_context_t *context, int status, int flag)
1639 {
1640         char    *c;
1641         short   length;
1642         int     returnstat;
1643         uval_t  uval;
1644 
1645         /*
1646          * We need to know how much space to allocate for our string, so
1647          * read the length first, then call pr_adr_char to read those bytes.
1648          */
1649         if (status < 0)
1650                 return (status);
1651 
1652         if ((returnstat = pr_adr_short(context, &length, 1)) != 0)
1653                 return (returnstat);
1654         if ((c = (char *)malloc(length + 1)) == NULL)
1655                 return (-1);
1656         if ((returnstat = pr_adr_char(context, c, length)) != 0) {
1657                 free(c);
1658                 return (returnstat);
1659         }
1660 
1661         uval.uvaltype = PRA_STRING;
1662         uval.string_val = c;
1663         returnstat = pa_print(context, &uval, flag);
1664         free(c);
1665         return (returnstat);
1666 }
1667 
1668 /*
1669  * -----------------------------------------------------------------------
1670  * pa_file_string: Retrieves a file string from the input stream and prints it
1671  *                if status >= 0
1672  * return codes : -1 - error
1673  *              :  0 - successful
1674  * -----------------------------------------------------------------------
1675  */
1676 int
1677 pa_file_string(pr_context_t *context, int status, int flag)
1678 {
1679         char    *c;
1680         char    *p;
1681         short   length;
1682         int     returnstat;
1683         uval_t  uval;
1684 
1685         /*
1686          * We need to know how much space to allocate for our string, so
1687          * read the length first, then call pr_adr_char to read those bytes.
1688          */
1689         if (status < 0)
1690                 return (status);
1691 
1692         if ((returnstat = pr_adr_short(context, &length, 1)) != 0)
1693                 return (returnstat);
1694         if ((c = (char *)malloc(length + 1)) == NULL)
1695                 return (-1);
1696         if ((p = (char *)malloc((length * 4) + 1)) == NULL) {
1697                 free(c);
1698                 return (-1);
1699         }
1700         if ((returnstat = pr_adr_char(context, c, length)) != 0) {
1701                 free(c);
1702                 free(p);
1703                 return (returnstat);
1704         }
1705 
1706         if (is_file_token(context->tokenid))
1707                 context->audit_rec_len += length;
1708 
1709         convertascii(p, c, length - 1);
1710         uval.uvaltype = PRA_STRING;
1711         uval.string_val = p;
1712 
1713         if (returnstat == 0)
1714                 returnstat = finish_open_tag(context);
1715 
1716         if (returnstat == 0)
1717                 returnstat = pa_print(context, &uval, flag);
1718 
1719         free(c);
1720         free(p);
1721         return (returnstat);
1722 }
1723 
1724 static int
1725 pa_putstr_xml(pr_context_t *context, int printable, char *str, size_t len)
1726 {
1727         int     err;
1728 
1729         if (!printable) {
1730                 /*
1731                  * Unprintable chars should always be converted to the
1732                  * visible form. If there are unprintable characters which
1733                  * require special treatment in xml, those should be
1734                  * handled here.
1735                  */
1736                 do {
1737                         err = pr_printf(context, "\\%03o",
1738                             (unsigned char)*str++);
1739                 } while (err == 0 && --len != 0);
1740                 return (err);
1741         }
1742         /* printable characters */
1743         if (len == 1) {
1744                 /*
1745                  * check for the special chars only when char size was 1
1746                  * ie, ignore special chars appear in the middle of multibyte
1747                  * sequence.
1748                  */
1749 
1750                 /* Escape for XML */
1751                 switch (*str) {
1752                 case '&':
1753                         err = pr_printf(context, "%s", "&");
1754                         break;
1755 
1756                 case '<':
1757                         err = pr_printf(context, "%s", "<");
1758                         break;
1759 
1760                 case '>':
1761                         err = pr_printf(context, "%s", ">");
1762                         break;
1763 
1764                 case '\"':
1765                         err = pr_printf(context, "%s", """);
1766                         break;
1767 
1768                 case '\'':
1769                         err = pr_printf(context, "%s", "'");
1770                         break;
1771 
1772                 default:
1773                         err = pr_putchar(context, *str);
1774                         break;
1775                 }
1776                 return (err);
1777         }
1778         do {
1779                 err = pr_putchar(context, *str++);
1780         } while (err == 0 && --len != 0);
1781         return (err);
1782 }
1783 
1784 static int
1785 pa_putstr(pr_context_t *context, int printable, char *str, size_t len)
1786 {
1787         int     err;
1788 
1789         if (context->format & PRF_XMLM)
1790                 return (pa_putstr_xml(context, printable, str, len));
1791 
1792         if (!printable) {
1793                 do {
1794                         err = pr_printf(context, "\\%03o",
1795                             (unsigned char)*str++);
1796                 } while (err == 0 && --len != 0);
1797                 return (err);
1798         }
1799         do {
1800                 err = pr_putchar(context, *str++);
1801         } while (err == 0 && --len != 0);
1802         return (err);
1803 }
1804 
1805 int
1806 pa_string(pr_context_t *context, int status, int flag)
1807 {
1808         int     rstat, wstat;
1809         int     i, printable, eos;
1810         int     mlen, rlen;
1811         int     mbmax = MB_CUR_MAX;
1812         wchar_t wc;
1813         char    mbuf[MB_LEN_MAX + 1];
1814         char    c;
1815 
1816         if (status < 0)
1817                 return (status);
1818 
1819         rstat = wstat = 0;
1820 
1821         if (mbmax == 1) {
1822                 while (wstat == 0) {
1823                         if ((rstat = pr_adr_char(context, &c, 1)) < 0)
1824                                 break;
1825                         if (c == '\0')
1826                                 break;
1827                         printable = isprint((unsigned char)c);
1828                         wstat = pa_putstr(context, printable, &c, 1);
1829                 }
1830                 goto done;
1831         }
1832 
1833         mlen = eos = 0;
1834         while (wstat == 0) {
1835                 rlen = 0;
1836                 do {
1837                         if (!eos) {
1838                                 rstat = pr_adr_char(context, &c, 1);
1839                                 if (rstat != 0 || c == '\0')
1840                                         eos = 1;
1841                                 else
1842                                         mbuf[mlen++] = c;
1843                         }
1844                         rlen = mbtowc(&wc, mbuf, mlen);
1845                 } while (!eos && mlen < mbmax && rlen <= 0);
1846 
1847                 if (mlen == 0)
1848                         break;  /* end of string */
1849 
1850                 if (rlen <= 0) { /* no good sequence */
1851                         rlen = 1;
1852                         printable = 0;
1853                 } else {
1854                         printable = iswprint(wc);
1855                 }
1856                 wstat = pa_putstr(context, printable, mbuf, rlen);
1857                 mlen -= rlen;
1858                 if (mlen > 0) {
1859                         for (i = 0; i < mlen; i++)
1860                                 mbuf[i] = mbuf[rlen + i];
1861                 }
1862         }
1863 
1864 done:
1865         if (wstat == 0)
1866                 wstat = do_newline(context, flag);
1867 
1868         if (wstat == 0 && context->data_mode == FILEMODE)
1869                 (void) fflush(stdout);
1870 
1871         return ((rstat != 0 || wstat != 0) ? -1 : 0);
1872 }
1873 
1874 /*
1875  * -----------------------------------------------------------------------
1876  * pa_adr_u_int32: Issues pr_adr_u_int32 to retrieve the next ADR item from
1877  *                the input stream pointed to by audit_adr, and prints it
1878  *                if status = 0
1879  * return codes : -1 - error
1880  *              :  0 - successful
1881  * -----------------------------------------------------------------------
1882  */
1883 
1884 
1885 int
1886 pa_adr_u_int32(pr_context_t *context, int status, int flag)
1887 {
1888         uint32_t c;
1889         uval_t  uval;
1890 
1891         if (status >= 0) {
1892                 if (pr_adr_u_int32(context, &c, 1) == 0) {
1893                         uval.uvaltype = PRA_UINT32;
1894                         uval.uint32_val = c;
1895                         return (pa_print(context, &uval, flag));
1896                 } else
1897                         return (-1);
1898         } else
1899                 return (status);
1900 }
1901 
1902 
1903 
1904 /*
1905  * -----------------------------------------------------------------------
1906  * pa_adr_u_int64: Issues pr_adr_u_int64 to retrieve the next ADR item from the
1907  *                input stream pointed to by audit_adr, and prints it
1908  *                if status = 0
1909  * return codes : -1 - error
1910  *              :  0 - successful
1911  * -----------------------------------------------------------------------
1912  */
1913 int
1914 pa_adr_u_int64(pr_context_t *context, int status, int flag)
1915 {
1916         uint64_t c;
1917         uval_t  uval;
1918 
1919         if (status >= 0) {
1920                 if (pr_adr_u_int64(context, &c, 1) == 0) {
1921                         uval.uvaltype = PRA_UINT64;
1922                         uval.uint64_val = c;
1923                         return (pa_print(context, &uval, flag));
1924                 } else
1925                         return (-1);
1926         } else
1927                 return (status);
1928 }
1929 
1930 
1931 /*
1932  * -----------------------------------------------------------------------
1933  * pa_adr_u_short: Issues pr_adr_u_short to retrieve the next ADR item from
1934  *                      the input stream pointed to by audit_adr, and prints it
1935  *                      if status = 0
1936  * return codes : -1 - error
1937  *              :  0 - successful
1938  * -----------------------------------------------------------------------
1939  */
1940 int
1941 pa_adr_u_short(pr_context_t *context, int status, int flag)
1942 {
1943         ushort_t c;
1944         uval_t  uval;
1945 
1946         if (status >= 0) {
1947                 if (pr_adr_u_short(context, &c, 1) == 0) {
1948                         uval.uvaltype = PRA_USHORT;
1949                         uval.ushort_val = c;
1950                         return (pa_print(context, &uval, flag));
1951                 } else
1952                         return (-1);
1953         } else
1954                 return (status);
1955 }
1956 
1957 /*
1958  * -----------------------------------------------------------------------
1959  * pa_reclen: Issues pr_adr_u_long to retrieve the length of the record
1960  *                from the input stream pointed to by audit_adr,
1961  *                and prints it (unless format is XML) if status = 0
1962  * return codes : -1 - error
1963  *              :  0 - successful
1964  * -----------------------------------------------------------------------
1965  */
1966 int
1967 pa_reclen(pr_context_t *context, int status)
1968 {
1969         uint32_t c;
1970         uval_t  uval;
1971 
1972         if (status >= 0) {
1973                 if ((int)pr_adr_u_int32(context, &c, 1) == 0) {
1974                         context->audit_rec_len = c;
1975 
1976                         /* Don't print this for XML format */
1977                         if (context->format & PRF_XMLM) {
1978                                 return (0);
1979                         } else {
1980                                 uval.uvaltype = PRA_UINT32;
1981                                 uval.uint32_val = c;
1982                                 return (pa_print(context, &uval, 0));
1983                         }
1984                 } else
1985                         return (-1);
1986         } else
1987                 return (status);
1988 }
1989 
1990 /*
1991  * -----------------------------------------------------------------------
1992  * pa_mode      : Issues pr_adr_u_short to retrieve the next ADR item from
1993  *              the input stream pointed to by audit_adr, and prints it
1994  *              in octal if status = 0
1995  * return codes : -1 - error
1996  *              :  0 - successful
1997  * -----------------------------------------------------------------------
1998  */
1999 int
2000 pa_mode(pr_context_t *context, int status, int flag)
2001 {
2002         uint32_t c;
2003         uval_t  uval;
2004 
2005         if (status >= 0) {
2006                 if (pr_adr_u_int32(context, &c, 1) == 0) {
2007                         uval.uvaltype = PRA_LOCT;
2008                         uval.uint32_val = c;
2009                         return (pa_print(context, &uval, flag));
2010                 } else
2011                         return (-1);
2012         } else
2013                 return (status);
2014 }
2015 
2016 static int
2017 pa_print_uid(pr_context_t *context, uid_t uid, int status, int flag)
2018 {
2019         int     returnstat;
2020         struct passwd *pw;
2021         uval_t  uval;
2022 
2023         if (status < 0)
2024                 return (status);
2025 
2026         if (!(context->format & PRF_RAWM)) {
2027                 /* get password file entry */
2028                 if ((pw = getpwuid(uid)) == NULL) {
2029                         returnstat = 1;
2030                 } else {
2031                         /* print in ASCII form */
2032                         uval.uvaltype = PRA_STRING;
2033                         uval.string_val = pw->pw_name;
2034                         returnstat = pa_print(context, &uval, flag);
2035                 }
2036         }
2037         /* print in integer form */
2038         if ((context->format & PRF_RAWM) || (returnstat == 1)) {
2039                 uval.uvaltype = PRA_INT32;
2040                 uval.int32_val = uid;
2041                 returnstat = pa_print(context, &uval, flag);
2042         }
2043         return (returnstat);
2044 }
2045 
2046 
2047 /*
2048  * -----------------------------------------------------------------------
2049  * pa_pw_uid()  : Issues pr_adr_u_int32 to reads uid from input stream
2050  *              pointed to by audit_adr, and displays it in either
2051  *              raw form or its ASCII representation, if status >= 0.
2052  * return codes : -1 - error
2053  *              :  1 - warning, passwd entry not found
2054  *              :  0 - successful
2055  * -----------------------------------------------------------------------
2056  */
2057 int
2058 pa_pw_uid(pr_context_t *context, int status, int flag)
2059 {
2060         uint32_t uid;
2061 
2062         if (status < 0)
2063                 return (status);
2064 
2065         if (pr_adr_u_int32(context, &uid, 1) != 0)
2066                 /* cannot retrieve uid */
2067                 return (-1);
2068 
2069         return (pa_print_uid(context, uid, status, flag));
2070 }
2071 
2072 static int
2073 pa_print_gid(pr_context_t *context, gid_t gid, int status, int flag)
2074 {
2075         int     returnstat;
2076         struct group *gr;
2077         uval_t  uval;
2078 
2079         if (status < 0)
2080                 return (status);
2081 
2082         if (!(context->format & PRF_RAWM)) {
2083                 /* get group file entry */
2084                 if ((gr = getgrgid(gid)) == NULL) {
2085                         returnstat = 1;
2086                 } else {
2087                         /* print in ASCII form */
2088                         uval.uvaltype = PRA_STRING;
2089                         uval.string_val = gr->gr_name;
2090                         returnstat = pa_print(context, &uval, flag);
2091                 }
2092         }
2093         /* print in integer form */
2094         if ((context->format & PRF_RAWM) || (returnstat == 1)) {
2095                 uval.uvaltype = PRA_INT32;
2096                 uval.int32_val = gid;
2097                 returnstat = pa_print(context, &uval, flag);
2098         }
2099         return (returnstat);
2100 }
2101 
2102 
2103 /*
2104  * -----------------------------------------------------------------------
2105  * pa_gr_uid()  : Issues pr_adr_u_int32 to reads group uid from input stream
2106  *                      pointed to by audit_adr, and displays it in either
2107  *                      raw form or its ASCII representation, if status >= 0.
2108  * return codes : -1 - error
2109  *              :  1 - warning, passwd entry not found
2110  *              :  0 - successful
2111  * -----------------------------------------------------------------------
2112  */
2113 int
2114 pa_gr_uid(pr_context_t *context, int status, int flag)
2115 {
2116         uint32_t gid;
2117 
2118         if (status < 0)
2119                 return (status);
2120 
2121         if (pr_adr_u_int32(context, &gid, 1) != 0)
2122                 /* cannot retrieve gid */
2123                 return (-1);
2124 
2125         return (pa_print_gid(context, gid, status, flag));
2126 }
2127 
2128 
2129 /*
2130  * -----------------------------------------------------------------------
2131  * pa_pw_uid_gr_gid()   : Issues pr_adr_u_int32 to reads uid or group uid
2132  *                      from input stream
2133  *                      pointed to by audit_adr, and displays it in either
2134  *                      raw form or its ASCII representation, if status >= 0.
2135  * return codes : -1 - error
2136  *              :  1 - warning, passwd entry not found
2137  *              :  0 - successful
2138  * -----------------------------------------------------------------------
2139  */
2140 int
2141 pa_pw_uid_gr_gid(pr_context_t *context, int status, int flag)
2142 {
2143         int     returnstat;
2144         uint32_t        value;
2145         uval_t          uval;
2146 
2147         if (status < 0)
2148                 return (status);
2149 
2150         /* get value of a_type */
2151         if ((returnstat = pr_adr_u_int32(context, &value, 1)) != 0)
2152                 return (returnstat);
2153 
2154         if ((returnstat = open_tag(context, TAG_ACLTYPE)) != 0)
2155                 return (returnstat);
2156 
2157         uval.uvaltype = PRA_UINT32;
2158         uval.uint32_val = value;
2159         if ((returnstat = pa_print(context, &uval, flag)) != 0)
2160                 return (returnstat);
2161 
2162         if ((returnstat = close_tag(context, TAG_ACLTYPE)) != 0)
2163                 return (returnstat);
2164 
2165         if ((returnstat = open_tag(context, TAG_ACLVAL)) != 0)
2166                 return (returnstat);
2167         /*
2168          * TRANSLATION_NOTE
2169          * The "mask" and "other" strings refer to the class mask
2170          * and other (or world) entries in an ACL.
2171          * The "unrecognized" string refers to an unrecognized ACL
2172          * entry.
2173          */
2174         switch (value) {
2175                 case USER_OBJ:
2176                 case USER:
2177                         returnstat = pa_pw_uid(context, returnstat, flag);
2178                         break;
2179                 case GROUP_OBJ:
2180                 case GROUP:
2181                         returnstat = pa_gr_uid(context, returnstat, flag);
2182                         break;
2183                 case CLASS_OBJ:
2184                         returnstat = pr_adr_u_int32(context, &value, 1);
2185                         if (returnstat != 0)
2186                                 return (returnstat);
2187 
2188                         if (!(context->format & PRF_RAWM)) {
2189                                 uval.uvaltype = PRA_STRING;
2190                                 uval.string_val = gettext("mask");
2191                                 returnstat = pa_print(context, &uval, flag);
2192                         } else {
2193                                 uval.uvaltype = PRA_UINT32;
2194                                 uval.uint32_val = value;
2195                                 if ((returnstat =
2196                                     pa_print(context, &uval, flag)) != 0) {
2197                                         return (returnstat);
2198                                 }
2199                         }
2200                         break;
2201                 case OTHER_OBJ:
2202                         returnstat = pr_adr_u_int32(context, &value, 1);
2203                         if (returnstat != 0)
2204                                 return (returnstat);
2205 
2206                         if (!(context->format & PRF_RAWM)) {
2207                                 uval.uvaltype = PRA_STRING;
2208                                 uval.string_val = gettext("other");
2209                                 returnstat = pa_print(context, &uval, flag);
2210                         } else {
2211                                 uval.uvaltype = PRA_UINT32;
2212                                 uval.uint32_val = value;
2213                                 if ((returnstat =
2214                                     pa_print(context, &uval, flag)) != 0) {
2215                                         return (returnstat);
2216                                 }
2217                         }
2218                         break;
2219                 default:
2220                         returnstat = pr_adr_u_int32(context, &value, 1);
2221                         if (returnstat != 0)
2222                                 return (returnstat);
2223 
2224                         if (!(context->format & PRF_RAWM)) {
2225                                 uval.uvaltype = PRA_STRING;
2226                                 uval.string_val = gettext("unrecognized");
2227                                 returnstat = pa_print(context, &uval, flag);
2228                         } else {
2229                                 uval.uvaltype = PRA_UINT32;
2230                                 uval.uint32_val = value;
2231                                 if ((returnstat =
2232                                     pa_print(context, &uval, flag)) != 0) {
2233                                         return (returnstat);
2234                                 }
2235                         }
2236         }
2237 
2238         if ((returnstat = close_tag(context, TAG_ACLVAL)) != 0)
2239                 return (returnstat);
2240 
2241         return (returnstat);
2242 }
2243 
2244 
2245 /*
2246  * -----------------------------------------------------------------------
2247  * pa_event_modifier(): Issues pr_adr_u_short to retrieve the next ADR item from
2248  *                the input stream pointed to by audit_adr.  This is the
2249  *                event type, and is displayed in hex;
2250  * return codes : -1 - error
2251  *              :  0 - successful
2252  * -----------------------------------------------------------------------
2253  */
2254 int
2255 pa_event_modifier(pr_context_t *context, int status,  int flag)
2256 {
2257         int     returnstat;
2258         au_emod_t emodifier;
2259         uval_t  uval;
2260         char    modstring[64];
2261 
2262         if (status < 0)
2263                 return (status);
2264 
2265         if ((returnstat = pr_adr_u_short(context, &emodifier, 1)) != 0)
2266                 return (returnstat);
2267 
2268         /* For XML, only print when modifier is non-zero */
2269         if (!(context->format & PRF_XMLM) || (emodifier != 0)) {
2270                 uval.uvaltype = PRA_STRING;
2271 
2272                 returnstat = open_tag(context, TAG_EVMOD);
2273 
2274                 if (returnstat >= 0) {
2275                         if (!(context->format & PRF_RAWM)) {
2276                                 eventmodifier2string(emodifier, modstring,
2277                                     sizeof (modstring));
2278                                 uval.string_val = modstring;
2279                                 returnstat = pa_print(context, &uval, flag);
2280                         } else {
2281                                 uval.string_val = hexconvert((char *)&emodifier,
2282                                     sizeof (emodifier), sizeof (emodifier));
2283                                 if (uval.string_val) {
2284                                         returnstat = pa_print(context, &uval,
2285                                             flag);
2286                                         free(uval.string_val);
2287                                 }
2288                         }
2289                 }
2290                 if (returnstat >= 0)
2291                         returnstat = close_tag(context, TAG_EVMOD);
2292         }
2293 
2294         return (returnstat);
2295 }
2296 
2297 
2298 /*
2299  * -----------------------------------------------------------------------
2300  * pa_event_type(): Issues pr_adr_u_short to retrieve the next ADR item from
2301  *                the input stream pointed to by audit_adr.  This is the
2302  *                event type, and is displayed in either raw or
2303  *                ASCII form as appropriate
2304  * return codes : -1 - error
2305  *              :  0 - successful
2306  * -----------------------------------------------------------------------
2307  */
2308 int
2309 pa_event_type(pr_context_t *context, int status,  int flag)
2310 {
2311         au_event_t etype;
2312         int     returnstat;
2313         au_event_ent_t *p_event = NULL;
2314         uval_t  uval;
2315 
2316         if (status >= 0) {
2317                 if ((returnstat = pr_adr_u_short(context, &etype, 1)) == 0) {
2318                         if (!(context->format & PRF_RAWM)) {
2319                                 uval.uvaltype = PRA_STRING;
2320                                 if (context->format & PRF_NOCACHE) {
2321                                         p_event = getauevnum(etype);
2322                                 } else {
2323                                         (void) cacheauevent(&p_event, etype);
2324                                 }
2325                                 if (p_event != NULL) {
2326                                         if (context->format & PRF_SHORTM)
2327                                                 uval.string_val =
2328                                                     p_event->ae_name;
2329                                         else
2330                                                 uval.string_val =
2331                                                     p_event->ae_desc;
2332                                 } else {
2333                                         uval.string_val =
2334                                             gettext("invalid event number");
2335                                 }
2336                                 returnstat = pa_print(context, &uval, flag);
2337                         } else {
2338                                 uval.uvaltype = PRA_USHORT;
2339                                 uval.ushort_val = etype;
2340                                 returnstat = pa_print(context, &uval, flag);
2341                         }
2342                 }
2343                 return (returnstat);
2344         } else
2345                 return (status);
2346 
2347 }
2348 
2349 
2350 /*
2351  * Print time from struct timeval to millisecond resolution.
2352  *
2353  *      typedef long    time_t;         time of day in seconds
2354  *      typedef long    useconds_t;     signed # of microseconds
2355  *
2356  * struct timeval {
2357  *      time_t          tv_sec;         seconds
2358  *      suseconds_t     tv_usec;        and microseconds
2359  * };
2360  */
2361 
2362 int
2363 pa_utime32(pr_context_t *context, int status, int flag)
2364 {
2365         uint32_t scale = 1000;          /* usec to msec */
2366 
2367         return (do_mtime32(context, status, flag, scale));
2368 }
2369 
2370 /*
2371  * Print time from timestruc_t to millisecond resolution.
2372  *
2373  *      typedef struct timespec timestruct_t;
2374  * struct timespec{
2375  *      time_t  tv_sec;         seconds
2376  *      long    tv_nsec;        and nanoseconds
2377  * };
2378  */
2379 int
2380 pa_ntime32(pr_context_t *context, int status, int flag)
2381 {
2382         uint32_t scale = 1000000;       /* nsec to msec */
2383 
2384         return (do_mtime32(context, status, flag, scale));
2385 }
2386 
2387 /*
2388  * Format the timezone +/- HH:MM and terminate the string
2389  * Note tm and tv_sec are the same time.
2390  * Too bad strftime won't produce an ISO 8601 time zone numeric
2391  */
2392 
2393 #define MINS    (24L * 60)
2394 static void
2395 tzone(struct tm *tm, time_t *tv_sec, char *p)
2396 {
2397         struct tm *gmt;
2398         int min_off;
2399 
2400         gmt = gmtime(tv_sec);
2401 
2402         min_off = ((tm->tm_hour - gmt->tm_hour) * 60) +
2403             (tm->tm_min - gmt->tm_min);
2404 
2405         if (tm->tm_year < gmt->tm_year)                /* cross new year */
2406                 min_off -= MINS;
2407         else if (tm->tm_year > gmt->tm_year)
2408                 min_off += MINS;
2409         else if (tm->tm_yday < gmt->tm_yday)   /* cross dateline */
2410                 min_off -= MINS;
2411         else if (tm->tm_yday > gmt->tm_yday)
2412                 min_off += MINS;
2413 
2414         if (min_off < 0) {
2415                 min_off = -min_off;
2416                 *p++ = '-';
2417         } else {
2418                 *p++ = '+';
2419         }
2420 
2421         *p++ = min_off / 600 + '0';             /* 10s of hours */
2422         min_off = min_off - min_off / 600 * 600;
2423         *p++ = min_off / 60 % 10 + '0';         /* hours */
2424         min_off = min_off - min_off / 60 * 60;
2425         *p++ = ':';
2426         *p++ = min_off / 10 + '0';              /* 10s of minutes */
2427         *p++ = min_off % 10 + '0';              /* minutes */
2428         *p = '\0';
2429 }
2430 
2431 /*
2432  * Format the milliseconds in place in the string.
2433  * Borrowed from strftime.c:itoa()
2434  */
2435 static void
2436 msec32(uint32_t msec, char *p)
2437 {
2438         *p++ = msec / 100 + '0';
2439         msec  = msec - msec / 100 * 100;
2440         *p++ = msec / 10 + '0';
2441         *p++ = msec % 10 +'0';
2442 }
2443 
2444 /*
2445  * Format time and print relative to scale factor from micro/nano seconds.
2446  */
2447 static int
2448 do_mtime32(pr_context_t *context, int status, int flag, uint32_t scale)
2449 {
2450         uint32_t t32;
2451         time_t tv_sec;
2452         struct tm tm;
2453         char    time_created[sizeof ("YYYY-MM-DD HH:MM:SS.sss -HH:MM")];
2454         int     returnstat;
2455         uval_t  uval;
2456 
2457         if (status < 0)
2458                 return (status);
2459 
2460         if ((returnstat = open_tag(context, TAG_ISO)) != 0)
2461                 return (returnstat);
2462 
2463         if ((returnstat = pr_adr_u_int32(context,
2464             (uint32_t *)&tv_sec, 1)) != 0)
2465                 return (returnstat);
2466         if ((returnstat = pr_adr_u_int32(context, &t32, 1)) == 0) {
2467                 if (!(context->format & PRF_RAWM)) {
2468                         (void) localtime_r(&tv_sec, &tm);
2469                         (void) strftime(time_created,
2470                             sizeof ("YYYY-MM-DD HH:MM:SS.xxx "),
2471                             "%Y-%m-%d %H:%M:%S.xxx ", &tm);
2472                         msec32(t32/scale,
2473                             &time_created[sizeof ("YYYY-MM-DD HH:MM:SS.")-1]);
2474                         tzone(&tm, &tv_sec,
2475                             &time_created[
2476                             sizeof ("YYYY-MM-DD HH:MM:SS.xxx ")-1]);
2477                         uval.uvaltype = PRA_STRING;
2478                         uval.string_val = time_created;
2479                 } else {
2480                         uval.uvaltype = PRA_UINT32;
2481                         uval.uint32_val = (uint32_t)tv_sec;
2482                         (void) pa_print(context, &uval, 0);
2483                         if (context->format & PRF_XMLM) {
2484                                 uval.uvaltype = PRA_CHAR;
2485                                 uval.char_val = '.';
2486                                 (void) pa_print(context, &uval, 0);
2487                         }
2488                         uval.uvaltype = PRA_UINT32;
2489                         uval.uint32_val = t32;
2490                 }
2491                 returnstat = pa_print(context, &uval, flag);
2492         }
2493 
2494         if (returnstat == 0)
2495                 return (close_tag(context, TAG_ISO));
2496         else
2497                 return (returnstat);
2498 }
2499 
2500 /*
2501  * Print time from struct timeval to millisecond resolution.
2502  *
2503  *      typedef long    time_t;         time of day in seconds
2504  *      typedef long    useconds_t;     signed # of microseconds
2505  *
2506  * struct timeval {
2507  *      time_t          tv_sec;         seconds
2508  *      suseconds_t     tv_usec;        and microseconds
2509  * };
2510  */
2511 
2512 int
2513 pa_utime64(pr_context_t *context, int status, int flag)
2514 {
2515         uint64_t scale = 1000;          /* usec to msec */
2516 
2517         return (do_mtime64(context, status, flag, scale));
2518 }
2519 
2520 /*
2521  * Print time from timestruc_t to millisecond resolution.
2522  *
2523  *      typedef struct timespec timestruct_t;
2524  * struct timespec{
2525  *      time_t  tv_sec;         seconds
2526  *      long    tv_nsec;        and nanoseconds
2527  * };
2528  */
2529 int
2530 pa_ntime64(pr_context_t *context, int status, int flag)
2531 {
2532         uint64_t scale = 1000000;       /* nsec to msec */
2533 
2534         return (do_mtime64(context, status, flag, scale));
2535 }
2536 
2537 /*
2538  * Format the milliseconds in place in the string.
2539  * Borrowed from strftime.c:itoa()
2540  */
2541 static void
2542 msec64(uint64_t msec, char *p)
2543 {
2544         *p++ = msec / 100 + '0';
2545         msec = msec - msec / 100 * 100;
2546         *p++ = msec / 10 + '0';
2547         *p++ = msec % 10 +'0';
2548 }
2549 
2550 /*
2551  * Format time and print relative to scale factor from micro/nano seconds.
2552  */
2553 static int
2554 do_mtime64(pr_context_t *context, int status, int flag, uint64_t scale)
2555 {
2556         uint64_t t64_sec;
2557         uint64_t t64_msec;
2558         time_t tv_sec;
2559         struct tm tm;
2560         char    time_created[sizeof ("YYYY-MM-DD HH:MM:SS.sss -HH:MM")];
2561         int     returnstat;
2562         uval_t  uval;
2563 
2564         if (status < 0)
2565                 return (status);
2566 
2567         if ((returnstat = open_tag(context, TAG_ISO)) != 0)
2568                 return (returnstat);
2569 
2570         if ((returnstat = pr_adr_u_int64(context, &t64_sec, 1)) != 0)
2571                 return (returnstat);
2572         if ((returnstat = pr_adr_u_int64(context, &t64_msec, 1)) == 0) {
2573                 if (!(context->format & PRF_RAWM)) {
2574 #ifndef _LP64
2575                         /*
2576                          * N.B.
2577                          * This fails for years from 2038
2578                          * The Y2K+38 problem
2579                          */
2580 #endif  /* !_LP64 */
2581                         tv_sec = (time_t)t64_sec;
2582                         (void) localtime_r(&tv_sec, &tm);
2583                         (void) strftime(time_created,
2584                             sizeof ("YYYY-MM-DD HH:MM:SS.xxx "),
2585                             "%Y-%m-%d %H:%M:%S.xxx ", &tm);
2586                         msec64(t64_msec/scale,
2587                             &time_created[sizeof ("YYYY-MM-DD HH:MM:SS.")-1]);
2588                         tzone(&tm, &tv_sec,
2589                             &time_created[
2590                             sizeof ("YYYY-MM-DD HH:MM:SS.xxx ")-1]);
2591                         uval.uvaltype = PRA_STRING;
2592                         uval.string_val = time_created;
2593                 } else {
2594                         uval.uvaltype = PRA_UINT64;
2595                         uval.uint64_val = t64_sec;
2596                         (void) pa_print(context, &uval, 0);
2597                         if (context->format & PRF_XMLM) {
2598                                 uval.uvaltype = PRA_CHAR;
2599                                 uval.char_val = '.';
2600                                 (void) pa_print(context, &uval, 0);
2601                         }
2602                         uval.uvaltype = PRA_UINT64;
2603                         uval.uint64_val = t64_msec;
2604                 }
2605                 returnstat = pa_print(context, &uval, flag);
2606         }
2607 
2608         if (returnstat < 0)
2609                 return (returnstat);
2610 
2611         return (close_tag(context, TAG_ISO));
2612 }
2613 
2614 /*
2615  * -----------------------------------------------------------------------
2616  * pa_error()   :  convert the return token error code.
2617  *
2618  * output       : buf string representing return token error code.
2619  *
2620  * -----------------------------------------------------------------------
2621  */
2622 void
2623 pa_error(const uchar_t err, char *buf, size_t buflen)
2624 {
2625         if (err == ADT_SUCCESS) {
2626                 (void) strlcpy(buf, gettext("success"), buflen);
2627         } else if ((char)err == ADT_FAILURE) {
2628                 (void) strlcpy(buf, gettext("failure"), buflen);
2629         } else {
2630                 char *emsg = strerror(err);
2631 
2632                 if (emsg != NULL) {
2633                         (void) strlcpy(buf, gettext("failure: "), buflen);
2634                         (void) strlcat(buf, emsg, buflen);
2635                 } else {
2636                         (void) snprintf(buf, buflen, "%s%d",
2637                             gettext("failure: "), err);
2638                 }
2639         }
2640 }
2641 
2642 /*
2643  * -----------------------------------------------------------------------
2644  * pa_retval()  :  convert the return token return value code.
2645  *
2646  * input        : err, for kernel success 0, or
2647  *                      failure errno: 0 > & < sys_nerr.
2648  *                      for userland success ADT_SUCCESS (0) or
2649  *                      failure ADT_FAILURE (-1).
2650  *              pa_error() above has already converted err.
2651  *
2652  *              : retval, for kernel arbitrary return value for success, or
2653  *                      failure: -1.
2654  *                      for userland,
2655  *                      >= ADT_FAIL_VALUE < ADT_FAIL_PAM, an adt message code;
2656  *                      >= ADT_FAIL_PAM, a pam_strerror value;
2657  *                      < ADT_FAIL_VALUE, supposed to be an errno.
2658  *
2659  * output       : buf string representing return token error code.
2660  *
2661  * -----------------------------------------------------------------------
2662  */
2663 void
2664 pa_retval(const uchar_t err, const int32_t retval, char *buf, size_t buflen)
2665 {
2666         struct msg_text *msglist;
2667         char *emsg;
2668 
2669         /* success or kernel failure */
2670         if (((char)err == ADT_SUCCESS) ||
2671             (retval < 0)) {
2672 
2673                 (void) snprintf(buf, buflen, "%d", retval);
2674                 return;
2675         }
2676 
2677         /* userland failure */
2678         msglist = &adt_msg_text[ADT_LIST_FAIL_VALUE];
2679 
2680         if ((retval + msglist->ml_offset >= msglist->ml_min_index) &&
2681             (retval + msglist->ml_offset <= msglist->ml_max_index)) {
2682 
2683                 (void) strlcpy(buf,
2684                     gettext(msglist->ml_msg_list[retval + msglist->ml_offset]),
2685                     buflen);
2686         } else if ((retval >= ADT_FAIL_PAM) &&
2687             (retval < ADT_FAIL_PAM + PAM_TOTAL_ERRNUM)) {
2688 
2689                 (void) strlcpy(buf, pam_strerror(NULL, retval - ADT_FAIL_PAM),
2690                     buflen);
2691         } else if ((emsg = strerror(retval)) != NULL) {
2692 
2693                 (void) strlcpy(buf, emsg, buflen);
2694         } else {
2695 
2696                 (void) snprintf(buf, buflen, "%d", retval);
2697         }
2698 }
2699 
2700 /*
2701  * -----------------------------------------------------------------------
2702  * pa_printstr()        :  print a given string, translating unprintables
2703  *                      :  as needed.
2704  */
2705 static int
2706 pa_printstr(pr_context_t *context, char *str)
2707 {
2708         int     err = 0;
2709         int     len, printable;
2710         int     mbmax = MB_CUR_MAX;
2711         wchar_t wc;
2712         char    c;
2713 
2714         if (mbmax == 1) {
2715                 /* fast path */
2716                 while (err == 0 && *str != '\0') {
2717                         c = *str++;
2718                         printable = isprint((unsigned char)c);
2719                         err = pa_putstr(context, printable, &c, 1);
2720                 }
2721                 return (err);
2722         }
2723         while (err == 0 && *str != '\0') {
2724                 len = mbtowc(&wc, str, mbmax);
2725                 if (len <= 0) {
2726                         len = 1;
2727                         printable = 0;
2728                 } else {
2729                         printable = iswprint(wc);
2730                 }
2731                 err = pa_putstr(context, printable, str, len);
2732                 str += len;
2733         }
2734         return (err);
2735 }
2736 
2737 /*
2738  * -----------------------------------------------------------------------
2739  * pa_print()   :  print as one str or formatted for easy reading.
2740  *              : flag - indicates whether to output a new line for
2741  *              : multi-line output.
2742  *              :               = 0; no new line
2743  *              :               = 1; new line if regular output
2744  * output       : The audit record information is displayed in the
2745  *                type specified by uvaltype and value specified in
2746  *                uval.  The printing of the delimiter or newline is
2747  *                determined by PRF_ONELINE, and the flag value,
2748  *                as follows:
2749  *                      +--------+------+------+-----------------+
2750  *                      |ONELINE | flag | last | Action          |
2751  *                      +--------+------+------+-----------------+
2752  *                      |    Y   |   Y  |   T  | print new line  |
2753  *                      |    Y   |   Y  |   F  | print delimiter |
2754  *                      |    Y   |   N  |   T  | print new line  |
2755  *                      |    Y   |   N  |   F  | print delimiter |
2756  *                      |    N   |   Y  |   T  | print new line  |
2757  *                      |    N   |   Y  |   F  | print new line  |
2758  *                      |    N   |   N  |   T  | print new line  |
2759  *                      |    N   |   N  |   F  | print delimiter |
2760  *                      +--------+------+------+-----------------+
2761  *
2762  * return codes : -1 - error
2763  *              0 - successful
2764  * -----------------------------------------------------------------------
2765  */
2766 int
2767 pa_print(pr_context_t *context, uval_t *uval, int flag)
2768 {
2769         int     returnstat = 0;
2770         int     last;
2771 
2772         switch (uval->uvaltype) {
2773         case PRA_INT32:
2774                 returnstat = pr_printf(context, "%d", uval->int32_val);
2775                 break;
2776         case PRA_UINT32:
2777                 returnstat = pr_printf(context, "%u", uval->uint32_val);
2778                 break;
2779         case PRA_INT64:
2780                 returnstat = pr_printf(context, "%"PRId64, uval->int64_val);
2781                 break;
2782         case PRA_UINT64:
2783                 returnstat = pr_printf(context, "%"PRIu64, uval->uint64_val);
2784                 break;
2785         case PRA_SHORT:
2786                 returnstat = pr_printf(context, "%hd", uval->short_val);
2787                 break;
2788         case PRA_USHORT:
2789                 returnstat = pr_printf(context, "%hu", uval->ushort_val);
2790                 break;
2791         case PRA_CHAR:
2792                 returnstat = pr_printf(context, "%c", uval->char_val);
2793                 break;
2794         case PRA_BYTE:
2795                 returnstat = pr_printf(context, "%d", uval->char_val);
2796                 break;
2797         case PRA_STRING:
2798                 returnstat = pa_printstr(context, uval->string_val);
2799                 break;
2800         case PRA_HEX32:
2801                 returnstat = pr_printf(context, "0x%x", uval->int32_val);
2802                 break;
2803         case PRA_HEX64:
2804                 returnstat = pr_printf(context, "0x%"PRIx64, uval->int64_val);
2805                 break;
2806         case PRA_SHEX:
2807                 returnstat = pr_printf(context, "0x%hx", uval->short_val);
2808                 break;
2809         case PRA_OCT:
2810                 returnstat = pr_printf(context, "%ho", uval->ushort_val);
2811                 break;
2812         case PRA_LOCT:
2813                 returnstat = pr_printf(context, "%o", (int)uval->uint32_val);
2814                 break;
2815         default:
2816                 (void) fprintf(stderr, gettext("praudit: Unknown type.\n"));
2817                 returnstat = -1;
2818                 break;
2819         }
2820         if (returnstat < 0)
2821                 return (returnstat);
2822 
2823         last = (context->audit_adr->adr_now ==
2824             (context->audit_rec_start + context->audit_rec_len));
2825 
2826         if (!(context->format & PRF_XMLM)) {
2827                 if (!(context->format & PRF_ONELINE)) {
2828                         if ((flag == 1) || last)
2829                                 returnstat = pr_putchar(context, '\n');
2830                         else
2831                                 returnstat = pr_printf(context, "%s",
2832                                     context->SEPARATOR);
2833                 } else {
2834                         if (!last)
2835                                 returnstat = pr_printf(context, "%s",
2836                                     context->SEPARATOR);
2837                         else
2838                                 returnstat = pr_putchar(context, '\n');
2839                 }
2840         }
2841         if ((returnstat == 0) && (context->data_mode == FILEMODE))
2842                 (void) fflush(stdout);
2843 
2844         return (returnstat);
2845 }
2846 
2847 static struct cntrl_mapping {
2848         char from;
2849         char to;
2850 } cntrl_map[] = {
2851         '\0', '0',
2852         '\a', 'a',
2853         '\b', 'b',
2854         '\t', 't',
2855         '\f', 'f',
2856         '\n', 'n',
2857         '\r', 'r',
2858         '\v', 'v'
2859 };
2860 
2861 static int cntrl_map_entries = sizeof (cntrl_map)
2862         / sizeof (struct cntrl_mapping);
2863 
2864 /*
2865  * Convert binary data to ASCII for printing.
2866  */
2867 void
2868 convertascii(char *p, char *c, int size)
2869 {
2870         int     i, j, uc;
2871 
2872         for (i = 0; i < size; i++) {
2873                 uc = (unsigned char)*(c + i);
2874                 if (isascii(uc)) {
2875                         if (iscntrl(uc)) {
2876                                 for (j = 0; j < cntrl_map_entries; j++) {
2877                                         if (cntrl_map[j].from == uc) {
2878                                                 *p++ = '\\';
2879                                                 *p++ = cntrl_map[j].to;
2880                                                 break;
2881                                         }
2882                                 }
2883                                 if (j == cntrl_map_entries) {
2884                                         *p++ = '^';
2885                                         *p++ = (char)(uc ^ 0100);
2886                                 }
2887                         } else {
2888                                 *p++ = (char)uc;
2889                         }
2890                 } else {
2891                         p += sprintf(p, "\\%03o", uc);
2892                 }
2893         }
2894         *p = '\0';
2895 }
2896 
2897 /*
2898  * -----------------------------------------------------------------------
2899  * pa_xgeneric: Process Xobject token and display contents
2900  *                    This routine will handle many of the attribute
2901  *                    types introduced in TS 2.x, such as:
2902  *
2903  *                    AUT_XCOLORMAP, AUT_XCURSOR, AUT_XFONT,
2904  *                    AUT_XGC, AUT_XPIXMAP, AUT_XWINDOW
2905  *
2906  * NOTE: At the time of call, the token id has been retrieved
2907  *
2908  * return codes         : -1 - error
2909  *                      :  0 - successful
2910  * NOTE: At the time of call, the xatom token id has been retrieved
2911  *
2912  * Format of xobj
2913  *      text token id           adr_char
2914  *      XID                     adr_u_int32
2915  *      creator uid             adr_pw_uid
2916  * -----------------------------------------------------------------------
2917  */
2918 int
2919 pa_xgeneric(pr_context_t *context)
2920 {
2921         int     returnstat;
2922 
2923         returnstat = process_tag(context, TAG_XID, 0, 0);
2924         return (process_tag(context, TAG_XCUID, returnstat, 1));
2925 }
2926 
2927 
2928 /*
2929  * ------------------------------------------------------------------------
2930  * pa_liaison : Issues pr_adr_char to retrieve the next ADR item from the
2931  *                      input stream pointed to by audit_adr, and prints it
2932  *                      if status >= 0 either in ASCII or raw form
2933  * return codes : -1 - error
2934  *              : 0 - successful
2935  *              : 1 - warning, unknown label type
2936  * -----------------------------------------------------------------------
2937  */
2938 int
2939 pa_liaison(pr_context_t *context, int status, int flag)
2940 {
2941         int     returnstat;
2942         int32_t li;
2943         uval_t  uval;
2944 
2945         if (status >= 0) {
2946                 if ((returnstat = pr_adr_int32(context, &li, 1)) != 0) {
2947                         return (returnstat);
2948                 }
2949                 if (!(context->format & PRF_RAWM)) {
2950                         uval.uvaltype = PRA_UINT32;
2951                         uval.uint32_val = li;
2952                         returnstat = pa_print(context, &uval, flag);
2953                 }
2954                 /* print in hexadecimal form */
2955                 if ((context->format & PRF_RAWM) || (returnstat == 1)) {
2956                         uval.uvaltype = PRA_HEX32;
2957                         uval.uint32_val = li;
2958                         returnstat = pa_print(context, &uval, flag);
2959                 }
2960                 return (returnstat);
2961         } else
2962                 return (status);
2963 }
2964 
2965 /*
2966  * ------------------------------------------------------------------------
2967  * pa_xid : Issues pr_adr_int32 to retrieve the XID from the input
2968  *            stream pointed to by audit_adr, and prints it if
2969  *            status >= 0 either in ASCII or raw form
2970  * return codes : -1 - error
2971  *              :  0 - successful
2972  *              :  1 - warning, unknown label type
2973  * ------------------------------------------------------------------------
2974  */
2975 
2976 int
2977 pa_xid(pr_context_t *context, int status, int flag)
2978 {
2979         int returnstat;
2980         int32_t xid;
2981         uval_t  uval;
2982 
2983         if (status < 0)
2984                 return (status);
2985 
2986         /* get XID from stream */
2987         if ((returnstat = pr_adr_int32(context, (int32_t *)&xid, 1)) != 0)
2988                 return (returnstat);
2989 
2990         if (!(context->format & PRF_RAWM)) {
2991                 uval.uvaltype = PRA_STRING;
2992                 uval.string_val = hexconvert((char *)&xid, sizeof (xid),
2993                     sizeof (xid));
2994                 if (uval.string_val) {
2995                         returnstat = pa_print(context, &uval, flag);
2996                         free(uval.string_val);
2997                 }
2998         } else {
2999                 uval.uvaltype = PRA_INT32;
3000                 uval.int32_val = xid;
3001                 returnstat = pa_print(context, &uval, flag);
3002         }
3003 
3004         return (returnstat);
3005 }
3006 
3007 static int
3008 pa_ace_flags(pr_context_t *context, ace_t *ace, int status, int flag)
3009 {
3010         int     returnstat;
3011         uval_t  uval;
3012 
3013         if (status < 0)
3014                 return (status);
3015 
3016         /*
3017          * TRANSLATION_NOTE
3018          * ace->a_flags refers to access flags of ZFS/NFSv4 ACL entry.
3019          */
3020         if ((returnstat = open_tag(context, TAG_ACEFLAGS)) != 0)
3021                 return (returnstat);
3022         if (!(context->format & PRF_RAWM)) {
3023                 uval.uvaltype = PRA_STRING;
3024                 switch (ace->a_flags & ACE_TYPE_FLAGS) {
3025                 case ACE_OWNER:
3026                         uval.string_val = gettext(OWNERAT_TXT);
3027                         break;
3028                 case ACE_GROUP | ACE_IDENTIFIER_GROUP:
3029                         uval.string_val = gettext(GROUPAT_TXT);
3030                         break;
3031                 case ACE_IDENTIFIER_GROUP:
3032                         uval.string_val = gettext(GROUP_TXT);
3033                         break;
3034                 case ACE_EVERYONE:
3035                         uval.string_val = gettext(EVERYONEAT_TXT);
3036                         break;
3037                 case 0:
3038                         uval.string_val = gettext(USER_TXT);
3039                         break;
3040                 default:
3041                         uval.uvaltype = PRA_USHORT;
3042                         uval.uint32_val = ace->a_flags;
3043                 }
3044         } else {
3045                 uval.uvaltype = PRA_USHORT;
3046                 uval.uint32_val = ace->a_flags;
3047         }
3048         if ((returnstat = pa_print(context, &uval, flag)) != 0)
3049                 return (returnstat);
3050         return (close_tag(context, TAG_ACEFLAGS));
3051 }
3052 
3053 static int
3054 pa_ace_who(pr_context_t *context, ace_t *ace, int status, int flag)
3055 {
3056         int             returnstat;
3057 
3058         if (status < 0)
3059                 return (status);
3060 
3061         /*
3062          * TRANSLATION_NOTE
3063          * ace->a_who refers to user id or group id of ZFS/NFSv4 ACL entry.
3064          */
3065         if ((returnstat = open_tag(context, TAG_ACEID)) != 0)
3066                 return (returnstat);
3067         switch (ace->a_flags & ACE_TYPE_FLAGS) {
3068         case ACE_IDENTIFIER_GROUP:      /* group id */
3069                 returnstat = pa_print_gid(context, ace->a_who, returnstat,
3070                     flag);
3071                 break;
3072         default:                        /* user id */
3073                 returnstat = pa_print_uid(context, ace->a_who, returnstat,
3074                     flag);
3075                 break;
3076         }
3077         if (returnstat < 0)
3078                 return (returnstat);
3079         return (close_tag(context, TAG_ACEID));
3080 }
3081 
3082 /*
3083  * Appends what to str, (re)allocating str if necessary.
3084  */
3085 #define INITIAL_ALLOC   256
3086 static int
3087 strappend(char **str, char *what, size_t *alloc)
3088 {
3089         char    *s, *newstr;
3090         size_t  needed;
3091 
3092         s = *str;
3093 
3094         if (s == NULL) {
3095                 s = malloc(INITIAL_ALLOC);
3096                 if (s == NULL) {
3097                         *alloc = 0;
3098                         return (-1);
3099                 }
3100                 *alloc = INITIAL_ALLOC;
3101                 s[0] = '\0';
3102                 *str = s;
3103         }
3104 
3105         needed = strlen(s) + strlen(what) + 1;
3106         if (*alloc < needed) {
3107                 newstr = realloc(s, needed);
3108                 if (newstr == NULL)
3109                         return (-1);
3110                 s = newstr;
3111                 *alloc = needed;
3112                 *str = s;
3113         }
3114         (void) strlcat(s, what, *alloc);
3115 
3116         return (0);
3117 }
3118 
3119 static int
3120 pa_ace_access_mask(pr_context_t *context, uint32_t mask, int status, int flag)
3121 {
3122         int     returnstat, i;
3123         uval_t  uval;
3124         char    *permstr = NULL;
3125         size_t  permstr_alloc = 0;
3126 
3127         if (status < 0)
3128                 return (status);
3129 
3130         /*
3131          * TRANSLATION_NOTE
3132          * mask refers to access mask of ZFS/NFSv4 ACL entry.
3133          */
3134         if ((returnstat = open_tag(context, TAG_ACEMASK)) != 0)
3135                 return (returnstat);
3136         if (context->format & PRF_SHORTM &&
3137             ((permstr = malloc(15)) != NULL)) {
3138                 for (i = 0; i < 14; i++)
3139                         permstr[i] = '-';
3140 
3141                 if (mask & ACE_READ_DATA)
3142                         permstr[0] = 'r';
3143                 if (mask & ACE_WRITE_DATA)
3144                         permstr[1] = 'w';
3145                 if (mask & ACE_EXECUTE)
3146                         permstr[2] = 'x';
3147                 if (mask & ACE_APPEND_DATA)
3148                         permstr[3] = 'p';
3149                 if (mask & ACE_DELETE)
3150                         permstr[4] = 'd';
3151                 if (mask & ACE_DELETE_CHILD)
3152                         permstr[5] = 'D';
3153                 if (mask & ACE_READ_ATTRIBUTES)
3154                         permstr[6] = 'a';
3155                 if (mask & ACE_WRITE_ATTRIBUTES)
3156                         permstr[7] = 'A';
3157                 if (mask & ACE_READ_NAMED_ATTRS)
3158                         permstr[8] = 'R';
3159                 if (mask & ACE_WRITE_NAMED_ATTRS)
3160                         permstr[9] = 'W';
3161                 if (mask & ACE_READ_ACL)
3162                         permstr[10] = 'c';
3163                 if (mask & ACE_WRITE_ACL)
3164                         permstr[11] = 'C';
3165                 if (mask & ACE_WRITE_OWNER)
3166                         permstr[12] = 'o';
3167                 if (mask & ACE_SYNCHRONIZE)
3168                         permstr[13] = 's';
3169                 permstr[14] = '\0';
3170                 uval.uvaltype = PRA_STRING;
3171                 uval.string_val = permstr;
3172         } else if (!(context->format & PRF_RAWM)) {
3173 
3174                 /*
3175                  * Note this differs from acltext.c:ace_perm_txt()
3176                  * because we don't know if the acl belongs to a file
3177                  * or directory. ace mask value are the same
3178                  * nonetheless, see sys/acl.h
3179                  */
3180                 if (mask & ACE_LIST_DIRECTORY) {
3181                         returnstat = strappend(&permstr, gettext(READ_DIR_TXT),
3182                             &permstr_alloc);
3183                 }
3184                 if (mask & ACE_ADD_FILE) {
3185                         returnstat = strappend(&permstr, gettext(ADD_FILE_TXT),
3186                             &permstr_alloc);
3187                 }
3188                 if (mask & ACE_ADD_SUBDIRECTORY) {
3189                         returnstat = strappend(&permstr, gettext(ADD_DIR_TXT),
3190                             &permstr_alloc);
3191                 }
3192                 if (mask & ACE_READ_NAMED_ATTRS) {
3193                         returnstat = strappend(&permstr,
3194                             gettext(READ_XATTR_TXT), &permstr_alloc);
3195                 }
3196                 if (mask & ACE_WRITE_NAMED_ATTRS) {
3197                         returnstat = strappend(&permstr,
3198                             gettext(WRITE_XATTR_TXT), &permstr_alloc);
3199                 }
3200                 if (mask & ACE_EXECUTE) {
3201                         returnstat = strappend(&permstr,
3202                             gettext(EXECUTE_TXT), &permstr_alloc);
3203                 }
3204                 if (mask & ACE_DELETE_CHILD) {
3205                         returnstat = strappend(&permstr,
3206                             gettext(DELETE_CHILD_TXT), &permstr_alloc);
3207                 }
3208                 if (mask & ACE_READ_ATTRIBUTES) {
3209                         returnstat = strappend(&permstr,
3210                             gettext(READ_ATTRIBUTES_TXT), &permstr_alloc);
3211                 }
3212                 if (mask & ACE_WRITE_ATTRIBUTES) {
3213                         returnstat = strappend(&permstr,
3214                             gettext(WRITE_ATTRIBUTES_TXT), &permstr_alloc);
3215                 }
3216                 if (mask & ACE_DELETE) {
3217                         returnstat = strappend(&permstr, gettext(DELETE_TXT),
3218                             &permstr_alloc);
3219                 }
3220                 if (mask & ACE_READ_ACL) {
3221                         returnstat = strappend(&permstr, gettext(READ_ACL_TXT),
3222                             &permstr_alloc);
3223                 }
3224                 if (mask & ACE_WRITE_ACL) {
3225                         returnstat = strappend(&permstr, gettext(WRITE_ACL_TXT),
3226                             &permstr_alloc);
3227                 }
3228                 if (mask & ACE_WRITE_OWNER) {
3229                         returnstat = strappend(&permstr,
3230                             gettext(WRITE_OWNER_TXT), &permstr_alloc);
3231                 }
3232                 if (mask & ACE_SYNCHRONIZE) {
3233                         returnstat = strappend(&permstr,
3234                             gettext(SYNCHRONIZE_TXT), &permstr_alloc);
3235                 }
3236                 if (permstr[strlen(permstr) - 1] == '/')
3237                         permstr[strlen(permstr) - 1] = '\0';
3238                 uval.uvaltype = PRA_STRING;
3239                 uval.string_val = permstr;
3240         }
3241         if ((permstr == NULL) || (returnstat != 0) ||
3242             (context->format & PRF_RAWM)) {
3243                 uval.uvaltype = PRA_HEX32;
3244                 uval.int32_val = mask;
3245         }
3246         returnstat = pa_print(context, &uval, flag);
3247 
3248         if (permstr != NULL)
3249                 free(permstr);
3250         if (returnstat != 0)
3251                 return (returnstat);
3252         return (close_tag(context, TAG_ACEMASK));
3253 }
3254 
3255 static int
3256 pa_ace_type(pr_context_t *context, ace_t *ace, int status, int flag)
3257 {
3258         int     returnstat;
3259         uval_t  uval;
3260 
3261         if (status < 0)
3262                 return (status);
3263 
3264         /*
3265          * TRANSLATION_NOTE
3266          * ace->a_type refers to access type of ZFS/NFSv4 ACL entry.
3267          */
3268         if ((returnstat = open_tag(context, TAG_ACETYPE)) != 0)
3269                 return (returnstat);
3270         if (!(context->format & PRF_RAWM)) {
3271                 uval.uvaltype = PRA_STRING;
3272                 switch (ace->a_type) {
3273                 case ACE_ACCESS_ALLOWED_ACE_TYPE:
3274                         uval.string_val = gettext(ALLOW_TXT);
3275                         break;
3276                 case ACE_ACCESS_DENIED_ACE_TYPE:
3277                         uval.string_val = gettext(DENY_TXT);
3278                         break;
3279                 case ACE_SYSTEM_AUDIT_ACE_TYPE:
3280                         uval.string_val = gettext(AUDIT_TXT);
3281                         break;
3282                 case ACE_SYSTEM_ALARM_ACE_TYPE:
3283                         uval.string_val = gettext(ALARM_TXT);
3284                         break;
3285                 default:
3286                         uval.string_val = gettext(UNKNOWN_TXT);
3287                 }
3288         } else {
3289                 uval.uvaltype = PRA_USHORT;
3290                 uval.uint32_val = ace->a_type;
3291         }
3292         if ((returnstat = pa_print(context, &uval, flag)) != 0)
3293                 return (returnstat);
3294         return (close_tag(context, TAG_ACETYPE));
3295 }
3296 
3297 int
3298 pa_ace(pr_context_t *context, int status, int flag)
3299 {
3300         int             returnstat;
3301         ace_t           ace;
3302 
3303         if (status < 0)
3304                 return (status);
3305 
3306         if ((returnstat = pr_adr_u_int32(context, &ace.a_who, 1)) != 0)
3307                 return (returnstat);
3308         if ((returnstat = pr_adr_u_int32(context, &ace.a_access_mask, 1)) != 0)
3309                 return (returnstat);
3310         if ((returnstat = pr_adr_u_short(context, &ace.a_flags, 1)) != 0)
3311                 return (returnstat);
3312         if ((returnstat = pr_adr_u_short(context, &ace.a_type, 1)) != 0)
3313                 return (returnstat);
3314 
3315         if ((returnstat = pa_ace_flags(context, &ace, returnstat, 0)) != 0)
3316                 return (returnstat);
3317         /* pa_ace_who can returns 1 if uid/gid is not found */
3318         if ((returnstat = pa_ace_who(context, &ace, returnstat, 0)) < 0)
3319                 return (returnstat);
3320         if ((returnstat = pa_ace_access_mask(context, ace.a_access_mask,
3321             returnstat, 0)) != 0)
3322                 return (returnstat);
3323         return (pa_ace_type(context, &ace, returnstat, flag));
3324 }
3325 
3326 int
3327 pa_access_mask(pr_context_t *context, int status, int flag)
3328 {
3329         int returnstat;
3330         uint32_t mask;
3331 
3332         if (status < 0)
3333                 return (status);
3334 
3335         returnstat = pr_adr_u_int32(context, &mask, 1);
3336         return (pa_ace_access_mask(context, mask, returnstat, flag));
3337 }
3338 
3339 int
3340 pa_wsid(pr_context_t *context, int status, int flag)
3341 {
3342         int returnstat;
3343         short length;
3344         char *sid;
3345         uval_t uval;
3346         char *name = NULL;
3347 
3348         if (status < 0)
3349                 return (status);
3350         if ((returnstat = open_tag(context, TAG_WSID)) != 0)
3351                 return (returnstat);
3352 
3353         if ((returnstat = pr_adr_short(context, &length, 1)) != 0)
3354                 return (returnstat);
3355         if ((sid = (char *)malloc(length + 1)) == NULL)
3356                 return (-1);
3357         if ((returnstat = pr_adr_char(context, sid, length)) != 0) {
3358                 free(sid);
3359                 return (returnstat);
3360         }
3361 
3362         uval.uvaltype = PRA_STRING;
3363         uval.string_val = sid;
3364         if ((context->format & PRF_RAWM) == 0) {
3365                 int rc;
3366                 int flag = IDMAP_REQ_FLG_USE_CACHE;
3367                 rc = idmap_getwinnamebysid(sid, flag, &name);
3368                 if (rc == IDMAP_SUCCESS)
3369                         uval.string_val = name;
3370                 else
3371                         (void) fprintf(stderr,
3372                             gettext("praudit: failed to map sid to name "
3373                             "rc=%d\n"), rc);
3374         }
3375         returnstat = pa_print(context, &uval, flag);
3376         free(sid);
3377         if (name != NULL)
3378                 free(name);
3379         if (returnstat == 0)
3380                 returnstat = close_tag(context, TAG_WSID);
3381         return (returnstat);
3382 }