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