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