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