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 * adt_token.c
23 *
24 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
25 * Use is subject to license terms.
26 *
27 * This file does not provide any user callable functions.  See adt.c
28 */
29
30#include <bsm/adt.h>
31#include <bsm/adt_event.h>
32#include <bsm/audit.h>
33
34#include <adt_xlate.h>
35#include <alloca.h>
36#include <assert.h>
37#include <netdb.h>
38#include <priv.h>
39#include <string.h>
40#include <strings.h>
41#include <stdlib.h>
42#include <time.h>
43#include <unistd.h>
44
45#include <sys/priv_names.h>
46#include <sys/socket.h>
47#include <sys/types.h>
48#include <sys/vnode.h>
49
50#include <tsol/label.h>
51
52#ifdef	C2_DEBUG
53#define	DPRINTF(x) { (void) printf x; }
54#define	DFLUSH (void) fflush(stdout);
55
56/* 0x + Classification + Compartments + end of string */
57#define	HEX_SIZE 2 + 2*2 + 2*32 + 1
58
59static char *
60dprt_label(m_label_t *label)
61{
62	static char	hex[HEX_SIZE];
63	char		*direct = NULL;
64
65	if (label_to_str(label, &direct, M_INTERNAL, DEF_NAMES) != 0) {
66		adt_write_syslog("label_to_str(M_INTERNAL)", errno);
67		return ("hex label failed");
68	}
69	(void) strlcpy(hex, direct, sizeof (hex));
70	free(direct);
71	return (hex);
72}
73#else	/* !C2_DEBUG */
74#define	DPRINTF(x)
75#define	DFLUSH
76#endif	/* C2_DEBUG */
77
78static adt_token_func_t adt_getTokenFunction(char);
79
80static char	*empty = "";
81
82/*
83 * call adt_token_open() first and adt_token_close() last.
84 *
85 * au_open is sort of broken; it returns a -1 when out of memory that
86 * you're supposed to ignore; au_write and au_close return without
87 * doing anything when a -1 is passed.  This code sort of follows the
88 * au_open model except that it calls syslog to indicate underlying
89 * brokenness.  Other than that, -1 is ignored.
90 */
91
92void
93adt_token_open(struct adt_event_state *event)
94{
95	static int	have_syslogged = 0;
96
97	event->ae_event_handle = au_open();
98	if (event->ae_event_handle < 0) {
99		if (!have_syslogged) {
100			adt_write_syslog("au_open failed", ENOMEM);
101			have_syslogged = 1;
102		}
103	} else {
104		have_syslogged = 0;
105	}
106}
107
108/*
109 * call generate_token for each token in the order you want the tokens
110 * generated.
111 */
112
113void
114adt_generate_token(struct entry *p_entry, void *p_data,
115    struct adt_event_state *event)
116{
117	adt_token_func_t	p_func;
118
119	assert((p_entry != NULL) && (p_data != NULL) && (event != NULL));
120
121	p_func = adt_getTokenFunction(p_entry->en_token_id);
122	assert(p_func != NULL);
123
124	DPRINTF(("p_entry=%p, p_data=%p, offset=%llu, msgFmt=%s\n",
125	    (void *)p_entry, p_data, (long long)p_entry->en_offset,
126	    p_entry->en_msg_format));
127	DFLUSH
128
129	(*p_func)(p_entry->en_type_def,
130	    (char *)p_data + p_entry->en_offset, p_entry->en_required, event,
131	    p_entry->en_msg_format);
132}
133
134/* call this last */
135
136int
137adt_token_close(struct adt_event_state *event)
138{
139	int	rc;
140
141	rc = au_close(event->ae_event_handle, AU_TO_WRITE,
142	    event->ae_internal_id);
143	if (rc < 0)
144		adt_write_syslog("au_close failed", errno);
145	return (rc);
146}
147
148/*
149 * one function per token -- see the jump table at the end of file
150 */
151
152/* ARGSUSED */
153static void
154adt_to_return(datadef *def, void *p_data, int required,
155    struct adt_event_state *event, char *notUsed)
156{
157
158#ifdef _LP64
159	(void) au_write(event->ae_event_handle,
160	    au_to_return64((int64_t)event->ae_rc, event->ae_type));
161#else
162	(void) au_write(event->ae_event_handle,
163	    au_to_return32((int32_t)event->ae_rc, event->ae_type));
164#endif
165}
166
167/*
168 * AUT_CMD
169 *
170 * the command line is described with argc and argv and the environment
171 * with envp.  The envp list is NULL terminated and has no separate
172 * counter; envp will be a NULL list unless the AUDIT_ARGE policy is
173 * set.
174 */
175
176/* ARGSUSED */
177static void
178adt_to_cmd(datadef *def, void *p_data, int required,
179    struct adt_event_state *event, char *notUsed)
180{
181	struct adt_internal_state	*sp = event->ae_session;
182	int				argc;
183	char				**argv;
184	char				**envp = NULL;
185
186	argc = ((union convert *)p_data)->tint;
187	p_data = adt_adjust_address(p_data, sizeof (int), sizeof (char **));
188	argv = ((union convert *)p_data)->tchar2star;
189	p_data = adt_adjust_address(p_data, sizeof (char **), sizeof (char **));
190
191	if (sp->as_kernel_audit_policy & AUDIT_ARGE)
192		envp = ((union convert *)p_data)->tchar2star;
193
194	(void) au_write(event->ae_event_handle,
195	    au_to_cmd(argc, argv, envp));
196}
197
198/*
199 * special case of AUT_CMD with 1 argument that is
200 * a string showing the whole command and no envp
201 */
202/* ARGSUSED */
203static void
204adt_to_cmd1(datadef *def, void *p_data, int required,
205    struct adt_event_state *event, char *notUsed)
206{
207	char	*string;
208
209	string = ((union convert *)p_data)->tcharstar;
210
211	if (string == NULL) {
212		if (required) {
213			string = empty;
214		} else {
215			return;
216		}
217	}
218	/* argc is hardcoded as 1 */
219	(void) au_write(event->ae_event_handle, au_to_cmd(1, &string,
220	    NULL));
221}
222
223/*
224 * adt_to_tid	-- generic address (ip is only one defined at present)
225 *	input:
226 *		terminal type:  ADT_IPv4, ADT_IPv6...
227 *		case: ADT_IPv4 or ADT_IPv6...
228 *			ip type
229 *			remote port
230 *			local port
231 *			address
232 *		case: not defined...
233 */
234/* ARGSUSED */
235static void
236adt_to_tid(datadef *def, void *p_data, int required,
237    struct adt_event_state *event, char *notUsed)
238{
239	au_generic_tid_t	tid;
240	uint32_t		type;
241	au_ip_t			*ip;
242
243	type = ((union convert *)p_data)->tuint32;
244
245	switch (type) {
246	case ADT_IPv4:
247	case ADT_IPv6:
248		p_data = adt_adjust_address(p_data, sizeof (uint32_t),
249		    sizeof (uint32_t));
250
251		tid.gt_type = AU_IPADR;
252		ip = &(tid.gt_adr.at_ip);
253
254		ip->at_type = (type == ADT_IPv4) ?
255		    AU_IPv4 : AU_IPv6;
256
257		ip->at_r_port = ((union convert *)p_data)->tuint16;
258		p_data = adt_adjust_address(p_data, sizeof (uint16_t),
259		    sizeof (uint16_t));
260
261		ip->at_l_port = ((union convert *)p_data)->tuint16;
262
263		/* arg3 is for the array element, not the array size */
264		p_data = adt_adjust_address(p_data, sizeof (uint16_t),
265		    sizeof (uint32_t));
266
267		(void) memcpy(ip->at_addr, p_data, ip->at_type);
268		break;
269	default:
270		adt_write_syslog("Invalid terminal id type", EINVAL);
271		return;
272	}
273	(void) au_write(event->ae_event_handle, au_to_tid(&tid));
274}
275
276/*
277 * au_to_frmi takes a char * that is the fmri.
278 */
279/* ARGSUSED */
280static void
281adt_to_frmi(datadef *def, void *p_data, int required,
282    struct adt_event_state *event, char *notUsed)
283{
284	char		*fmri;
285
286	DPRINTF(("  adt_to_fmri dd_datatype=%d\n", def->dd_datatype));
287
288	fmri = ((union convert *)p_data)->tcharstar;
289
290	if (fmri == NULL) {
291		if (required) {
292			fmri = empty;
293		} else {
294			return;
295		}
296	}
297	DPRINTF(("  fmri=%s\n", fmri));
298	(void) au_write(event->ae_event_handle, au_to_fmri(fmri));
299}
300
301/*
302 * au_to_label takes an m_label_t * that is the label.
303 */
304/* ARGSUSED */
305static void
306adt_to_label(datadef *def, void *p_data, int required,
307    struct adt_event_state *event, char *notUsed)
308{
309	m_label_t	*label;
310
311	DPRINTF(("  adt_to_label dd_datatype=%d\n", def->dd_datatype));
312
313	label = ((union convert *)p_data)->tm_label;
314
315	if (label != NULL) {
316		DPRINTF(("  label=%s\n", dprt_label(label)));
317		DFLUSH
318		(void) au_write(event->ae_event_handle, au_to_label(label));
319	} else {
320		DPRINTF(("  Null label\n"));
321		if (required)
322			adt_write_syslog("adt_to_label no required label", 0);
323	}
324}
325
326/*
327 * au_to_newgroups takes a length and an array of gids
328 * as input.  The input to adt_to_newgroups is a length
329 * and a pointer to an array of gids.
330 */
331
332/* ARGSUSED */
333static void
334adt_to_newgroups(datadef *def, void *p_data, int required,
335    struct adt_event_state *event, char *notUsed)
336{
337	int	n;
338	gid_t	*groups;
339
340	n = ((union convert *)p_data)->tint;
341	if (n < 1) {
342		if (required) {
343			n = 0;  /* in case negative n was passed */
344		} else {
345			return;
346		}
347	}
348	p_data = adt_adjust_address(p_data, sizeof (int), sizeof (int32_t *));
349
350	groups = ((union convert *)p_data)->tgidstar;
351
352	(void) au_write(event->ae_event_handle, au_to_newgroups(n, groups));
353}
354
355/* ARGSUSED */
356static void
357adt_to_path(datadef *def, void *p_data, int required,
358    struct adt_event_state *event, char *notUsed)
359{
360	char	*path;
361
362	path = ((union convert *)p_data)->tcharstar;
363
364	if (path != NULL) {
365		DPRINTF(("  path=%s\n", path));
366		(void) au_write(event->ae_event_handle, au_to_path(path));
367	} else {
368		DPRINTF(("  Null path\n"));
369		if (required) {
370			(void) au_write(event->ae_event_handle,
371			    au_to_path(empty));
372		}
373	}
374}
375
376/*
377 * dummy token id:  AUT_PATHLIST
378 */
379
380/* ARGSUSED */
381static void
382adt_to_pathlist(datadef *def, void *p_data, int required,
383    struct adt_event_state *event, char *notUsed)
384{
385	char	*path;
386	char	*working_buf;
387	char	*pathlist;
388	char	*last_str;
389
390	pathlist = ((union convert *)p_data)->tcharstar;
391
392	if (pathlist != NULL) {
393		working_buf = strdup(pathlist);
394		if (working_buf == NULL) {
395			adt_write_syslog("audit failure", errno);
396			if (required) {
397				(void) au_write(event->ae_event_handle,
398				    au_to_path(empty));
399			}
400			return;
401		}
402		for (path = strtok_r(working_buf, " ", &last_str);
403		    path; path = strtok_r(NULL, " ", &last_str)) {
404			DPRINTF(("  path=%s\n", path));
405			(void) au_write(event->ae_event_handle,
406			    au_to_path(path));
407		}
408	} else {
409		DPRINTF(("  Null path list\n"));
410		if (required)
411			(void) au_write(event->ae_event_handle,
412			    au_to_path(empty));
413	}
414}
415
416/*
417 * AUT_PRIV
418 */
419
420/* ARGSUSED */
421static void
422adt_to_priv(datadef *def, void *p_data, int required,
423    struct adt_event_state *event, const char *priv_type)
424{
425	priv_set_t	*privilege;
426
427	privilege = ((union convert *)p_data)->tprivstar;
428
429	if (privilege != NULL) {
430		(void) au_write(event->ae_event_handle,
431		    au_to_privset(priv_type, privilege));
432	} else {
433		if (required) {
434			DPRINTF(("  Null privilege\n"));
435			(void) au_write(event->ae_event_handle,
436			    au_to_privset(empty, NULL));
437		}
438	}
439}
440
441/*
442 * -AUT_PRIV_L	AUT_PRIV for a limit set
443 */
444
445/* ARGSUSED */
446static void
447adt_to_priv_limit(datadef *def, void *p_data, int required,
448    struct adt_event_state *event, char *notUsed)
449{
450	adt_to_priv(def, p_data, required, event, PRIV_LIMIT);
451}
452
453/*
454 * -AUT_PRIV_I	AUT_PRIV for an inherit set
455 */
456
457/* ARGSUSED */
458static void
459adt_to_priv_inherit(datadef *def, void *p_data, int required,
460    struct adt_event_state *event, char *notUsed)
461{
462	adt_to_priv(def, p_data, required, event, PRIV_INHERITABLE);
463}
464
465/* ARGSUSED */
466static void
467adt_to_priv_effective(datadef *def, void *p_data, int required,
468    struct adt_event_state *event, char *notUsed)
469{
470	adt_to_priv(def, p_data, required, event, PRIV_EFFECTIVE);
471}
472
473static void
474getCharacteristics(struct auditpinfo_addr *info, pid_t *pid)
475{
476	int	rc;
477
478	if (*pid == 0) {		/* getpinfo for this pid */
479		info->ap_pid = getpid();
480	} else {
481		info->ap_pid = *pid;
482	}
483
484	rc = auditon(A_GETPINFO_ADDR, (caddr_t)info,
485	    sizeof (struct auditpinfo_addr));
486	if (rc == -1) {
487		info->ap_auid = AU_NOAUDITID;
488		info->ap_asid = 0;
489		(void) memset((void *)&(info->ap_termid), 0,
490		    sizeof (au_tid_addr_t));
491		info->ap_termid.at_type = AU_IPv4;
492	}
493}
494
495/*
496 * AUT_PROCESS
497 *
498 */
499
500/* ARGSUSED */
501static void
502adt_to_process(datadef *def, void *p_data, int required,
503    struct adt_event_state *event, char *notUsed)
504{
505	au_id_t			auid;
506	uid_t			euid;
507	gid_t			egid;
508	uid_t			ruid;
509	gid_t			rgid;
510	pid_t			pid;
511	au_asid_t		sid;
512	au_tid_addr_t		*tid;
513	struct auditpinfo_addr	info;
514
515	auid = ((union convert *)p_data)->tuid;
516	p_data = adt_adjust_address(p_data, sizeof (uid_t), sizeof (uid_t));
517	euid = ((union convert *)p_data)->tuid;
518	p_data = adt_adjust_address(p_data, sizeof (uid_t), sizeof (gid_t));
519	egid = ((union convert *)p_data)->tgid;
520	p_data = adt_adjust_address(p_data, sizeof (gid_t), sizeof (uid_t));
521	ruid = ((union convert *)p_data)->tuid;
522	p_data = adt_adjust_address(p_data, sizeof (uid_t), sizeof (gid_t));
523	rgid = ((union convert *)p_data)->tgid;
524	p_data = adt_adjust_address(p_data, sizeof (gid_t), sizeof (pid_t));
525	pid  = ((union convert *)p_data)->tpid;
526	p_data = adt_adjust_address(p_data, sizeof (pid_t), sizeof (uint32_t));
527	sid  = ((union convert *)p_data)->tuint32;
528	p_data = adt_adjust_address(p_data, sizeof (uint32_t),
529	    sizeof (au_tid_addr_t *));
530	tid  = ((union convert *)p_data)->ttermid;
531
532	getCharacteristics(&info, &pid);
533
534	if (auid == AU_NOAUDITID)
535		auid = info.ap_auid;
536
537	if (euid == AU_NOAUDITID)
538		euid = geteuid();
539
540	if (egid == AU_NOAUDITID)
541		egid = getegid();
542
543	if (ruid == AU_NOAUDITID)
544		ruid = getuid();
545
546	if (rgid == AU_NOAUDITID)
547		rgid = getgid();
548
549	if (tid == NULL)
550		tid = &(info.ap_termid);
551
552	if (sid == 0)
553		sid = info.ap_asid;
554
555	if (pid == 0)
556		pid = info.ap_pid;
557
558	(void) au_write(event->ae_event_handle,
559	    au_to_process_ex(auid, euid, egid, ruid, rgid, pid, sid, tid));
560}
561
562/*
563 * Generate subject information.
564 * If labels are present, generate the subject label token.
565 * If the group audit policy is set, generate the subject group token.
566 *
567 * The required flag does not apply here.
568 *
569 * Non-attributable records are indicated by an auid of AU_NOAUDITID;
570 * no subject token or group token is generated for a non-attributable
571 * record.
572 */
573
574/* ARGSUSED */
575static void
576adt_to_subject(datadef *def, void *p_data, int required,
577    struct adt_event_state *event, char *notUsed)
578{
579	struct adt_internal_state	*sp = event->ae_session;
580
581	if (sp->as_info.ai_auid == AU_NOAUDITID)
582		return;
583
584	assert(sp->as_have_user_data == ADT_HAVE_ALL);
585
586	(void) au_write(event->ae_event_handle,
587	    au_to_subject_ex(sp->as_info.ai_auid,
588	    sp->as_euid, sp->as_egid, sp->as_ruid, sp->as_rgid,
589	    sp->as_pid, sp->as_info.ai_asid,
590	    &(sp->as_info.ai_termid)));
591	if (is_system_labeled()) {
592		(void) au_write(event->ae_event_handle,
593		    au_to_label(sp->as_label));
594	}
595	/*
596	 * Add optional tokens if in the process model.
597	 * In a session model, the groups list is undefined and label
598	 * is in the state.
599	 */
600	if (sp->as_session_model == ADT_PROCESS_MODEL) {
601		if (sp->as_kernel_audit_policy & AUDIT_GROUP) {
602			int group_count;
603			int maxgrp = getgroups(0, NULL);
604			gid_t *grouplist = alloca(maxgrp * sizeof (gid_t));
605
606			if ((group_count = getgroups(maxgrp, grouplist)) > 0) {
607				(void) au_write(event->ae_event_handle,
608				    au_to_newgroups(group_count, grouplist));
609			}
610		}
611	}
612}
613
614/*
615 * adt_to_text()
616 *
617 * The format string, normally null, is sort of a wrapper around
618 * the input.  adt_write_text() is a wrapper around au_write that
619 * handles the format string
620 *
621 */
622#define	TEXT_LENGTH 49
623
624static void
625adt_write_text(int handle, char *main_text, const char *format)
626{
627	char	buffer[TEXT_LENGTH * 2 + 1];
628
629	if (format == NULL) {
630		(void) au_write(handle, au_to_text(main_text));
631	} else {
632		(void) snprintf(buffer, TEXT_LENGTH * 2, format, main_text);
633		(void) au_write(handle, au_to_text(buffer));
634	}
635}
636
637static void
638adt_to_text(datadef *def, void *p_data, int required,
639    struct adt_event_state *event, char *format)
640{
641	static int	have_syslogged = 0;
642	char		*string;
643	char		**string_list;
644	char		buffer[TEXT_LENGTH + 1];
645	time_t		date;
646	struct tm	tm;
647	uint32_t	*int_list;
648	int		written, available;
649	int		i, arrayCount;
650	struct msg_text *list;
651	int		list_index;
652
653	DPRINTF(("  adt_to_text dd_datatype=%d\n", def->dd_datatype));
654	switch (def->dd_datatype) {
655	case ADT_DATE:
656		/*
657		 * Consider creating a separate token type for dates
658		 * -- store as longs and format them in praudit.
659		 * For now, a date is input as a time_t and output as
660		 * a text token.  If we do this, we need to consider
661		 * carrying timezone info so that praudit can
662		 * represent times in an unambiguous manner.
663		 */
664		date = ((union convert *)p_data)->tlong;
665		if (strftime(buffer, sizeof (buffer), "%x",
666		    localtime_r(&date, &tm)) > TEXT_LENGTH) {
667			if (required) {
668				(void) strncpy(buffer, "invalid date",
669				    TEXT_LENGTH);
670			} else {
671				break;
672			}
673		}
674		DPRINTF(("  text=%s\n", buffer));
675		adt_write_text(event->ae_event_handle, buffer, format);
676		break;
677		/*
678		 * The "input size" is overloaded to mean the list number
679		 * and the msg_selector indexes the desired string in
680		 * that list
681		 */
682	case ADT_MSG:
683		list = &adt_msg_text[(enum adt_msg_list)def->dd_input_size];
684		list_index = ((union convert *)p_data)->msg_selector;
685
686		if ((list_index + list->ml_offset < list->ml_min_index) ||
687		    (list_index + list->ml_offset > list->ml_max_index)) {
688			string = "Invalid message index";
689		} else {
690			string = list->ml_msg_list[list_index +
691			    list->ml_offset];
692		}
693
694		if (string == NULL) {	/* null is valid; means skip */
695			if (required) {
696				string = empty;
697			} else {
698				break;
699			}
700		}
701		DPRINTF(("  text=%s\n", string));
702		adt_write_text(event->ae_event_handle, string, format);
703		break;
704	case ADT_UID:
705	case ADT_GID:
706	case ADT_UINT:
707	case ADT_UINT32:
708		(void) snprintf(buffer, TEXT_LENGTH, "%u",
709		    ((union convert *)p_data)->tuint);
710
711		DPRINTF(("  text=%s\n", buffer));
712		adt_write_text(event->ae_event_handle, buffer, format);
713		break;
714	case ADT_INT:
715	case ADT_INT32:
716		(void) snprintf(buffer, TEXT_LENGTH, "%d",
717		    ((union convert *)p_data)->tint);
718
719		DPRINTF(("  text=%s\n", buffer));
720		adt_write_text(event->ae_event_handle, buffer, format);
721		break;
722	case ADT_LONG:
723		(void) snprintf(buffer, TEXT_LENGTH, "%ld",
724		    ((union convert *)p_data)->tlong);
725
726		DPRINTF(("  text=%s\n", buffer));
727		adt_write_text(event->ae_event_handle, buffer, format);
728		break;
729	case ADT_UIDSTAR:
730	case ADT_GIDSTAR:
731	case ADT_UINT32STAR:
732		int_list = ((union convert *)p_data)->tuint32star;
733		p_data = adt_adjust_address(p_data, sizeof (int *),
734		    sizeof (int));
735		arrayCount = ((union convert *)p_data)->tint;
736
737		string = buffer;
738		available = TEXT_LENGTH;	/* space available in buffer */
739
740		if (arrayCount < 0)
741			arrayCount = 0;
742
743		if ((arrayCount > 0) && (int_list != NULL)) {
744			for (; arrayCount > 0; arrayCount--) {
745				written = snprintf(string, available,
746				    "%d ", *int_list++);
747				if (written < 1)
748					break;
749				string += written;
750				available -= written;
751			}
752		} else if (required) {
753			string = empty;
754		} else {
755			break;
756		}
757
758		adt_write_text(event->ae_event_handle, buffer, format);
759		break;
760	case ADT_ULONG:
761		(void) snprintf(buffer, TEXT_LENGTH, "%lu",
762		    ((union convert *)p_data)->tulong);
763
764		DPRINTF(("  text=%s\n", buffer));
765		adt_write_text(event->ae_event_handle, buffer, format);
766		break;
767	case ADT_UINT64:
768		(void) snprintf(buffer, TEXT_LENGTH, "%llu",
769		    ((union convert *)p_data)->tuint64);
770
771		DPRINTF(("  text=%s\n", buffer));
772		adt_write_text(event->ae_event_handle, buffer, format);
773		break;
774	case ADT_CHARSTAR:
775		string = ((union convert *)p_data)->tcharstar;
776
777		if (string == NULL) {
778			if (required) {
779				string = empty;
780			} else {
781				break;
782			}
783		}
784		DPRINTF(("  text=%s\n", string));
785		adt_write_text(event->ae_event_handle, string, format);
786		break;
787	case ADT_CHAR2STAR:
788		string_list = ((union convert *)p_data)->tchar2star;
789		p_data = adt_adjust_address(p_data, sizeof (char **),
790		    sizeof (int));
791		arrayCount = ((union convert *)p_data)->tint;
792
793		if (arrayCount < 0)
794			arrayCount = 0;
795
796		if ((arrayCount > 0) && (string_list != NULL)) {
797			for (i = 0; i < arrayCount; i++) {
798				string = string_list[i];
799				if (string != NULL)
800					adt_write_text(event->ae_event_handle,
801					    string, format);
802			}
803		} else if (required) {
804			adt_write_text(event->ae_event_handle, empty, format);
805		} else {
806			break;
807		}
808		break;
809	default:
810		if (!have_syslogged) { /* don't flood the log */
811			adt_write_syslog("unsupported data conversion",
812			    ENOTSUP);
813			have_syslogged = 1;
814		}
815		break;
816	}
817	DFLUSH
818}
819
820/*
821 * AUT_UAUTH
822 */
823
824/* ARGSUSED */
825static void
826adt_to_uauth(datadef *def, void *p_data, int required,
827    struct adt_event_state *event, char *format)
828{
829	char		*string;
830
831	DPRINTF(("  adt_to_uauth dd_datatype=%d\n", def->dd_datatype));
832
833	string = ((union convert *)p_data)->tcharstar;
834
835	if (string == NULL) {
836		if (required) {
837			string = empty;
838		} else {
839			return;
840		}
841	}
842	DPRINTF(("  text=%s\n", string));
843	(void) au_write(event->ae_event_handle, au_to_uauth(string));
844}
845
846/*
847 * AUT_USER
848 */
849
850/* ARGSUSED */
851static void
852adt_to_user(datadef *def, void *p_data, int required,
853    struct adt_event_state *event, char *format)
854{
855	uid_t	uid;
856	char	*username;
857
858	DPRINTF(("  adt_to_user dd_datatype=%d\n", def->dd_datatype));
859
860	uid = ((union convert *)p_data)->tuid;
861	p_data = adt_adjust_address(p_data, sizeof (uid_t), sizeof (uid_t));
862
863	username = ((union convert *)p_data)->tcharstar;
864
865	if (username == NULL) {
866		if (required) {
867			username = empty;
868		} else {
869			return;
870		}
871	}
872	DPRINTF(("  username=%s\n", username));
873	(void) au_write(event->ae_event_handle, au_to_user(uid, username));
874}
875
876/*
877 * AUT_ZONENAME
878 */
879
880/* ARGSUSED */
881static void
882adt_to_zonename(datadef *def, void *p_data, int required,
883    struct adt_event_state *event, char *notUsed)
884{
885	char	*name;
886
887	name = ((union convert *)p_data)->tcharstar;
888
889	if (name != NULL) {
890		DPRINTF(("  name=%s\n", name));
891		(void) au_write(event->ae_event_handle, au_to_zonename(name));
892	} else {
893		DPRINTF(("  Null name\n"));
894		if (required) {
895			(void) au_write(event->ae_event_handle,
896			    au_to_zonename(empty));
897		}
898	}
899}
900
901/*
902 * ADT_IN_PEER dummy token
903 */
904
905/* ARGSUSED */
906static void
907adt_to_in_peer(datadef *def, void *p_data, int required,
908    struct adt_event_state *event, char *notUsed)
909{
910	int	sock;
911	struct sockaddr_in6 peer;
912	int	peerlen = sizeof (peer);
913
914	DPRINTF(("    adt_to_in_peer dd_datatype=%d\n", def->dd_datatype));
915
916	sock = ((union convert *)p_data)->tfd;
917
918	if (sock < 0) {
919		DPRINTF(("  Socket fd %d\n", sock));
920		if (required) {
921			adt_write_syslog("adt_to_in_peer no required socket",
922			    0);
923		}
924		return;
925	}
926	if (getpeername(sock, (struct sockaddr *)&peer, (socklen_t *)&peerlen)
927	    < 0) {
928
929		adt_write_syslog("adt_to_in_addr getpeername", errno);
930		return;
931	}
932	if (peer.sin6_family == AF_INET6) {
933		(void) au_write(event->ae_event_handle,
934		    au_to_in_addr_ex(&(peer.sin6_addr)));
935		(void) au_write(event->ae_event_handle,
936		    au_to_iport((ushort_t)peer.sin6_port));
937	} else {
938		(void) au_write(event->ae_event_handle,
939		    au_to_in_addr(&(((struct sockaddr_in *)&peer)->sin_addr)));
940		(void) au_write(event->ae_event_handle,
941		    au_to_iport(
942		    (ushort_t)(((struct sockaddr_in *)&peer)->sin_port)));
943	}
944}
945
946/*
947 * ADT_IN_REMOTE dummy token
948 *
949 * Similar to ADT_IN_PEER except the input is
950 * an IP address type (ADT_IPv4 | ADT_IPv6) and an address V4/V6
951 */
952
953/* ARGSUSED */
954static void
955adt_to_in_remote(datadef *def, void *p_data, int required,
956    struct adt_event_state *event, char *notUsed)
957{
958	int32_t	type;
959
960	DPRINTF(("    adt_to_in_remote dd_datatype=%d\n", def->dd_datatype));
961
962	type = ((union convert *)p_data)->tuint32;
963
964	if (type ==  0) {
965		if (required == 0) {
966			return;
967		}
968		/* required and not specified */
969		adt_write_syslog("adt_to_in_remote required address not "
970		    "specified", 0);
971		type = ADT_IPv4;
972	}
973	p_data = adt_adjust_address(p_data, sizeof (int32_t),
974	    sizeof (uint32_t));
975
976	switch (type) {
977	case ADT_IPv4:
978		(void) au_write(event->ae_event_handle, au_to_in_addr(
979		    (struct in_addr *)&(((union convert *)p_data)->tuint32)));
980		break;
981	case ADT_IPv6:
982		(void) au_write(event->ae_event_handle, au_to_in_addr_ex(
983		    (struct in6_addr *)&(((union convert *)p_data)->tuint32)));
984		break;
985	default:
986		adt_write_syslog("adt_to_in_remote invalid type", EINVAL);
987		return;
988	}
989}
990
991/*
992 * adt_to_iport takes a uint16_t IP port.
993 */
994
995/* ARGSUSED */
996static void
997adt_to_iport(datadef *def, void *p_data, int required,
998    struct adt_event_state *event, char *notUsed)
999{
1000	ushort_t port;
1001
1002	DPRINTF(("  adt_to_iport dd_datatype=%d\n", def->dd_datatype));
1003
1004	port = ((union convert *)p_data)->tuint16;
1005
1006	if (port == 0) {
1007		if (required == 0) {
1008			return;
1009		}
1010		/* required and not specified */
1011		adt_write_syslog("adt_to_iport no required port", 0);
1012	}
1013	(void) au_write(event->ae_event_handle, au_to_iport(port));
1014
1015}
1016
1017
1018/*
1019 *	This is a compact table that defines only the tokens that are
1020 * actually generated in the adt.xml file.  It can't be a  pure
1021 * indexed table because the adt.xml language defines internal extension
1022 * tokens for some processing.  VIZ. ADT_CMD_ALT, ADT_AUT_PRIV_* (see
1023 * adt_xlate.h), and the -AUT_PATH value.
1024 */
1025
1026#define	MAX_TOKEN_JMP 21
1027
1028static struct token_jmp token_table[MAX_TOKEN_JMP] =
1029{
1030	{AUT_CMD, adt_to_cmd},
1031	{ADT_CMD_ALT, adt_to_cmd1},
1032	{AUT_FMRI, adt_to_frmi},
1033	{ADT_IN_PEER, adt_to_in_peer},
1034	{ADT_IN_REMOTE, adt_to_in_remote},
1035	{AUT_IPORT, adt_to_iport},
1036	{AUT_LABEL, adt_to_label},
1037	{AUT_NEWGROUPS, adt_to_newgroups},
1038	{AUT_PATH, adt_to_path},
1039	{-AUT_PATH, adt_to_pathlist},	/* private extension of token values */
1040	{ADT_AUT_PRIV_L, adt_to_priv_limit},
1041	{ADT_AUT_PRIV_I, adt_to_priv_inherit},
1042	{ADT_AUT_PRIV_E, adt_to_priv_effective},
1043	{AUT_PROCESS, adt_to_process},
1044	{AUT_RETURN, adt_to_return},
1045	{AUT_SUBJECT, adt_to_subject},
1046	{AUT_TEXT, adt_to_text},
1047	{AUT_TID, adt_to_tid},
1048	{AUT_UAUTH, adt_to_uauth},
1049	{AUT_USER, adt_to_user},
1050	{AUT_ZONENAME, adt_to_zonename}
1051};
1052
1053/*
1054 *	{AUT_ACL, adt_to_acl},			not used
1055 *	{AUT_ARBITRARY, adt_to_arbitrary},	AUT_ARBITRARY is undefined
1056 *	{AUT_ARG, adt_to_arg},			not used
1057 *	{AUT_ATTR, adt_to_attr},		not used in mountd
1058 *	{AUT_XATOM, adt_to_atom},		not used
1059 *	{AUT_EXEC_ARGS, adt_to_exec_args},	not used
1060 *	{AUT_EXEC_ENV, adt_to_exec_env},	not used
1061 *	{AUT_EXIT, adt_to_exit},		obsolete
1062 *	{AUT_FILE, adt_to_file},		AUT_FILE is undefined
1063 *	{AUT_XCOLORMAP, adt_to_colormap},	not used
1064 *	{AUT_XCURSOR, adt_to_cursor},		not used
1065 *	{AUT_XFONT, adt_to_font},		not used
1066 *	{AUT_XGC, adt_to_gc},			not used
1067 *	{AUT_GROUPS, adt_to_groups},		obsolete
1068 *	{AUT_HEADER, adt_to_header},		generated by au_close
1069 *	{AUT_IP, adt_to_ip},			not used
1070 *	{AUT_IPC, adt_to_ipc},			not used
1071 *	{AUT_IPC_PERM, adt_to_ipc_perm},	not used
1072 *	{AUT_OPAQUE, adt_to_opaque},		not used
1073 *	{AUT_XPIXMAP, adt_to_pixmap},		not used
1074 *	{AUT_XPROPERTY, adt_to_property},	not used
1075 *	{AUT_SEQ, adt_to_seq},			not used
1076 *	{AUT_SOCKET, adt_to_socket},		not used
1077 *	{AUT_SOCKET_INET, adt_to_socket_inet},  AUT_SOCKET_INET is undefined
1078 *	{AUT_TRAILER, adt_to_trailer},		generated by au_close
1079 *	{AUT_XCLIENT, adt_to_xclient}		not used
1080 */
1081
1082/* find function to generate token */
1083
1084static adt_token_func_t
1085adt_getTokenFunction(char token_id)
1086{
1087	int	i;
1088	struct token_jmp	*p_jmp = token_table;
1089
1090	for (i = 0; i < MAX_TOKEN_JMP; i++) {
1091		if (token_id == p_jmp->jmp_id) {
1092			return (p_jmp->jmp_to);
1093		}
1094		p_jmp++;
1095	}
1096	errno = EINVAL;
1097	return (NULL);
1098}
1099
1100/*
1101 * adjustAddress -- given the address of data, its size, and the type of
1102 * the next data field, calculate the offset to the next piece of data.
1103 * Depending on the caller, "current" and "next" mean the current pointer
1104 * and the next pointer or the last pointer and the current pointer.
1105 */
1106void *
1107adt_adjust_address(void *current_address, size_t current_size,
1108    size_t next_size)
1109{
1110	ptrdiff_t adjustment;
1111	ptrdiff_t remainder;
1112
1113	adjustment = (size_t)current_address + current_size;
1114
1115	if (next_size) {
1116		remainder = adjustment % next_size;
1117		if (remainder != 0)
1118			adjustment += next_size - remainder;
1119	}
1120	return ((char *)adjustment);
1121}
1122