Home | History | Annotate | Download | only in praudit
      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", "&amp;");
   1751 			break;
   1752 
   1753 		case '<':
   1754 			err = pr_printf(context, "%s", "&lt;");
   1755 			break;
   1756 
   1757 		case '>':
   1758 			err = pr_printf(context, "%s", "&gt;");
   1759 			break;
   1760 
   1761 		case '\"':
   1762 			err = pr_printf(context, "%s", "&quot;");
   1763 			break;
   1764 
   1765 		case '\'':
   1766 			err = pr_printf(context, "%s", "&apos;");
   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 }
   3322