xref: /titanic_41/usr/src/cmd/praudit/format.c (revision 1c42de6d020629af774dd9e9fc81be3f3ed9398e)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #define	_REENTRANT
29 
30 #include <ctype.h>
31 #include <errno.h>
32 #include <grp.h>
33 #include <libintl.h>
34 #include <netdb.h>
35 #include <time.h>
36 #include <pwd.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <wchar.h>
41 
42 #include <arpa/inet.h>
43 
44 #include <bsm/audit.h>
45 #include <bsm/audit_record.h>
46 #include <bsm/libbsm.h>
47 #include <security/pam_appl.h>
48 
49 #include <sys/inttypes.h>
50 #include <sys/mkdev.h>
51 #include <sys/types.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(ushort_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",
699 		major_32(dev_maj_min),
700 		minor_32(dev_maj_min),
701 		ipstring);
702 
703 	return (pa_print(context, &uval, flag));
704 }
705 
706 int
707 pa_tid32_ex(pr_context_t *context, int status, int flag)
708 {
709 	int		returnstat;
710 	int32_t		dev_maj_min;
711 	uint32_t	ip_addr[16];
712 	uint32_t	ip_type;
713 	struct in_addr	ia;
714 	char		*ipstring;
715 	char		hostname[256];
716 	char		buf[256];
717 	char		tbuf[256];
718 	uval_t		uval;
719 
720 	if (status <  0)
721 		return (status);
722 
723 	/* get port info */
724 	if ((returnstat = pr_adr_int32(context, &dev_maj_min, 1)) != 0)
725 		return (returnstat);
726 
727 	/* get address type */
728 	if ((returnstat = pr_adr_u_int32(context, &ip_type, 1)) != 0)
729 		return (returnstat);
730 
731 	/* legal address types are either AU_IPv4 or AU_IPv6 only */
732 	if ((ip_type != AU_IPv4) && (ip_type != AU_IPv6))
733 		return (-1);
734 
735 	/* get address (4/16) */
736 	if ((returnstat = pr_adr_char(context, (char *)ip_addr, ip_type)) != 0)
737 		return (returnstat);
738 
739 	uval.uvaltype = PRA_STRING;
740 	if (ip_type == AU_IPv4) {
741 		uval.string_val = buf;
742 
743 		if (!(context->format & PRF_RAWM)) {
744 			get_Hname(ip_addr[0], hostname, sizeof (hostname));
745 			(void) snprintf(buf, sizeof (buf), "%d %d %s",
746 				major_32(dev_maj_min),
747 				minor_32(dev_maj_min),
748 				hostname);
749 			return (pa_print(context, &uval, flag));
750 		}
751 
752 		ia.s_addr = ip_addr[0];
753 		if ((ipstring = inet_ntoa(ia)) == NULL)
754 			return (-1);
755 
756 		(void) snprintf(buf, sizeof (buf), "%d %d %s",
757 			major_32(dev_maj_min),
758 			minor_32(dev_maj_min),
759 			ipstring);
760 
761 		return (pa_print(context, &uval, flag));
762 	} else {
763 		uval.string_val = buf;
764 
765 		if (!(context->format & PRF_RAWM)) {
766 			get_Hname_ex(ip_addr, hostname, sizeof (hostname));
767 			(void) snprintf(buf, sizeof (buf), "%d %d %s",
768 				major_32(dev_maj_min),
769 				minor_32(dev_maj_min),
770 				hostname);
771 			return (pa_print(context, &uval, flag));
772 		}
773 
774 		(void) inet_ntop(AF_INET6, (void *) ip_addr, tbuf,
775 		    sizeof (tbuf));
776 
777 		(void) snprintf(buf, sizeof (buf), "%d %d %s",
778 			major_32(dev_maj_min),
779 			minor_32(dev_maj_min),
780 			tbuf);
781 
782 		return (pa_print(context, &uval, flag));
783 	}
784 }
785 
786 int
787 pa_ip_addr(pr_context_t *context, int status, int flag)
788 {
789 	int		returnstat;
790 	uval_t		uval;
791 	uint32_t	ip_addr[4];
792 	uint32_t	ip_type;
793 	struct in_addr	ia;
794 	char		*ipstring;
795 	char		hostname[256];
796 	char		buf[256];
797 	char		tbuf[256];
798 
799 	if (status <  0)
800 		return (status);
801 
802 	/* get address type */
803 	if ((returnstat = pr_adr_u_int32(context, &ip_type, 1)) != 0)
804 		return (returnstat);
805 
806 	/* legal address type is AU_IPv4 or AU_IPv6 */
807 	if ((ip_type != AU_IPv4) && (ip_type != AU_IPv6))
808 		return (-1);
809 
810 	/* get address (4/16) */
811 	if ((returnstat = pr_adr_char(context, (char *)ip_addr, ip_type)) != 0)
812 		return (returnstat);
813 
814 	uval.uvaltype = PRA_STRING;
815 	if (ip_type == AU_IPv4) {
816 		uval.string_val = buf;
817 
818 		if (!(context->format & PRF_RAWM)) {
819 			get_Hname(ip_addr[0], hostname, sizeof (hostname));
820 			(void) snprintf(buf, sizeof (buf), "%s",
821 				hostname);
822 			return (pa_print(context, &uval, flag));
823 		}
824 
825 		ia.s_addr = ip_addr[0];
826 		if ((ipstring = inet_ntoa(ia)) == NULL)
827 			return (-1);
828 
829 		(void) snprintf(buf, sizeof (buf), "%s",
830 			ipstring);
831 
832 		return (pa_print(context, &uval, flag));
833 	} else {
834 		uval.string_val = buf;
835 
836 		if (!(context->format & PRF_RAWM)) {
837 			get_Hname_ex(ip_addr, hostname, sizeof (hostname));
838 			(void) snprintf(buf, sizeof (buf), "%s",
839 			    hostname);
840 			return (pa_print(context, &uval, flag));
841 		}
842 
843 		(void) inet_ntop(AF_INET6, (void *) ip_addr, tbuf,
844 		    sizeof (tbuf));
845 
846 		(void) snprintf(buf, sizeof (buf), "%s", tbuf);
847 
848 		return (pa_print(context, &uval, flag));
849 	}
850 
851 }
852 
853 int
854 pa_tid64(pr_context_t *context, int status, int flag)
855 {
856 	int	returnstat;
857 	int64_t dev_maj_min;
858 	uint32_t	ip_addr;
859 	struct in_addr ia;
860 	char	*ipstring;
861 	char	buf[256];
862 	uval_t	uval;
863 
864 	if (status <  0)
865 		return (status);
866 
867 	if ((returnstat = pr_adr_int64(context, &dev_maj_min, 1)) != 0)
868 		return (returnstat);
869 
870 	if ((returnstat = pr_adr_char(context, (char *)&ip_addr, 4)) != 0)
871 		return (returnstat);
872 
873 	uval.uvaltype = PRA_STRING;
874 	uval.string_val = buf;
875 
876 	if (!(context->format & PRF_RAWM)) {
877 		char	hostname[256];
878 
879 		get_Hname(ip_addr, hostname, sizeof (hostname));
880 		(void) snprintf(buf, sizeof (buf), "%d %d %s",
881 			major_64(dev_maj_min),
882 			minor_64(dev_maj_min),
883 			hostname);
884 		return (pa_print(context, &uval, flag));
885 	}
886 
887 	ia.s_addr = ip_addr;
888 	if ((ipstring = inet_ntoa(ia)) == NULL)
889 		return (-1);
890 
891 	(void) snprintf(buf, sizeof (buf), "%d %d %s",
892 		major_64(dev_maj_min),
893 		minor_64(dev_maj_min),
894 		ipstring);
895 
896 	return (pa_print(context, &uval, flag));
897 }
898 
899 int
900 pa_tid64_ex(pr_context_t *context, int status, int flag)
901 {
902 	int		returnstat;
903 	int64_t		dev_maj_min;
904 	uint32_t	ip_addr[4];
905 	uint32_t	ip_type;
906 	struct in_addr	ia;
907 	char		*ipstring;
908 	char		hostname[256];
909 	char		buf[256];
910 	char		tbuf[256];
911 	uval_t		uval;
912 
913 	if (status <  0)
914 		return (status);
915 
916 	/* get port info */
917 	if ((returnstat = pr_adr_int64(context, &dev_maj_min, 1)) != 0)
918 		return (returnstat);
919 
920 	/* get address type */
921 	if ((returnstat = pr_adr_u_int32(context, &ip_type, 1)) != 0)
922 		return (returnstat);
923 
924 	/* legal address types are either AU_IPv4 or AU_IPv6 only */
925 	if ((ip_type != AU_IPv4) && (ip_type != AU_IPv6))
926 		return (-1);
927 
928 	/* get address (4/16) */
929 	if ((returnstat = pr_adr_char(context, (char *)&ip_addr, ip_type)) != 0)
930 		return (returnstat);
931 
932 	uval.uvaltype = PRA_STRING;
933 	if (ip_type == AU_IPv4) {
934 		uval.string_val = buf;
935 
936 		if (!(context->format & PRF_RAWM)) {
937 			get_Hname(ip_addr[0], hostname, sizeof (hostname));
938 			uval.string_val = buf;
939 			(void) snprintf(buf, sizeof (buf), "%d %d %s",
940 				major_64(dev_maj_min),
941 				minor_64(dev_maj_min),
942 				hostname);
943 			return (pa_print(context, &uval, flag));
944 		}
945 
946 		ia.s_addr = ip_addr[0];
947 		if ((ipstring = inet_ntoa(ia)) == NULL)
948 			return (-1);
949 
950 		(void) snprintf(buf, sizeof (buf), "%d %d %s",
951 			major_64(dev_maj_min),
952 			minor_64(dev_maj_min),
953 			ipstring);
954 
955 		return (pa_print(context, &uval, flag));
956 	} else {
957 		uval.string_val = buf;
958 
959 		if (!(context->format & PRF_RAWM)) {
960 			get_Hname_ex(ip_addr, hostname, sizeof (hostname));
961 			(void) snprintf(buf, sizeof (buf), "%d %d %s",
962 				major_64(dev_maj_min),
963 				minor_64(dev_maj_min),
964 				hostname);
965 			return (pa_print(context, &uval, flag));
966 		}
967 
968 		(void) inet_ntop(AF_INET6, (void *)ip_addr, tbuf,
969 		    sizeof (tbuf));
970 
971 		(void) snprintf(buf, sizeof (buf), "%d %d %s",
972 			major_64(dev_maj_min),
973 			minor_64(dev_maj_min),
974 			tbuf);
975 
976 		return (pa_print(context, &uval, flag));
977 	}
978 }
979 
980 
981 /*
982  * ----------------------------------------------------------------
983  * findfieldwidth:
984  * Returns the field width based on the basic unit and print mode.
985  * This routine is called to determine the field width for the
986  * data items in the arbitrary data token where the tokens are
987  * to be printed in more than one line.  The field width can be
988  * found in the fwidth structure.
989  *
990  * Input parameters:
991  * basicunit	Can be one of AUR_CHAR, AUR_BYTE, AUR_SHORT,
992  *		AUR_INT32, or AUR_INT64
993  * howtoprint	Print mode. Can be one of AUP_BINARY, AUP_OCTAL,
994  *		AUP_DECIMAL, or AUP_HEX.
995  * ----------------------------------------------------------------
996  */
997 int
998 findfieldwidth(char basicunit, char howtoprint)
999 {
1000 	int	i, j;
1001 
1002 	for (i = 0; i < numwidthentries; i++) {
1003 		if (fwidth[i].basic_unit == basicunit) {
1004 			for (j = 0; j <= 4; j++) {
1005 				if (fwidth[i].pwidth[j].print_base ==
1006 					howtoprint)
1007 				return (fwidth[i].pwidth[j].field_width);
1008 			}
1009 			/*
1010 			 * if we got here, then we didn't get what we were after
1011 			 */
1012 			return (0);
1013 		}
1014 	}
1015 	/* if we got here, we didn't get what we wanted either */
1016 	return (0);
1017 }
1018 
1019 
1020 /*
1021  * -----------------------------------------------------------------------
1022  * pa_cmd: Retrieves the cmd item from the input stream.
1023  * return codes : -1 - error
1024  *		:  0 - successful
1025  * -----------------------------------------------------------------------
1026  */
1027 int
1028 pa_cmd(pr_context_t *context, int status, int flag)
1029 {
1030 	char	*cmd;  /* cmd */
1031 	short	length;
1032 	int	returnstat;
1033 	uval_t	uval;
1034 
1035 	/*
1036 	 * We need to know how much space to allocate for our string, so
1037 	 * read the length first, then call pr_adr_char to read those bytes.
1038 	 */
1039 	if (status >= 0) {
1040 		if (pr_adr_short(context, &length, 1) == 0) {
1041 			if ((cmd = (char *)malloc(length + 1)) == NULL)
1042 				return (-1);
1043 			if (pr_adr_char(context, cmd, length) == 0) {
1044 				uval.uvaltype = PRA_STRING;
1045 				uval.string_val = cmd;
1046 				returnstat = pa_print(context, &uval, flag);
1047 			} else {
1048 				returnstat = -1;
1049 			}
1050 			free(cmd);
1051 			return (returnstat);
1052 		} else
1053 			return (-1);
1054 	} else
1055 		return (status);
1056 }
1057 
1058 
1059 
1060 /*
1061  * -----------------------------------------------------------------------
1062  * pa_adr_byte	: Issues pr_adr_char to retrieve the next ADR item from
1063  *		  the input stream pointed to by audit_adr, and prints it
1064  *		  as an integer if status >= 0
1065  * return codes : -1 - error
1066  *		:  0 - successful
1067  * -----------------------------------------------------------------------
1068  */
1069 int
1070 pa_adr_byte(pr_context_t *context, int status, int flag)
1071 {
1072 	char	c;
1073 	uval_t	uval;
1074 
1075 	if (status >= 0) {
1076 		if (pr_adr_char(context, &c, 1) == 0) {
1077 			uval.uvaltype = PRA_BYTE;
1078 			uval.char_val = c;
1079 			return (pa_print(context, &uval, flag));
1080 		} else
1081 			return (-1);
1082 	} else
1083 		return (status);
1084 }
1085 
1086 /*
1087  * -----------------------------------------------------------------------
1088  * pa_adr_charhex: Issues pr_adr_char to retrieve the next ADR item from
1089  *			the input stream pointed to by audit_adr, and prints it
1090  *			in hexadecimal if status >= 0
1091  * return codes  : -1 - error
1092  *		 :  0 - successful
1093  * -----------------------------------------------------------------------
1094  */
1095 int
1096 pa_adr_charhex(pr_context_t *context, int status, int flag)
1097 {
1098 	char	p[2];
1099 	int	returnstat;
1100 	uval_t	uval;
1101 
1102 	if (status >= 0) {
1103 		p[0] = p[1] = 0;
1104 
1105 		if ((returnstat = pr_adr_char(context, p, 1)) == 0) {
1106 			uval.uvaltype = PRA_STRING;
1107 			uval.string_val = hexconvert(p, sizeof (char),
1108 			    sizeof (char));
1109 			if (uval.string_val) {
1110 				returnstat = pa_print(context, &uval, flag);
1111 				free(uval.string_val);
1112 			}
1113 		}
1114 		return (returnstat);
1115 	} else
1116 		return (status);
1117 }
1118 
1119 /*
1120  * -----------------------------------------------------------------------
1121  * pa_adr_int32	: Issues pr_adr_int32 to retrieve the next ADR item from the
1122  *		  input stream pointed to by audit_adr, and prints it
1123  *		  if status >= 0
1124  * return codes : -1 - error
1125  *		:  0 - successful
1126  * -----------------------------------------------------------------------
1127  */
1128 int
1129 pa_adr_int32(pr_context_t *context, int status, int flag)
1130 {
1131 	int32_t	c;
1132 	uval_t	uval;
1133 
1134 	if (status >= 0) {
1135 		if (pr_adr_int32(context, &c, 1) == 0) {
1136 			uval.uvaltype = PRA_INT32;
1137 			uval.int32_val = c;
1138 			return (pa_print(context, &uval, flag));
1139 		} else
1140 			return (-1);
1141 	} else
1142 		return (status);
1143 }
1144 
1145 
1146 
1147 
1148 /*
1149  * -----------------------------------------------------------------------
1150  * pa_adr_int64	: Issues pr_adr_int64 to retrieve the next ADR item from the
1151  *		  input stream pointed to by audit_adr, and prints it
1152  *		  if status >= 0
1153  * return codes : -1 - error
1154  *		:  0 - successful
1155  * -----------------------------------------------------------------------
1156  */
1157 int
1158 pa_adr_int64(pr_context_t *context, int status, int flag)
1159 {
1160 	int64_t	c;
1161 	uval_t	uval;
1162 
1163 	if (status >= 0) {
1164 		if (pr_adr_int64(context, &c, 1) == 0) {
1165 			uval.uvaltype = PRA_INT64;
1166 			uval.int64_val = c;
1167 			return (pa_print(context, &uval, flag));
1168 		} else
1169 			return (-1);
1170 	} else
1171 		return (status);
1172 }
1173 
1174 /*
1175  * -----------------------------------------------------------------------
1176  * pa_adr_int64hex: Issues pr_adr_int64 to retrieve the next ADR item from the
1177  *			input stream pointed to by audit_adr, and prints it
1178  *			in hexadecimal if status >= 0
1179  * return codes  : -1 - error
1180  *		:  0 - successful
1181  * -----------------------------------------------------------------------
1182  */
1183 int
1184 pa_adr_int32hex(pr_context_t *context, int status, int flag)
1185 {
1186 	int32_t	l;
1187 	int	returnstat;
1188 	uval_t	uval;
1189 
1190 	if (status >= 0) {
1191 		if ((returnstat = pr_adr_int32(context, &l, 1)) == 0) {
1192 			uval.uvaltype = PRA_HEX32;
1193 			uval.int32_val = l;
1194 			returnstat = pa_print(context, &uval, flag);
1195 		}
1196 		return (returnstat);
1197 	} else
1198 		return (status);
1199 }
1200 
1201 /*
1202  * -----------------------------------------------------------------------
1203  * pa_adr_int64hex: Issues pr_adr_int64 to retrieve the next ADR item from the
1204  *			input stream pointed to by audit_adr, and prints it
1205  *			in hexadecimal if status >= 0
1206  * return codes  : -1 - error
1207  *		:  0 - successful
1208  * -----------------------------------------------------------------------
1209  */
1210 int
1211 pa_adr_int64hex(pr_context_t *context, int status, int flag)
1212 {
1213 	int64_t	l;
1214 	int	returnstat;
1215 	uval_t	uval;
1216 
1217 	if (status >= 0) {
1218 		if ((returnstat = pr_adr_int64(context, &l, 1)) == 0) {
1219 			uval.uvaltype = PRA_HEX64;
1220 			uval.int64_val = l;
1221 			returnstat = pa_print(context, &uval, flag);
1222 		}
1223 		return (returnstat);
1224 	} else
1225 		return (status);
1226 }
1227 
1228 
1229 /*
1230  * -------------------------------------------------------------------
1231  * bu2string: Maps a print basic unit type to a string.
1232  * returns  : The string mapping or "unknown basic unit type".
1233  * -------------------------------------------------------------------
1234  */
1235 char *
1236 bu2string(char basic_unit)
1237 {
1238 	register int	i;
1239 
1240 	struct bu_map_ent {
1241 		char	basic_unit;
1242 		char	*string;
1243 	};
1244 
1245 	/*
1246 	 * TRANSLATION_NOTE
1247 	 * These names are data units when displaying the arbitrary data
1248 	 * token.
1249 	 */
1250 
1251 	static struct bu_map_ent bu_map[] = {
1252 				{ AUR_BYTE, "byte" },
1253 				{ AUR_CHAR, "char" },
1254 				{ AUR_SHORT, "short" },
1255 				{ AUR_INT32, "int32" },
1256 				{ AUR_INT64, "int64" } 	};
1257 
1258 	for (i = 0; i < sizeof (bu_map) / sizeof (struct bu_map_ent); i++)
1259 		if (basic_unit == bu_map[i].basic_unit)
1260 			return (gettext(bu_map[i].string));
1261 
1262 	return (gettext("unknown basic unit type"));
1263 }
1264 
1265 
1266 /*
1267  * -------------------------------------------------------------------
1268  * eventmodifier2string: Maps event modifier flags to a readable string.
1269  * returns: The string mapping or "none".
1270  * -------------------------------------------------------------------
1271  */
1272 static void
1273 eventmodifier2string(ushort_t emodifier, char *modstring, size_t modlen)
1274 {
1275 	register int	i, j;
1276 
1277 	struct em_map_ent {
1278 		int	mask;
1279 		char	*string;
1280 	};
1281 
1282 	/*
1283 	 * TRANSLATION_NOTE
1284 	 * These abbreviations represent the event modifier field of the
1285 	 * header token.  To gain a better understanding of each modifier,
1286 	 * read the SunShield BSM Guide, part no. 802-1965-xx.
1287 	 */
1288 
1289 	static struct em_map_ent em_map[] = {
1290 		{ (int)PAD_READ,	"rd" },	/* data read from object */
1291 		{ (int)PAD_WRITE,	"wr" },	/* data written to object */
1292 		{ (int)PAD_SPRIVUSE,	"sp" },	/* successfully used priv */
1293 		{ (int)PAD_FPRIVUSE,	"fp" },	/* failed use of priv */
1294 		{ (int)PAD_NONATTR,	"na" },	/* non-attributable event */
1295 		{ (int)PAD_FAILURE,	"fe" }	/* fail audit event */
1296 	};
1297 
1298 	modstring[0] = '\0';
1299 
1300 	for (i = 0, j = 0; i < sizeof (em_map) / sizeof (struct em_map_ent);
1301 	    i++) {
1302 		if ((int)emodifier & em_map[i].mask) {
1303 			if (j++)
1304 				(void) strlcat(modstring, ":", modlen);
1305 			(void) strlcat(modstring, em_map[i].string, modlen);
1306 		}
1307 	}
1308 }
1309 
1310 
1311 /*
1312  * ---------------------------------------------------------
1313  * convert_char_to_string:
1314  *   Converts a byte to string depending on the print mode
1315  * input	: printmode, which may be one of AUP_BINARY,
1316  *		  AUP_OCTAL, AUP_DECIMAL, and AUP_HEX
1317  *		  c, which is the byte to convert
1318  * output	: p, which is a pointer to the location where
1319  *		  the resulting string is to be stored
1320  *  ----------------------------------------------------------
1321  */
1322 
1323 int
1324 convert_char_to_string(char printmode, char c, char *p)
1325 {
1326 	union {
1327 		char	c1[4];
1328 		int	c2;
1329 	} dat;
1330 
1331 	dat.c2 = 0;
1332 	dat.c1[3] = c;
1333 
1334 	if (printmode == AUP_BINARY)
1335 		(void) convertbinary(p, &c, sizeof (char));
1336 	else if (printmode == AUP_OCTAL)
1337 		(void) sprintf(p, "%o", (int)dat.c2);
1338 	else if (printmode == AUP_DECIMAL)
1339 		(void) sprintf(p, "%d", c);
1340 	else if (printmode == AUP_HEX)
1341 		(void) sprintf(p, "0x%x", (int)dat.c2);
1342 	else if (printmode == AUP_STRING)
1343 		convertascii(p, &c, sizeof (char));
1344 	return (0);
1345 }
1346 
1347 /*
1348  * --------------------------------------------------------------
1349  * convert_short_to_string:
1350  * Converts a short integer to string depending on the print mode
1351  * input	: printmode, which may be one of AUP_BINARY,
1352  *		AUP_OCTAL, AUP_DECIMAL, and AUP_HEX
1353  *		c, which is the short integer to convert
1354  * output	: p, which is a pointer to the location where
1355  *		the resulting string is to be stored
1356  * ---------------------------------------------------------------
1357  */
1358 int
1359 convert_short_to_string(char printmode, short c, char *p)
1360 {
1361 	union {
1362 		short	c1[2];
1363 		int	c2;
1364 	} dat;
1365 
1366 	dat.c2 = 0;
1367 	dat.c1[1] = c;
1368 
1369 	if (printmode == AUP_BINARY)
1370 		(void) convertbinary(p, (char *)&c, sizeof (short));
1371 	else if (printmode == AUP_OCTAL)
1372 		(void) sprintf(p, "%o", (int)dat.c2);
1373 	else if (printmode == AUP_DECIMAL)
1374 		(void) sprintf(p, "%hd", c);
1375 	else if (printmode == AUP_HEX)
1376 		(void) sprintf(p, "0x%x", (int)dat.c2);
1377 	else if (printmode == AUP_STRING)
1378 		convertascii(p, (char *)&c, sizeof (short));
1379 	return (0);
1380 }
1381 
1382 /*
1383  * ---------------------------------------------------------
1384  * convert_int32_to_string:
1385  * Converts a integer to string depending on the print mode
1386  * input	: printmode, which may be one of AUP_BINARY,
1387  *		AUP_OCTAL, AUP_DECIMAL, and AUP_HEX
1388  *		c, which is the integer to convert
1389  * output	: p, which is a pointer to the location where
1390  *		the resulting string is to be stored
1391  * ----------------------------------------------------------
1392  */
1393 int
1394 convert_int32_to_string(char printmode, int32_t c, char *p)
1395 {
1396 	if (printmode == AUP_BINARY)
1397 		(void) convertbinary(p, (char *)&c, sizeof (int32_t));
1398 	else if (printmode == AUP_OCTAL)
1399 		(void) sprintf(p, "%o", c);
1400 	else if (printmode == AUP_DECIMAL)
1401 		(void) sprintf(p, "%d", c);
1402 	else if (printmode == AUP_HEX)
1403 		(void) sprintf(p, "0x%x", c);
1404 	else if (printmode == AUP_STRING)
1405 		convertascii(p, (char *)&c, sizeof (int));
1406 	return (0);
1407 }
1408 
1409 /*
1410  * ---------------------------------------------------------
1411  * convert_int64_to_string:
1412  * Converts a integer to string depending on the print mode
1413  * input	: printmode, which may be one of AUP_BINARY,
1414  *		AUP_OCTAL, AUP_DECIMAL, and AUP_HEX
1415  *		c, which is the integer to convert
1416  * output	: p, which is a pointer to the location where
1417  *		the resulting string is to be stored
1418  * ----------------------------------------------------------
1419  */
1420 int
1421 convert_int64_to_string(char printmode, int64_t c, char *p)
1422 {
1423 	if (printmode == AUP_BINARY)
1424 		(void) convertbinary(p, (char *)&c, sizeof (int64_t));
1425 	else if (printmode == AUP_OCTAL)
1426 		(void) sprintf(p, "%"PRIo64, c);
1427 	else if (printmode == AUP_DECIMAL)
1428 		(void) sprintf(p, "%"PRId64, c);
1429 	else if (printmode == AUP_HEX)
1430 		(void) sprintf(p, "0x%"PRIx64, c);
1431 	else if (printmode == AUP_STRING)
1432 		convertascii(p, (char *)&c, sizeof (int64_t));
1433 	return (0);
1434 }
1435 
1436 
1437 /*
1438  * -----------------------------------------------------------
1439  * convertbinary:
1440  * Converts a unit c of 'size' bytes long into a binary string
1441  * and returns it into the position pointed to by p
1442  * ------------------------------------------------------------
1443  */
1444 int
1445 convertbinary(char *p, char *c, int size)
1446 {
1447 	char	*s, *t, *ss;
1448 	int	i, j;
1449 
1450 	if ((s = (char *)malloc(8 * size + 1)) == NULL)
1451 		return (0);
1452 
1453 	ss = s;
1454 
1455 	/* first convert to binary */
1456 	t = s;
1457 	for (i = 0; i < size; i++) {
1458 		for (j = 0; j < 8; j++)
1459 			(void) sprintf(t++, "%d", ((*c >> (7 - j)) & (0x01)));
1460 		c++;
1461 	}
1462 	*t = '\0';
1463 
1464 	/* now string leading zero's if any */
1465 	j = strlen(s) - 1;
1466 	for (i = 0; i < j; i++) {
1467 		if (*s != '0')
1468 			break;
1469 			else
1470 			s++;
1471 	}
1472 
1473 	/* now copy the contents of s to p */
1474 	t = p;
1475 	for (i = 0; i < (8 * size + 1); i++) {
1476 		if (*s == '\0') {
1477 			*t = '\0';
1478 			break;
1479 		}
1480 		*t++ = *s++;
1481 	}
1482 	free(ss);
1483 
1484 	return (1);
1485 }
1486 
1487 
1488 static char hex[] = "0123456789abcdef";
1489 /*
1490  * -------------------------------------------------------------------
1491  * hexconvert	: Converts a string of (size) bytes to hexadecimal, and
1492  *		returns the hexadecimal string.
1493  * returns	: - NULL if memory cannot be allocated for the string, or
1494  *		- pointer to the hexadecimal string if successful
1495  * -------------------------------------------------------------------
1496  */
1497 char *
1498 hexconvert(char *c, int size, int chunk)
1499 {
1500 	register char	*s, *t;
1501 	register int	i, j, k;
1502 	int	numchunks;
1503 	int	leftovers;
1504 
1505 	if (size <= 0)
1506 		return (NULL);
1507 
1508 	if ((s = (char *)malloc((size * 5) + 1)) == NULL)
1509 		return (NULL);
1510 
1511 	if (chunk > size || chunk <= 0)
1512 		chunk = size;
1513 
1514 	numchunks = size / chunk;
1515 	leftovers = size % chunk;
1516 
1517 	t = s;
1518 	for (i = j = 0; i < numchunks; i++) {
1519 		if (j++) {
1520 			*t++ = ' ';
1521 		}
1522 		*t++ = '0';
1523 		*t++ = 'x';
1524 		for (k = 0; k < chunk; k++) {
1525 			*t++ = hex[(uint_t)((uchar_t)*c >> 4)];
1526 			*t++ = hex[(uint_t)((uchar_t)*c & 0xF)];
1527 			c++;
1528 		}
1529 	}
1530 
1531 	if (leftovers) {
1532 		*t++ = ' ';
1533 		*t++ = '0';
1534 		*t++ = 'x';
1535 		for (i = 0; i < leftovers; i++) {
1536 			*t++ = hex[(uint_t)((uchar_t)*c >> 4)];
1537 			*t++ = hex[(uint_t)((uchar_t)*c & 0xF)];
1538 			c++;
1539 		}
1540 	}
1541 
1542 	*t = '\0';
1543 	return (s);
1544 }
1545 
1546 
1547 /*
1548  * -------------------------------------------------------------------
1549  * htp2string: Maps a print suggestion to a string.
1550  * returns   : The string mapping or "unknown print suggestion".
1551  * -------------------------------------------------------------------
1552  */
1553 char *
1554 htp2string(char print_sugg)
1555 {
1556 	register int	i;
1557 
1558 	struct htp_map_ent {
1559 		char	print_sugg;
1560 		char	*print_string;
1561 	};
1562 
1563 	/*
1564 	 * TRANSLATION_NOTE
1565 	 * These names are data types when displaying the arbitrary data
1566 	 * token.
1567 	 */
1568 
1569 	static struct htp_map_ent htp_map[] = {
1570 				{ AUP_BINARY, "binary" },
1571 				{ AUP_OCTAL, "octal" },
1572 				{ AUP_DECIMAL, "decimal" },
1573 				{ AUP_HEX, "hexadecimal" },
1574 				{ AUP_STRING, "string" } 	};
1575 
1576 	for (i = 0; i < sizeof (htp_map) / sizeof (struct htp_map_ent); i++)
1577 		if (print_sugg == htp_map[i].print_sugg)
1578 			return (gettext(htp_map[i].print_string));
1579 
1580 	return (gettext("unknown print suggestion"));
1581 }
1582 
1583 /*
1584  * ----------------------------------------------------------------------
1585  * pa_adr_short: Issues pr_adr_short to retrieve the next ADR item from the
1586  *		input stream pointed to by audit_adr, and prints it
1587  *		if status >= 0
1588  * return codes: -1 - error
1589  *		:  0 - successful
1590  * ----------------------------------------------------------------------
1591  */
1592 int
1593 pa_adr_short(pr_context_t *context, int status, int flag)
1594 {
1595 	short	c;
1596 	uval_t	uval;
1597 
1598 	if (status >= 0) {
1599 		if (pr_adr_short(context, &c, 1) == 0) {
1600 			uval.uvaltype = PRA_SHORT;
1601 			uval.short_val = c;
1602 			return (pa_print(context, &uval, flag));
1603 		} else
1604 			return (-1);
1605 	} else
1606 		return (status);
1607 }
1608 
1609 /*
1610  * -----------------------------------------------------------------------
1611  * pa_adr_shorthex: Issues pr_adr_short to retrieve the next ADR item from the
1612  *			input stream pointed to by audit_adr, and prints it
1613  *			in hexadecimal if status >= 0
1614  * return codes  : -1 - error
1615  *		:  0 - successful
1616  * -----------------------------------------------------------------------
1617  */
1618 int
1619 pa_adr_shorthex(pr_context_t *context, int status, int flag)
1620 {
1621 	short	s;
1622 	int	returnstat;
1623 	uval_t	uval;
1624 
1625 	if (status >= 0) {
1626 		if ((returnstat = pr_adr_short(context, &s, 1)) == 0) {
1627 			uval.uvaltype = PRA_STRING;
1628 			uval.string_val = hexconvert((char *)&s, sizeof (s),
1629 			    sizeof (s));
1630 			if (uval.string_val) {
1631 				returnstat = pa_print(context, &uval, flag);
1632 				free(uval.string_val);
1633 			}
1634 		}
1635 		return (returnstat);
1636 	} else
1637 		return (status);
1638 }
1639 
1640 
1641 /*
1642  * -----------------------------------------------------------------------
1643  * pa_adr_string: Retrieves a string from the input stream and prints it
1644  *		  if status >= 0
1645  * return codes : -1 - error
1646  *		:  0 - successful
1647  * -----------------------------------------------------------------------
1648  */
1649 int
1650 pa_adr_string(pr_context_t *context, int status, int flag)
1651 {
1652 	char	*c;
1653 	char	*p;
1654 	short	length;
1655 	int	returnstat;
1656 	uval_t	uval;
1657 
1658 	/*
1659 	 * We need to know how much space to allocate for our string, so
1660 	 * read the length first, then call pr_adr_char to read those bytes.
1661 	 */
1662 	if (status < 0)
1663 		return (status);
1664 
1665 	if ((returnstat = pr_adr_short(context, &length, 1)) != 0)
1666 		return (returnstat);
1667 	if ((c = (char *)malloc(length + 1)) == NULL)
1668 		return (-1);
1669 	if ((p = (char *)malloc((length * 2) + 1)) == NULL) {
1670 		free(c);
1671 		return (-1);
1672 	}
1673 	if ((returnstat = pr_adr_char(context, c, length)) != 0) {
1674 		free(c);
1675 		free(p);
1676 		return (returnstat);
1677 	}
1678 	convertascii(p, c, length - 1);
1679 	uval.uvaltype = PRA_STRING;
1680 	uval.string_val = p;
1681 	returnstat = pa_print(context, &uval, flag);
1682 	free(c);
1683 	free(p);
1684 	return (returnstat);
1685 }
1686 
1687 /*
1688  * -----------------------------------------------------------------------
1689  * pa_file_string: Retrieves a file string from the input stream and prints it
1690  *		  if status >= 0
1691  * return codes : -1 - error
1692  *		:  0 - successful
1693  * -----------------------------------------------------------------------
1694  */
1695 int
1696 pa_file_string(pr_context_t *context, int status, int flag)
1697 {
1698 	char	*c;
1699 	char	*p;
1700 	short	length;
1701 	int	returnstat;
1702 	uval_t	uval;
1703 
1704 	/*
1705 	 * We need to know how much space to allocate for our string, so
1706 	 * read the length first, then call pr_adr_char to read those bytes.
1707 	 */
1708 	if (status < 0)
1709 		return (status);
1710 
1711 	if ((returnstat = pr_adr_short(context, &length, 1)) != 0)
1712 		return (returnstat);
1713 	if ((c = (char *)malloc(length + 1)) == NULL)
1714 		return (-1);
1715 	if ((p = (char *)malloc((length * 2) + 1)) == NULL) {
1716 		free(c);
1717 		return (-1);
1718 	}
1719 	if ((returnstat = pr_adr_char(context, c, length)) != 0) {
1720 		free(c);
1721 		free(p);
1722 		return (returnstat);
1723 	}
1724 
1725 	if (is_file_token(context->tokenid))
1726 		context->audit_rec_len += length;
1727 
1728 	convertascii(p, c, length - 1);
1729 	uval.uvaltype = PRA_STRING;
1730 	uval.string_val = p;
1731 
1732 	if (returnstat == 0)
1733 		returnstat = finish_open_tag(context);
1734 
1735 	if (returnstat == 0)
1736 		returnstat = pa_print(context, &uval, flag);
1737 
1738 	free(c);
1739 	free(p);
1740 	return (returnstat);
1741 }
1742 
1743 static int
1744 pa_putstr_xml(pr_context_t *context, int printable, char *str, size_t len)
1745 {
1746 	int	err;
1747 
1748 	if (!printable) {
1749 		/*
1750 		 * Unprintable chars should always be converted to the
1751 		 * visible form. If there are unprintable characters which
1752 		 * require special treatment in xml, those should be
1753 		 * handled here.
1754 		 */
1755 		do {
1756 			err = pr_printf(context, "\\%03o",
1757 				(unsigned char)*str++);
1758 		} while (err == 0 && --len != 0);
1759 		return (err);
1760 	}
1761 	/* printable characters */
1762 	if (len == 1) {
1763 		/*
1764 		 * check for the special chars only when char size was 1
1765 		 * ie, ignore special chars appear in the middle of multibyte
1766 		 * sequence.
1767 		 */
1768 
1769 		/* Escape for XML */
1770 		switch (*str) {
1771 		case '&':
1772 			err = pr_printf(context, "%s", "&amp;");
1773 			break;
1774 
1775 		case '<':
1776 			err = pr_printf(context, "%s", "&lt;");
1777 			break;
1778 
1779 		case '>':
1780 			err = pr_printf(context, "%s", "&gt;");
1781 			break;
1782 
1783 		case '\"':
1784 			err = pr_printf(context, "%s", "&quot;");
1785 			break;
1786 
1787 		case '\'':
1788 			err = pr_printf(context, "%s", "&apos;");
1789 			break;
1790 
1791 		default:
1792 			err = pr_putchar(context, *str);
1793 			break;
1794 		}
1795 		return (err);
1796 	}
1797 	do {
1798 		err = pr_putchar(context, *str++);
1799 	} while (err == 0 && --len != 0);
1800 	return (err);
1801 }
1802 
1803 static int
1804 pa_putstr(pr_context_t *context, int printable, char *str, size_t len)
1805 {
1806 	int	err;
1807 
1808 	if (context->format & PRF_XMLM)
1809 		return (pa_putstr_xml(context, printable, str, len));
1810 
1811 	if (!printable) {
1812 		do {
1813 			err = pr_printf(context, "\\%03o",
1814 				(unsigned char)*str++);
1815 		} while (err == 0 && --len != 0);
1816 		return (err);
1817 	}
1818 	do {
1819 		err = pr_putchar(context, *str++);
1820 	} while (err == 0 && --len != 0);
1821 	return (err);
1822 }
1823 
1824 int
1825 pa_string(pr_context_t *context, int status, int flag)
1826 {
1827 	int	rstat, wstat;
1828 	int	i, printable, eos;
1829 	int	mlen, rlen;
1830 	int	mbmax = MB_CUR_MAX;
1831 	wchar_t	wc;
1832 	char	mbuf[MB_LEN_MAX + 1];
1833 	char	c;
1834 
1835 	if (status < 0)
1836 		return (status);
1837 
1838 	rstat = wstat = 0;
1839 
1840 	if (mbmax == 1) {
1841 		while (wstat == 0) {
1842 			if ((rstat = pr_adr_char(context, &c, 1)) < 0)
1843 				break;
1844 			if (c == '\0')
1845 				break;
1846 			printable = isprint((unsigned char)c);
1847 			wstat = pa_putstr(context, printable, &c, 1);
1848 		}
1849 		goto done;
1850 	}
1851 
1852 	mlen = eos = 0;
1853 	while (wstat == 0) {
1854 		rlen = 0;
1855 		do {
1856 			if (!eos) {
1857 				rstat = pr_adr_char(context, &c, 1);
1858 				if (rstat != 0 || c == '\0')
1859 					eos = 1;
1860 				else
1861 					mbuf[mlen++] = c;
1862 			}
1863 			rlen = mbtowc(&wc, mbuf, mlen);
1864 		} while (!eos && mlen < mbmax && rlen <= 0);
1865 
1866 		if (mlen == 0)
1867 			break;	/* end of string */
1868 
1869 		if (rlen <= 0) { /* no good sequence */
1870 			rlen = 1;
1871 			printable = 0;
1872 		} else {
1873 			printable = iswprint(wc);
1874 		}
1875 		wstat = pa_putstr(context, printable, mbuf, rlen);
1876 		mlen -= rlen;
1877 		if (mlen > 0) {
1878 			for (i = 0; i < mlen; i++)
1879 				mbuf[i] = mbuf[rlen + i];
1880 		}
1881 	}
1882 
1883 done:
1884 	if (wstat == 0)
1885 		wstat = do_newline(context, flag);
1886 
1887 	if (wstat == 0 && context->data_mode == FILEMODE)
1888 		(void) fflush(stdout);
1889 
1890 	return ((rstat != 0 || wstat != 0) ? -1 : 0);
1891 }
1892 
1893 /*
1894  * -----------------------------------------------------------------------
1895  * pa_adr_u_int32: Issues pr_adr_u_int32 to retrieve the next ADR item from
1896  *		  the input stream pointed to by audit_adr, and prints it
1897  *		  if status = 0
1898  * return codes : -1 - error
1899  *		:  0 - successful
1900  * -----------------------------------------------------------------------
1901  */
1902 
1903 
1904 int
1905 pa_adr_u_int32(pr_context_t *context, int status, int flag)
1906 {
1907 	uint32_t c;
1908 	uval_t	uval;
1909 
1910 	if (status >= 0) {
1911 		if (pr_adr_u_int32(context, &c, 1) == 0) {
1912 			uval.uvaltype = PRA_UINT32;
1913 			uval.uint32_val = c;
1914 			return (pa_print(context, &uval, flag));
1915 		} else
1916 			return (-1);
1917 	} else
1918 		return (status);
1919 }
1920 
1921 
1922 
1923 /*
1924  * -----------------------------------------------------------------------
1925  * pa_adr_u_int64: Issues pr_adr_u_int64 to retrieve the next ADR item from the
1926  *		  input stream pointed to by audit_adr, and prints it
1927  *		  if status = 0
1928  * return codes : -1 - error
1929  *		:  0 - successful
1930  * -----------------------------------------------------------------------
1931  */
1932 int
1933 pa_adr_u_int64(pr_context_t *context, int status, int flag)
1934 {
1935 	uint64_t c;
1936 	uval_t	uval;
1937 
1938 	if (status >= 0) {
1939 		if (pr_adr_u_int64(context, &c, 1) == 0) {
1940 			uval.uvaltype = PRA_UINT64;
1941 			uval.uint64_val = c;
1942 			return (pa_print(context, &uval, flag));
1943 		} else
1944 			return (-1);
1945 	} else
1946 		return (status);
1947 }
1948 
1949 
1950 /*
1951  * -----------------------------------------------------------------------
1952  * pa_adr_u_short: Issues pr_adr_u_short to retrieve the next ADR item from
1953  *			the input stream pointed to by audit_adr, and prints it
1954  *			if status = 0
1955  * return codes : -1 - error
1956  *		:  0 - successful
1957  * -----------------------------------------------------------------------
1958  */
1959 int
1960 pa_adr_u_short(pr_context_t *context, int status, int flag)
1961 {
1962 	ushort_t c;
1963 	uval_t	uval;
1964 
1965 	if (status >= 0) {
1966 		if (pr_adr_u_short(context, &c, 1) == 0) {
1967 			uval.uvaltype = PRA_USHORT;
1968 			uval.ushort_val = c;
1969 			return (pa_print(context, &uval, flag));
1970 		} else
1971 			return (-1);
1972 	} else
1973 		return (status);
1974 }
1975 
1976 /*
1977  * -----------------------------------------------------------------------
1978  * pa_reclen: Issues pr_adr_u_long to retrieve the length of the record
1979  *		  from the input stream pointed to by audit_adr,
1980  *		  and prints it (unless format is XML) if status = 0
1981  * return codes : -1 - error
1982  *		:  0 - successful
1983  * -----------------------------------------------------------------------
1984  */
1985 int
1986 pa_reclen(pr_context_t *context, int status)
1987 {
1988 	uint32_t c;
1989 	uval_t	uval;
1990 
1991 	if (status >= 0) {
1992 		if ((int)pr_adr_u_int32(context, &c, 1) == 0) {
1993 			context->audit_rec_len = c;
1994 
1995 			/* Don't print this for XML format */
1996 			if (context->format & PRF_XMLM) {
1997 				return (0);
1998 			} else {
1999 				uval.uvaltype = PRA_UINT32;
2000 				uval.uint32_val = c;
2001 				return (pa_print(context, &uval, 0));
2002 			}
2003 		} else
2004 			return (-1);
2005 	} else
2006 		return (status);
2007 }
2008 
2009 /*
2010  * -----------------------------------------------------------------------
2011  * pa_mode	: Issues pr_adr_u_short to retrieve the next ADR item from
2012  *		the input stream pointed to by audit_adr, and prints it
2013  *		in octal if status = 0
2014  * return codes : -1 - error
2015  *		:  0 - successful
2016  * -----------------------------------------------------------------------
2017  */
2018 int
2019 pa_mode(pr_context_t *context, int status, int flag)
2020 {
2021 	uint32_t c;
2022 	uval_t	uval;
2023 
2024 	if (status >= 0) {
2025 		if (pr_adr_u_int32(context, &c, 1) == 0) {
2026 			uval.uvaltype = PRA_LOCT;
2027 			uval.uint32_val = c;
2028 			return (pa_print(context, &uval, flag));
2029 		} else
2030 			return (-1);
2031 	} else
2032 		return (status);
2033 }
2034 
2035 
2036 /*
2037  * -----------------------------------------------------------------------
2038  * pa_pw_uid()	: Issues pr_adr_u_int32 to reads uid from input stream
2039  *		pointed to by audit_adr, and displays it in either
2040  *		raw form or its ASCII representation, if status >= 0.
2041  * return codes : -1 - error
2042  * 		:  1 - warning, passwd entry not found
2043  *		:  0 - successful
2044  * -----------------------------------------------------------------------
2045  */
2046 int
2047 pa_pw_uid(pr_context_t *context, int status, int flag)
2048 {
2049 	int	returnstat;
2050 	struct passwd *pw;
2051 	uint32_t uid;
2052 	uval_t	uval;
2053 
2054 	if (status < 0)
2055 		return (status);
2056 
2057 	if (pr_adr_u_int32(context, &uid, 1) != 0)
2058 		/* cannot retrieve uid */
2059 		return (-1);
2060 
2061 	if (!(context->format & PRF_RAWM)) {
2062 		/* get password file entry */
2063 		if ((pw = getpwuid(uid)) == NULL) {
2064 			returnstat = 1;
2065 		} else {
2066 			/* print in ASCII form */
2067 			uval.uvaltype = PRA_STRING;
2068 			uval.string_val = pw->pw_name;
2069 			returnstat = pa_print(context, &uval, flag);
2070 		}
2071 	}
2072 	/* print in integer form */
2073 	if ((context->format & PRF_RAWM) || (returnstat == 1)) {
2074 		uval.uvaltype = PRA_INT32;
2075 		uval.int32_val = uid;
2076 		returnstat = pa_print(context, &uval, flag);
2077 	}
2078 	return (returnstat);
2079 }
2080 
2081 
2082 /*
2083  * -----------------------------------------------------------------------
2084  * pa_gr_uid()	: Issues pr_adr_u_int32 to reads group uid from input stream
2085  *			pointed to by audit_adr, and displays it in either
2086  *			raw form or its ASCII representation, if status >= 0.
2087  * return codes : -1 - error
2088  * 		:  1 - warning, passwd entry not found
2089  *		:  0 - successful
2090  * -----------------------------------------------------------------------
2091  */
2092 int
2093 pa_gr_uid(pr_context_t *context, int status, int flag)
2094 {
2095 	int	returnstat;
2096 	struct group *gr;
2097 	uint32_t gid;
2098 	uval_t	uval;
2099 
2100 	if (status < 0)
2101 		return (status);
2102 
2103 	if (pr_adr_u_int32(context, &gid, 1) != 0)
2104 		/* cannot retrieve gid */
2105 		return (-1);
2106 
2107 	if (!(context->format & PRF_RAWM)) {
2108 		/* get group file entry */
2109 		if ((gr = getgrgid(gid)) == NULL) {
2110 			returnstat = 1;
2111 		} else {
2112 			/* print in ASCII form */
2113 			uval.uvaltype = PRA_STRING;
2114 			uval.string_val = gr->gr_name;
2115 			returnstat = pa_print(context, &uval, flag);
2116 		}
2117 	}
2118 	/* print in integer form */
2119 	if ((context->format & PRF_RAWM) || (returnstat == 1)) {
2120 		uval.uvaltype = PRA_INT32;
2121 		uval.int32_val = gid;
2122 		returnstat = pa_print(context, &uval, flag);
2123 	}
2124 	return (returnstat);
2125 }
2126 
2127 
2128 /*
2129  * -----------------------------------------------------------------------
2130  * pa_pw_uid_gr_gid()	: Issues pr_adr_u_int32 to reads uid or group uid
2131  *			from input stream
2132  *			pointed to by audit_adr, and displays it in either
2133  *			raw form or its ASCII representation, if status >= 0.
2134  * return codes : -1 - error
2135  * 		:  1 - warning, passwd entry not found
2136  *		:  0 - successful
2137  * -----------------------------------------------------------------------
2138  */
2139 int
2140 pa_pw_uid_gr_gid(pr_context_t *context, int status, int flag)
2141 {
2142 	int	returnstat;
2143 	uint32_t	value;
2144 	uval_t		uval;
2145 
2146 	if (status < 0)
2147 		return (status);
2148 
2149 	/* get value of a_type */
2150 	if ((returnstat = pr_adr_u_int32(context, &value, 1)) != 0)
2151 		return (returnstat);
2152 
2153 	if ((returnstat = open_tag(context, TAG_ACLTYPE)) != 0)
2154 		return (returnstat);
2155 
2156 	uval.uvaltype = PRA_UINT32;
2157 	uval.uint32_val = value;
2158 	if ((returnstat = pa_print(context, &uval, flag)) != 0)
2159 		return (returnstat);
2160 
2161 	if ((returnstat = close_tag(context, TAG_ACLTYPE)) != 0)
2162 		return (returnstat);
2163 
2164 	if ((returnstat = open_tag(context, TAG_ACLVAL)) != 0)
2165 		return (returnstat);
2166 	/*
2167 	 * TRANSLATION_NOTE
2168 	 * The "mask" and "other" strings refer to the class mask
2169 	 * and other (or world) entries in an ACL.
2170 	 * The "unrecognized" string refers to an unrecognized ACL
2171 	 * entry.
2172 	 */
2173 	switch (value) {
2174 		case USER_OBJ:
2175 		case USER:
2176 			returnstat = pa_pw_uid(context, returnstat, flag);
2177 			break;
2178 		case GROUP_OBJ:
2179 		case GROUP:
2180 			returnstat = pa_gr_uid(context, returnstat, flag);
2181 			break;
2182 		case CLASS_OBJ:
2183 		    returnstat = pr_adr_u_int32(context, &value, 1);
2184 		    if (returnstat != 0)
2185 			return (returnstat);
2186 
2187 		    if (!(context->format & PRF_RAWM)) {
2188 			uval.uvaltype = PRA_STRING;
2189 			uval.string_val = gettext("mask");
2190 			returnstat = pa_print(context, &uval, flag);
2191 		    } else {
2192 			uval.uvaltype = PRA_UINT32;
2193 			uval.uint32_val = value;
2194 			if ((returnstat = pa_print(context, &uval, flag)) != 0)
2195 				return (returnstat);
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 = pa_print(context, &uval, flag)) != 0)
2211 				return (returnstat);
2212 		    }
2213 		    break;
2214 		default:
2215 		    returnstat = pr_adr_u_int32(context, &value, 1);
2216 		    if (returnstat != 0)
2217 			return (returnstat);
2218 
2219 		    if (!(context->format & PRF_RAWM)) {
2220 			uval.uvaltype = PRA_STRING;
2221 			uval.string_val = gettext("unrecognized");
2222 			returnstat = pa_print(context, &uval, flag);
2223 		    } else {
2224 			uval.uvaltype = PRA_UINT32;
2225 			uval.uint32_val = value;
2226 			if ((returnstat = pa_print(context, &uval, flag)) != 0)
2227 				return (returnstat);
2228 		    }
2229 	}
2230 
2231 	if ((returnstat = close_tag(context, TAG_ACLVAL)) != 0)
2232 		return (returnstat);
2233 
2234 	return (returnstat);
2235 }
2236 
2237 
2238 /*
2239  * -----------------------------------------------------------------------
2240  * pa_event_modifier(): Issues pr_adr_u_short to retrieve the next ADR item from
2241  *		  the input stream pointed to by audit_adr.  This is the
2242  *		  event type, and is displayed in hex;
2243  * return codes : -1 - error
2244  *		:  0 - successful
2245  * -----------------------------------------------------------------------
2246  */
2247 int
2248 pa_event_modifier(pr_context_t *context, int status,  int flag)
2249 {
2250 	int	returnstat;
2251 	ushort_t emodifier;
2252 	uval_t	uval;
2253 	char	modstring[64];
2254 
2255 	if (status < 0)
2256 		return (status);
2257 
2258 	if ((returnstat = pr_adr_u_short(context, &emodifier, 1)) != 0)
2259 		return (returnstat);
2260 
2261 	/* For XML, only print when modifier is non-zero */
2262 	if (!(context->format & PRF_XMLM) || (emodifier != 0)) {
2263 		uval.uvaltype = PRA_STRING;
2264 
2265 		returnstat = open_tag(context, TAG_EVMOD);
2266 
2267 		if (returnstat >= 0) {
2268 			if (!(context->format & PRF_RAWM)) {
2269 				eventmodifier2string(emodifier, modstring,
2270 				    sizeof (modstring));
2271 				uval.string_val = modstring;
2272 				returnstat = pa_print(context, &uval, flag);
2273 			} else {
2274 				uval.string_val = hexconvert((char *)&emodifier,
2275 				    sizeof (emodifier), sizeof (emodifier));
2276 				if (uval.string_val) {
2277 					returnstat = pa_print(context, &uval,
2278 					    flag);
2279 					free(uval.string_val);
2280 				}
2281 			}
2282 		}
2283 		if (returnstat >= 0)
2284 			returnstat = close_tag(context, TAG_EVMOD);
2285 	}
2286 
2287 	return (returnstat);
2288 }
2289 
2290 
2291 /*
2292  * -----------------------------------------------------------------------
2293  * pa_event_type(): Issues pr_adr_u_short to retrieve the next ADR item from
2294  *		  the input stream pointed to by audit_adr.  This is the
2295  *		  event type, and is displayed in either raw or
2296  *		  ASCII form as appropriate
2297  * return codes : -1 - error
2298  *		:  0 - successful
2299  * -----------------------------------------------------------------------
2300  */
2301 int
2302 pa_event_type(pr_context_t *context, int status,  int flag)
2303 {
2304 	ushort_t etype;
2305 	int	returnstat;
2306 	au_event_ent_t *p_event = NULL;
2307 	uval_t	uval;
2308 
2309 	if (status >= 0) {
2310 		if ((returnstat = pr_adr_u_short(context, &etype, 1)) == 0) {
2311 			if (!(context->format & PRF_RAWM)) {
2312 				uval.uvaltype = PRA_STRING;
2313 				if (context->format & PRF_NOCACHE) {
2314 					p_event = getauevnum(etype);
2315 				} else {
2316 					(void) cacheauevent(&p_event, etype);
2317 				}
2318 				if (p_event != NULL) {
2319 					if (context->format & PRF_SHORTM)
2320 						uval.string_val =
2321 						    p_event->ae_name;
2322 					else
2323 						uval.string_val =
2324 						    p_event->ae_desc;
2325 				} else {
2326 					uval.string_val =
2327 					    gettext("invalid event number");
2328 				}
2329 				returnstat = pa_print(context, &uval, flag);
2330 			} else {
2331 				uval.uvaltype = PRA_USHORT;
2332 				uval.ushort_val = etype;
2333 				returnstat = pa_print(context, &uval, flag);
2334 			}
2335 		}
2336 		return (returnstat);
2337 	} else
2338 		return (status);
2339 
2340 }
2341 
2342 
2343 /*
2344  * Print time from struct timeval to millisecond resolution.
2345  *
2346  *	typedef long	time_t;		time of day in seconds
2347  *	typedef	long	useconds_t;	signed # of microseconds
2348  *
2349  * struct timeval {
2350  *	time_t		tv_sec;		seconds
2351  *	suseconds_t	tv_usec;	and microseconds
2352  * };
2353  */
2354 
2355 int
2356 pa_utime32(pr_context_t *context, int status, int flag)
2357 {
2358 	uint32_t scale = 1000;		/* usec to msec */
2359 
2360 	return (do_mtime32(context, status, flag, scale));
2361 }
2362 
2363 /*
2364  * Print time from timestruc_t to millisecond resolution.
2365  *
2366  *	typedef struct timespec timestruct_t;
2367  * struct timespec{
2368  *	time_t	tv_sec;		seconds
2369  *	long	tv_nsec;	and nanoseconds
2370  * };
2371  */
2372 int
2373 pa_ntime32(pr_context_t *context, int status, int flag)
2374 {
2375 	uint32_t scale = 1000000;	/* nsec to msec */
2376 
2377 	return (do_mtime32(context, status, flag, scale));
2378 }
2379 
2380 /*
2381  * Format the timezone +/- HH:MM and terminate the string
2382  * Note tm and tv_sec are the same time.
2383  * Too bad strftime won't produce an ISO 8601 time zone numeric
2384  */
2385 
2386 #define	MINS	(24L * 60)
2387 static void
2388 tzone(struct tm *tm, time_t *tv_sec, char *p)
2389 {
2390 	struct tm *gmt;
2391 	int min_off;
2392 
2393 	gmt = gmtime(tv_sec);
2394 
2395 	min_off = ((tm->tm_hour - gmt->tm_hour) * 60) +
2396 	    (tm->tm_min - gmt->tm_min);
2397 
2398 	if (tm->tm_year < gmt->tm_year)		/* cross new year */
2399 		min_off -= MINS;
2400 	else if (tm->tm_year > gmt->tm_year)
2401 		min_off += MINS;
2402 	else if (tm->tm_yday < gmt->tm_yday)	/* cross dateline */
2403 		min_off -= MINS;
2404 	else if (tm->tm_yday > gmt->tm_yday)
2405 		min_off += MINS;
2406 
2407 	if (min_off < 0) {
2408 		min_off = -min_off;
2409 		*p++ = '-';
2410 	} else {
2411 		*p++ = '+';
2412 	}
2413 
2414 	*p++ = min_off / 600 + '0';		/* 10s of hours */
2415 	min_off = min_off - min_off / 600 * 600;
2416 	*p++ = min_off / 60 % 10 + '0';		/* hours */
2417 	min_off = min_off - min_off / 60 * 60;
2418 	*p++ = ':';
2419 	*p++ = min_off / 10 + '0';		/* 10s of minutes */
2420 	*p++ = min_off % 10 + '0';		/* minutes */
2421 	*p = '\0';
2422 }
2423 
2424 /*
2425  * Format the milliseconds in place in the string.
2426  * Borrowed from strftime.c:itoa()
2427  */
2428 static void
2429 msec32(uint32_t msec, char *p)
2430 {
2431 	*p++ = msec / 100 + '0';
2432 	msec  = msec - msec / 100 * 100;
2433 	*p++ = msec / 10 + '0';
2434 	*p++ = msec % 10 +'0';
2435 }
2436 
2437 /*
2438  * Format time and print relative to scale factor from micro/nano seconds.
2439  */
2440 static int
2441 do_mtime32(pr_context_t *context, int status, int flag, uint32_t scale)
2442 {
2443 	uint32_t t32;
2444 	time_t tv_sec;
2445 	struct tm tm;
2446 	char	time_created[sizeof ("YYYY-MM-DD HH:MM:SS.sss -HH:MM")];
2447 	int	returnstat;
2448 	uval_t	uval;
2449 
2450 	if (status < 0)
2451 		return (status);
2452 
2453 	if ((returnstat = open_tag(context, TAG_ISO)) != 0)
2454 		return (returnstat);
2455 
2456 	if ((returnstat = pr_adr_u_int32(context,
2457 	    (uint32_t *)&tv_sec, 1)) != 0)
2458 		return (returnstat);
2459 	if ((returnstat = pr_adr_u_int32(context, &t32, 1)) == 0) {
2460 		if (!(context->format & PRF_RAWM)) {
2461 			(void) localtime_r(&tv_sec, &tm);
2462 			(void) strftime(time_created,
2463 			    sizeof ("YYYY-MM-DD HH:MM:SS.xxx "),
2464 			    "%Y-%m-%d %H:%M:%S.xxx ", &tm);
2465 			msec32(t32/scale,
2466 			    &time_created[sizeof ("YYYY-MM-DD HH:MM:SS.")-1]);
2467 			tzone(&tm, &tv_sec,
2468 			    &time_created[
2469 			    sizeof ("YYYY-MM-DD HH:MM:SS.xxx ")-1]);
2470 			uval.uvaltype = PRA_STRING;
2471 			uval.string_val = time_created;
2472 		} else {
2473 			uval.uvaltype = PRA_UINT32;
2474 			uval.uint32_val = (uint32_t)tv_sec;
2475 			(void) pa_print(context, &uval, 0);
2476 			uval.uvaltype = PRA_UINT32;
2477 			uval.uint32_val = t32;
2478 		}
2479 		returnstat = pa_print(context, &uval, flag);
2480 	}
2481 
2482 	if (returnstat == 0)
2483 		return (close_tag(context, TAG_ISO));
2484 	else
2485 		return (returnstat);
2486 }
2487 
2488 /*
2489  * Print time from struct timeval to millisecond resolution.
2490  *
2491  *	typedef long	time_t;		time of day in seconds
2492  *	typedef	long	useconds_t;	signed # of microseconds
2493  *
2494  * struct timeval {
2495  *	time_t		tv_sec;		seconds
2496  *	suseconds_t	tv_usec;	and microseconds
2497  * };
2498  */
2499 
2500 int
2501 pa_utime64(pr_context_t *context, int status, int flag)
2502 {
2503 	uint64_t scale = 1000;		/* usec to msec */
2504 
2505 	return (do_mtime64(context, status, flag, scale));
2506 }
2507 
2508 /*
2509  * Print time from timestruc_t to millisecond resolution.
2510  *
2511  *	typedef struct timespec timestruct_t;
2512  * struct timespec{
2513  *	time_t	tv_sec;		seconds
2514  *	long	tv_nsec;	and nanoseconds
2515  * };
2516  */
2517 int
2518 pa_ntime64(pr_context_t *context, int status, int flag)
2519 {
2520 	uint64_t scale = 1000000;	/* nsec to msec */
2521 
2522 	return (do_mtime64(context, status, flag, scale));
2523 }
2524 
2525 /*
2526  * Format the milliseconds in place in the string.
2527  * Borrowed from strftime.c:itoa()
2528  */
2529 static void
2530 msec64(uint64_t msec, char *p)
2531 {
2532 	*p++ = msec / 100 + '0';
2533 	msec = msec - msec / 100 * 100;
2534 	*p++ = msec / 10 + '0';
2535 	*p++ = msec % 10 +'0';
2536 }
2537 
2538 /*
2539  * Format time and print relative to scale factor from micro/nano seconds.
2540  */
2541 static int
2542 do_mtime64(pr_context_t *context, int status, int flag, uint64_t scale)
2543 {
2544 	uint64_t t64_sec;
2545 	uint64_t t64_msec;
2546 	time_t tv_sec;
2547 	struct tm tm;
2548 	char	time_created[sizeof ("YYYY-MM-DD HH:MM:SS.sss -HH:MM")];
2549 	int	returnstat;
2550 	uval_t	uval;
2551 
2552 	if (status < 0)
2553 		return (status);
2554 
2555 	if ((returnstat = open_tag(context, TAG_ISO)) != 0)
2556 		return (returnstat);
2557 
2558 	if ((returnstat = pr_adr_u_int64(context, &t64_sec, 1)) != 0)
2559 		return (returnstat);
2560 	if ((returnstat = pr_adr_u_int64(context, &t64_msec, 1)) == 0) {
2561 		if (!(context->format & PRF_RAWM)) {
2562 #ifndef	_LP64
2563 			/*
2564 			 * N.B.
2565 			 * This fails for years from 2038
2566 			 * The Y2K+38 problem
2567 			 */
2568 #endif	/* !_LP64 */
2569 			tv_sec = (time_t)t64_sec;
2570 			(void) localtime_r(&tv_sec, &tm);
2571 			(void) strftime(time_created,
2572 			    sizeof ("YYYY-MM-DD HH:MM:SS.xxx "),
2573 			    "%Y-%m-%d %H:%M:%S.xxx ", &tm);
2574 			msec64(t64_msec/scale,
2575 			    &time_created[sizeof ("YYYY-MM-DD HH:MM:SS.")-1]);
2576 			tzone(&tm, &tv_sec,
2577 			    &time_created[
2578 			    sizeof ("YYYY-MM-DD HH:MM:SS.xxx ")-1]);
2579 			uval.uvaltype = PRA_STRING;
2580 			uval.string_val = time_created;
2581 		} else {
2582 			uval.uvaltype = PRA_UINT64;
2583 			uval.uint64_val = t64_sec;
2584 			(void) pa_print(context, &uval, 0);
2585 			uval.uvaltype = PRA_UINT64;
2586 			uval.uint64_val = t64_msec;
2587 		}
2588 		returnstat = pa_print(context, &uval, flag);
2589 	}
2590 
2591 	if (returnstat < 0)
2592 		return (returnstat);
2593 
2594 	return (close_tag(context, TAG_ISO));
2595 }
2596 
2597 /*
2598  * -----------------------------------------------------------------------
2599  * pa_error()   :  convert the return token error code.
2600  *
2601  * output	: buf string representing return token error code.
2602  *
2603  * -----------------------------------------------------------------------
2604  */
2605 void
2606 pa_error(const uchar_t err, char *buf, size_t buflen)
2607 {
2608 	if (err == 0) {
2609 		(void) strlcpy(buf, gettext("success"), buflen);
2610 	} else if ((char)err == -1) {
2611 		(void) strlcpy(buf, gettext("failure"), buflen);
2612 	} else {
2613 		char *emsg = strerror(err);
2614 
2615 		if (emsg != NULL) {
2616 			(void) strlcpy(buf, gettext("failure: "), buflen);
2617 			(void) strlcat(buf, emsg, buflen);
2618 		} else {
2619 			(void) snprintf(buf, buflen, "%s%d",
2620 			    gettext("failure: "), err);
2621 		}
2622 	}
2623 }
2624 
2625 /*
2626  * -----------------------------------------------------------------------
2627  * pa_retval()   :  convert the return token return value code.
2628  *
2629  * output	: buf string representing return token error code.
2630  *
2631  * -----------------------------------------------------------------------
2632  */
2633 void
2634 pa_retval(const int32_t retval, char *buf, size_t buflen)
2635 {
2636 	struct msg_text	*msglist = &adt_msg_text[ADT_LIST_FAIL_VALUE];
2637 
2638 	if ((retval + msglist->ml_offset >= msglist->ml_min_index) &&
2639 	    (retval + msglist->ml_offset <= msglist->ml_max_index)) {
2640 
2641 		(void) strlcpy(buf,
2642 		    gettext(msglist->ml_msg_list[retval + msglist->ml_offset]),
2643 		    buflen);
2644 	} else if ((retval >= ADT_FAIL_PAM) &&
2645 	    (retval < ADT_FAIL_PAM + PAM_TOTAL_ERRNUM))
2646 		(void) strlcpy(buf, pam_strerror(NULL, retval - ADT_FAIL_PAM),
2647 		    buflen);
2648 	else
2649 		(void) snprintf(buf, buflen, "%d", retval);
2650 }
2651 
2652 
2653 /*
2654  * -----------------------------------------------------------------------
2655  * pa_printstr()	:  print a given string, translating unprintables
2656  *			:  as needed.
2657  */
2658 static int
2659 pa_printstr(pr_context_t *context, char *str)
2660 {
2661 	int	err = 0;
2662 	int	len, printable;
2663 	int	mbmax = MB_CUR_MAX;
2664 	wchar_t	wc;
2665 	char	c;
2666 
2667 	if (mbmax == 1) {
2668 		/* fast path */
2669 		while (err == 0 && *str != '\0') {
2670 			c = *str++;
2671 			printable = isprint((unsigned char)c);
2672 			err = pa_putstr(context, printable, &c, 1);
2673 		}
2674 		return (err);
2675 	}
2676 	while (err == 0 && *str != '\0') {
2677 		len = mbtowc(&wc, str, mbmax);
2678 		if (len <= 0) {
2679 			len = 1;
2680 			printable = 0;
2681 		} else {
2682 			printable = iswprint(wc);
2683 		}
2684 		err = pa_putstr(context, printable, str, len);
2685 		str += len;
2686 	}
2687 	return (err);
2688 }
2689 
2690 /*
2691  * -----------------------------------------------------------------------
2692  * pa_print()	:  print as one str or formatted for easy reading.
2693  * 		: flag - indicates whether to output a new line for
2694  *		: multi-line output.
2695  * 		:		= 0; no new line
2696  *		:		= 1; new line if regular output
2697  * output	: The audit record information is displayed in the
2698  *		  type specified by uvaltype and value specified in
2699  *		  uval.  The printing of the delimiter or newline is
2700  *		  determined by PRF_ONELINE, and the flag value,
2701  *		  as follows:
2702  *			+--------+------+------+-----------------+
2703  *			|ONELINE | flag | last | Action          |
2704  *			+--------+------+------+-----------------+
2705  *			|    Y   |   Y  |   T  | print new line  |
2706  *			|    Y   |   Y  |   F  | print delimiter |
2707  *			|    Y   |   N  |   T  | print new line  |
2708  *			|    Y   |   N  |   F  | print delimiter |
2709  *			|    N   |   Y  |   T  | print new line  |
2710  *			|    N   |   Y  |   F  | print new line  |
2711  *			|    N   |   N  |   T  | print new line  |
2712  *			|    N   |   N  |   F  | print delimiter |
2713  *			+--------+------+------+-----------------+
2714  *
2715  * return codes : -1 - error
2716  *		0 - successful
2717  * -----------------------------------------------------------------------
2718  */
2719 int
2720 pa_print(pr_context_t *context, uval_t *uval, int flag)
2721 {
2722 	int	returnstat = 0;
2723 	int	last;
2724 
2725 	switch (uval->uvaltype) {
2726 	case PRA_INT32:
2727 		returnstat = pr_printf(context, "%d", uval->int32_val);
2728 		break;
2729 	case PRA_UINT32:
2730 		returnstat = pr_printf(context, "%u", uval->uint32_val);
2731 		break;
2732 	case PRA_INT64:
2733 		returnstat = pr_printf(context, "%"PRId64, uval->int64_val);
2734 		break;
2735 	case PRA_UINT64:
2736 		returnstat = pr_printf(context, "%"PRIu64, uval->uint64_val);
2737 		break;
2738 	case PRA_SHORT:
2739 		returnstat = pr_printf(context, "%hd", uval->short_val);
2740 		break;
2741 	case PRA_USHORT:
2742 		returnstat = pr_printf(context, "%hu", uval->ushort_val);
2743 		break;
2744 	case PRA_CHAR:
2745 		returnstat = pr_printf(context, "%c", uval->char_val);
2746 		break;
2747 	case PRA_BYTE:
2748 		returnstat = pr_printf(context, "%d", uval->char_val);
2749 		break;
2750 	case PRA_STRING:
2751 		returnstat = pa_printstr(context, uval->string_val);
2752 		break;
2753 	case PRA_HEX32:
2754 		returnstat = pr_printf(context, "0x%x", uval->int32_val);
2755 		break;
2756 	case PRA_HEX64:
2757 		returnstat = pr_printf(context, "0x%"PRIx64, uval->int64_val);
2758 		break;
2759 	case PRA_SHEX:
2760 		returnstat = pr_printf(context, "0x%hx", uval->short_val);
2761 		break;
2762 	case PRA_OCT:
2763 		returnstat = pr_printf(context, "%ho", uval->ushort_val);
2764 		break;
2765 	case PRA_LOCT:
2766 		returnstat = pr_printf(context, "%o", (int)uval->uint32_val);
2767 		break;
2768 	default:
2769 		(void) fprintf(stderr, gettext("praudit: Unknown type.\n"));
2770 		returnstat = -1;
2771 		break;
2772 	}
2773 	if (returnstat < 0)
2774 		return (returnstat);
2775 
2776 	last = (context->audit_adr->adr_now ==
2777 	    (context->audit_rec_start + context->audit_rec_len));
2778 
2779 	if (!(context->format & PRF_XMLM)) {
2780 		if (!(context->format & PRF_ONELINE)) {
2781 			if ((flag == 1) || last)
2782 				returnstat = pr_putchar(context, '\n');
2783 			else
2784 				returnstat = pr_printf(context, "%s",
2785 				    context->SEPARATOR);
2786 		} else {
2787 			if (!last)
2788 				returnstat = pr_printf(context, "%s",
2789 				    context->SEPARATOR);
2790 			else
2791 				returnstat = pr_putchar(context, '\n');
2792 		}
2793 	}
2794 	if ((returnstat == 0) && (context->data_mode == FILEMODE))
2795 		(void) fflush(stdout);
2796 
2797 	return (returnstat);
2798 }
2799 
2800 static struct cntrl_mapping {
2801 	char from;
2802 	char to;
2803 } cntrl_map[] = {
2804 	'\0', '0',
2805 	'\a', 'a',
2806 	'\b', 'b',
2807 	'\t', 't',
2808 	'\f', 'f',
2809 	'\n', 'n',
2810 	'\r', 'r',
2811 	'\v', 'v'
2812 };
2813 
2814 static int cntrl_map_entries = sizeof (cntrl_map)
2815 	/ sizeof (struct cntrl_mapping);
2816 
2817 /*
2818  * Convert binary data to ASCII for printing.
2819  */
2820 void
2821 convertascii(char *p, char *c, int size)
2822 {
2823 	register int	i;
2824 	register int	j, match;
2825 
2826 	for (i = 0; i < size; i++) {
2827 		*(c + i) = (char)toascii(*(c + i));
2828 		if ((int)iscntrl(*(c + i))) {
2829 			for (j = match = 0; j < cntrl_map_entries; j++)
2830 				if (cntrl_map[j].from == *(c + i)) {
2831 					*p++ = '\\';
2832 					*p++ = cntrl_map[j].to;
2833 					match = 1;
2834 				}
2835 			if (!match) {
2836 				*p++ = '^';
2837 				*p++ = (char)(*(c + i) + 0x40);
2838 			}
2839 		} else
2840 			*p++ = *(c + i);
2841 	}
2842 
2843 	*p = '\0';
2844 
2845 }
2846 
2847 
2848 /*
2849  * -----------------------------------------------------------------------
2850  * pa_xgeneric: Process Xobject token and display contents
2851  *		      This routine will handle many of the attribute
2852  *		      types introduced in TS 2.x, such as:
2853  *
2854  *		      AUT_XCOLORMAP, AUT_XCURSOR, AUT_XFONT,
2855  *		      AUT_XGC, AUT_XPIXMAP, AUT_XWINDOW
2856  *
2857  * NOTE: At the time of call, the token id has been retrieved
2858  *
2859  * return codes		: -1 - error
2860  *			:  0 - successful
2861  * NOTE: At the time of call, the xatom token id has been retrieved
2862  *
2863  * Format of xobj
2864  *	text token id		adr_char
2865  * 	XID 			adr_u_int32
2866  * 	creator uid		adr_pw_uid
2867  * -----------------------------------------------------------------------
2868  */
2869 int
2870 pa_xgeneric(pr_context_t *context)
2871 {
2872 	int	returnstat;
2873 
2874 	returnstat = process_tag(context, TAG_XID, 0, 0);
2875 	return (process_tag(context, TAG_XCUID, returnstat, 1));
2876 }
2877 
2878 
2879 /*
2880  * ------------------------------------------------------------------------
2881  * pa_liaison : Issues pr_adr_char to retrieve the next ADR item from the
2882  *			input stream pointed to by audit_adr, and prints it
2883  *			if status >= 0 either in ASCII or raw form
2884  * return codes : -1 - error
2885  *		: 0 - successful
2886  *		: 1 - warning, unknown label type
2887  * -----------------------------------------------------------------------
2888  */
2889 int
2890 pa_liaison(pr_context_t *context, int status, int flag)
2891 {
2892 	int	returnstat;
2893 	int32_t	li;
2894 	uval_t	uval;
2895 
2896 	if (status >= 0) {
2897 		if ((returnstat = pr_adr_int32(context, &li, 1)) != 0) {
2898 			return (returnstat);
2899 		}
2900 		if (!(context->format & PRF_RAWM)) {
2901 			uval.uvaltype = PRA_UINT32;
2902 			uval.uint32_val = li;
2903 			returnstat = pa_print(context, &uval, flag);
2904 		}
2905 		/* print in hexadecimal form */
2906 		if ((context->format & PRF_RAWM) || (returnstat == 1)) {
2907 			uval.uvaltype = PRA_HEX32;
2908 			uval.uint32_val = li;
2909 			returnstat = pa_print(context, &uval, flag);
2910 		}
2911 		return (returnstat);
2912 	} else
2913 		return (status);
2914 }
2915 
2916 /*
2917  * ------------------------------------------------------------------------
2918  * pa_xid : Issues pr_adr_int32 to retrieve the XID from the input
2919  *	      stream pointed to by audit_adr, and prints it if
2920  *	      status >= 0 either in ASCII or raw form
2921  * return codes : -1 - error
2922  *		:  0 - successful
2923  *		:  1 - warning, unknown label type
2924  * ------------------------------------------------------------------------
2925  */
2926 
2927 int
2928 pa_xid(pr_context_t *context, int status, int flag)
2929 {
2930 	int returnstat;
2931 	int32_t xid;
2932 	uval_t	uval;
2933 
2934 	if (status < 0)
2935 		return (status);
2936 
2937 	/* get XID from stream */
2938 	if ((returnstat = pr_adr_int32(context, (int32_t *)&xid, 1)) != 0)
2939 		return (returnstat);
2940 
2941 	if (!(context->format & PRF_RAWM)) {
2942 		uval.uvaltype = PRA_STRING;
2943 		uval.string_val = hexconvert((char *)&xid, sizeof (xid),
2944 		    sizeof (xid));
2945 		if (uval.string_val) {
2946 			returnstat = pa_print(context, &uval, flag);
2947 			free(uval.string_val);
2948 		}
2949 	} else {
2950 		uval.uvaltype = PRA_INT32;
2951 		uval.int32_val = xid;
2952 		returnstat = pa_print(context, &uval, flag);
2953 	}
2954 
2955 	return (returnstat);
2956 }
2957