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