xref: /illumos-gate/usr/src/cmd/praudit/format.c (revision 67dbe2be0c0f1e2eb428b89088bb5667e8f0b9f6)
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