2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * adt_token.c
2N/A *
2N/A * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A *
2N/A * This file does not provide any user callable functions. See adt.c
2N/A */
2N/A
2N/A#include <bsm/adt.h>
2N/A#include <bsm/adt_event.h>
2N/A#include <bsm/audit.h>
2N/A
2N/A#include <adt_xlate.h>
2N/A#include <alloca.h>
2N/A#include <assert.h>
2N/A#include <netdb.h>
2N/A#include <priv.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <stdlib.h>
2N/A#include <time.h>
2N/A#include <unistd.h>
2N/A#include <inttypes.h>
2N/A
2N/A#include <sys/priv_names.h>
2N/A#include <sys/socket.h>
2N/A#include <sys/types.h>
2N/A#include <sys/stat.h>
2N/A#include <sys/vnode.h>
2N/A
2N/A#include <tsol/label.h>
2N/A
2N/A#ifdef C2_DEBUG
2N/A#define DPRINTF(x) { (void) printf x; }
2N/A#define DFLUSH (void) fflush(stdout);
2N/A
2N/A/* 0x + Classification + Compartments + end of string */
2N/A#define HEX_SIZE 2 + 2*2 + 2*32 + 1
2N/A
2N/Astatic char *
2N/Adprt_label(m_label_t *label)
2N/A{
2N/A static char hex[HEX_SIZE];
2N/A char *direct = NULL;
2N/A
2N/A if (label_to_str(label, &direct, M_INTERNAL, DEF_NAMES) != 0) {
2N/A adt_write_syslog("label_to_str(M_INTERNAL)", errno);
2N/A return ("hex label failed");
2N/A }
2N/A (void) strlcpy(hex, direct, sizeof (hex));
2N/A free(direct);
2N/A return (hex);
2N/A}
2N/A#else /* !C2_DEBUG */
2N/A#define DPRINTF(x)
2N/A#define DFLUSH
2N/A#endif /* C2_DEBUG */
2N/A
2N/Astatic adt_token_func_t adt_getTokenFunction(char);
2N/A
2N/Astatic char *empty = "";
2N/A
2N/A/*
2N/A * call adt_token_open() first and adt_token_close() last.
2N/A *
2N/A * au_open returns -1 if it cannot allocate an audit record descriptor,
2N/A * errno is either from calloc, if it cannot allocate the record descriptor
2N/A * table, or EMFILE if the table is of maximum size and has no available
2N/A * descriptors.
2N/A */
2N/A
2N/Aint
2N/Aadt_token_open(struct adt_event_state *event)
2N/A{
2N/A static int have_syslogged = 0;
2N/A
2N/A event->ae_event_handle = au_open();
2N/A if (event->ae_event_handle < 0) {
2N/A if (!have_syslogged) {
2N/A adt_write_syslog("au_open failed", errno);
2N/A have_syslogged = 1;
2N/A }
2N/A return (-1);
2N/A }
2N/A have_syslogged = 0;
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * call generate_token for each token in the order you want the tokens
2N/A * generated.
2N/A */
2N/A
2N/Avoid
2N/Aadt_generate_token(struct entry *p_entry, void *p_data,
2N/A struct adt_event_state *event)
2N/A{
2N/A adt_token_func_t p_func;
2N/A
2N/A assert((p_entry != NULL) && (p_data != NULL) && (event != NULL));
2N/A
2N/A p_func = adt_getTokenFunction(p_entry->en_token_id);
2N/A assert(p_func != NULL);
2N/A
2N/A DPRINTF(("p_entry=%p, p_data=%p, offset=%llu, msgFmt=%s\n",
2N/A (void *)p_entry, p_data, (long long)p_entry->en_offset,
2N/A p_entry->en_msg_format));
2N/A DFLUSH
2N/A (*p_func)(p_entry->en_type_def,
2N/A (char *)p_data + p_entry->en_offset, p_entry->en_required, event,
2N/A p_entry->en_msg_format);
2N/A}
2N/A
2N/A/* call this last */
2N/A
2N/Aint
2N/Aadt_token_close(struct adt_event_state *event)
2N/A{
2N/A if (au_close(event->ae_event_handle, AU_TO_WRITE,
2N/A event->ae_internal_id, event->ae_emod) != 0) {
2N/A int save_errno = errno;
2N/A
2N/A adt_write_syslog("au_close write failed", errno);
2N/A if (au_close(event->ae_event_handle, AU_TO_NO_WRITE, 0, 0)
2N/A != 0) {
2N/A adt_write_syslog("au_close no write failed", errno);
2N/A }
2N/A errno = save_errno;
2N/A return (-1);
2N/A }
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * one function per token -- see the jump table at the end of file
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_return(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A
2N/A#ifdef _LP64
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_return64((int64_t)event->ae_rc, event->ae_type));
2N/A#else
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_return32((int32_t)event->ae_rc, event->ae_type));
2N/A#endif
2N/A}
2N/A
2N/A/*
2N/A * AUT_CMD
2N/A *
2N/A * the command line is described with argc and argv and the environment
2N/A * with envp. The envp list is NULL terminated and has no separate
2N/A * counter; envp will be a NULL list unless the AUDIT_ARGE policy is
2N/A * set.
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_cmd(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A struct adt_internal_state *sp = event->ae_session;
2N/A int argc;
2N/A char **argv;
2N/A char **envp = NULL;
2N/A
2N/A argc = ((union convert *)p_data)->tint;
2N/A p_data = adt_adjust_address(p_data, sizeof (int), sizeof (char **));
2N/A argv = ((union convert *)p_data)->tchar2star;
2N/A p_data = adt_adjust_address(p_data, sizeof (char **), sizeof (char **));
2N/A
2N/A if (sp->as_kernel_audit_policy & AUDIT_ARGE)
2N/A envp = ((union convert *)p_data)->tchar2star;
2N/A
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_cmd(argc, argv, envp));
2N/A}
2N/A
2N/A/*
2N/A * special case of AUT_CMD with 1 argument that is
2N/A * a string showing the whole command and no envp
2N/A */
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_cmd1(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A char *string;
2N/A
2N/A string = ((union convert *)p_data)->tcharstar;
2N/A
2N/A if (string == NULL) {
2N/A if (required) {
2N/A string = empty;
2N/A } else {
2N/A return;
2N/A }
2N/A }
2N/A /* argc is hardcoded as 1 */
2N/A (void) au_write(event->ae_event_handle, au_to_cmd(1, &string,
2N/A NULL));
2N/A}
2N/A
2N/A/*
2N/A * adt_to_tid -- generic address (ip is only one defined at present)
2N/A * input:
2N/A * terminal type: ADT_IPv4, ADT_IPv6...
2N/A * case: ADT_IPv4 or ADT_IPv6...
2N/A * ip type
2N/A * remote port
2N/A * local port
2N/A * address
2N/A * case: not defined...
2N/A */
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_tid(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A au_generic_tid_t tid;
2N/A uint32_t type;
2N/A au_ip_t *ip;
2N/A
2N/A type = ((union convert *)p_data)->tuint32;
2N/A
2N/A switch (type) {
2N/A case ADT_IPv4:
2N/A case ADT_IPv6:
2N/A p_data = adt_adjust_address(p_data, sizeof (uint32_t),
2N/A sizeof (uint32_t));
2N/A
2N/A tid.gt_type = AU_IPADR;
2N/A ip = &(tid.gt_adr.at_ip);
2N/A
2N/A ip->at_type = (type == ADT_IPv4) ?
2N/A AU_IPv4 : AU_IPv6;
2N/A
2N/A ip->at_r_port = ((union convert *)p_data)->tuint16;
2N/A p_data = adt_adjust_address(p_data, sizeof (uint16_t),
2N/A sizeof (uint16_t));
2N/A
2N/A ip->at_l_port = ((union convert *)p_data)->tuint16;
2N/A
2N/A /* arg3 is for the array element, not the array size */
2N/A p_data = adt_adjust_address(p_data, sizeof (uint16_t),
2N/A sizeof (uint32_t));
2N/A
2N/A (void) memcpy(ip->at_addr, p_data, ip->at_type);
2N/A break;
2N/A default:
2N/A adt_write_syslog("Invalid terminal id type", EINVAL);
2N/A return;
2N/A }
2N/A (void) au_write(event->ae_event_handle, au_to_tid(&tid));
2N/A}
2N/A
2N/A/*
2N/A * au_to_frmi takes a char * that is the fmri.
2N/A */
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_frmi(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A char *fmri;
2N/A
2N/A DPRINTF((" adt_to_fmri dd_datatype=%d\n", def->dd_datatype));
2N/A
2N/A fmri = ((union convert *)p_data)->tcharstar;
2N/A
2N/A if (fmri == NULL) {
2N/A if (required) {
2N/A fmri = empty;
2N/A } else {
2N/A return;
2N/A }
2N/A }
2N/A DPRINTF((" fmri=%s\n", fmri));
2N/A (void) au_write(event->ae_event_handle, au_to_fmri(fmri));
2N/A}
2N/A
2N/A/*
2N/A * au_to_label takes an m_label_t * that is the label.
2N/A */
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_label(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A m_label_t *label;
2N/A
2N/A DPRINTF((" adt_to_label dd_datatype=%d\n", def->dd_datatype));
2N/A
2N/A label = ((union convert *)p_data)->tm_label;
2N/A
2N/A if (label != NULL) {
2N/A DPRINTF((" label=%s\n", dprt_label(label)));
2N/A DFLUSH
2N/A (void) au_write(event->ae_event_handle, au_to_label(label));
2N/A } else {
2N/A DPRINTF((" Null label\n"));
2N/A if (required)
2N/A adt_write_syslog("adt_to_label no required label",
2N/A EINVAL);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * au_to_newgroups takes a length and an array of gids
2N/A * as input. The input to adt_to_newgroups is a length
2N/A * and a pointer to an array of gids.
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_newgroups(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A int n;
2N/A gid_t *groups;
2N/A
2N/A n = ((union convert *)p_data)->tint;
2N/A if (n < 1) {
2N/A if (required) {
2N/A n = 0; /* in case negative n was passed */
2N/A } else {
2N/A return;
2N/A }
2N/A }
2N/A p_data = adt_adjust_address(p_data, sizeof (int), sizeof (int32_t *));
2N/A
2N/A groups = ((union convert *)p_data)->tgidstar;
2N/A
2N/A (void) au_write(event->ae_event_handle, au_to_newgroups(n, groups));
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_path(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A char *path;
2N/A
2N/A path = ((union convert *)p_data)->tcharstar;
2N/A
2N/A if (path != NULL) {
2N/A DPRINTF((" path=%s\n", path));
2N/A (void) au_write(event->ae_event_handle, au_to_path(path));
2N/A } else {
2N/A DPRINTF((" Null path\n"));
2N/A if (required) {
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_path(empty));
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * dummy token id: AUT_PATHLIST
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_pathlist(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A char *path;
2N/A char *working_buf;
2N/A char *pathlist;
2N/A char *last_str;
2N/A
2N/A pathlist = ((union convert *)p_data)->tcharstar;
2N/A
2N/A if (pathlist != NULL) {
2N/A working_buf = strdup(pathlist);
2N/A if (working_buf == NULL) {
2N/A adt_write_syslog("audit failure", errno);
2N/A if (required) {
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_path(empty));
2N/A }
2N/A return;
2N/A }
2N/A for (path = strtok_r(working_buf, " ", &last_str);
2N/A path; path = strtok_r(NULL, " ", &last_str)) {
2N/A DPRINTF((" path=%s\n", path));
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_path(path));
2N/A }
2N/A free(working_buf);
2N/A } else {
2N/A DPRINTF((" Null path list\n"));
2N/A if (required)
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_path(empty));
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * AUT_PRIV
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_priv(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, const char *priv_type)
2N/A{
2N/A priv_set_t *privilege;
2N/A
2N/A privilege = ((union convert *)p_data)->tprivstar;
2N/A
2N/A if (privilege != NULL) {
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_privset(priv_type, privilege));
2N/A } else {
2N/A if (required) {
2N/A DPRINTF((" Null privilege\n"));
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_privset(empty, NULL));
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * -AUT_PRIV_L AUT_PRIV for a limit set
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_priv_limit(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A adt_to_priv(def, p_data, required, event, PRIV_LIMIT);
2N/A}
2N/A
2N/A/*
2N/A * -AUT_PRIV_I AUT_PRIV for an inherit set
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_priv_inherit(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A adt_to_priv(def, p_data, required, event, PRIV_INHERITABLE);
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_priv_effective(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A adt_to_priv(def, p_data, required, event, PRIV_EFFECTIVE);
2N/A}
2N/A
2N/Astatic void
2N/AgetCharacteristics(struct auditpinfo_addr *info, pid_t *pid)
2N/A{
2N/A int rc;
2N/A
2N/A if (*pid == 0) { /* getpinfo for this pid */
2N/A info->ap_pid = getpid();
2N/A } else {
2N/A info->ap_pid = *pid;
2N/A }
2N/A
2N/A rc = auditon(A_GETPINFO_ADDR, (caddr_t)info,
2N/A sizeof (struct auditpinfo_addr));
2N/A if (rc == -1) {
2N/A info->ap_auid = AU_NOAUDITID;
2N/A info->ap_asid = 0;
2N/A (void) memset((void *)&(info->ap_termid), 0,
2N/A sizeof (au_tid_addr_t));
2N/A info->ap_termid.at_type = AU_IPv4;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * AUT_PROCESS
2N/A *
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_process(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A au_id_t auid;
2N/A uid_t euid;
2N/A gid_t egid;
2N/A uid_t ruid;
2N/A gid_t rgid;
2N/A pid_t pid;
2N/A au_asid_t sid;
2N/A au_tid_addr_t *tid;
2N/A struct auditpinfo_addr info;
2N/A
2N/A auid = ((union convert *)p_data)->tuid;
2N/A p_data = adt_adjust_address(p_data, sizeof (uid_t), sizeof (uid_t));
2N/A euid = ((union convert *)p_data)->tuid;
2N/A p_data = adt_adjust_address(p_data, sizeof (uid_t), sizeof (gid_t));
2N/A egid = ((union convert *)p_data)->tgid;
2N/A p_data = adt_adjust_address(p_data, sizeof (gid_t), sizeof (uid_t));
2N/A ruid = ((union convert *)p_data)->tuid;
2N/A p_data = adt_adjust_address(p_data, sizeof (uid_t), sizeof (gid_t));
2N/A rgid = ((union convert *)p_data)->tgid;
2N/A p_data = adt_adjust_address(p_data, sizeof (gid_t), sizeof (pid_t));
2N/A pid = ((union convert *)p_data)->tpid;
2N/A p_data = adt_adjust_address(p_data, sizeof (pid_t), sizeof (uint32_t));
2N/A sid = ((union convert *)p_data)->tuint32;
2N/A p_data = adt_adjust_address(p_data, sizeof (uint32_t),
2N/A sizeof (au_tid_addr_t *));
2N/A tid = ((union convert *)p_data)->ttermid;
2N/A
2N/A getCharacteristics(&info, &pid);
2N/A
2N/A if (auid == AU_NOAUDITID)
2N/A auid = info.ap_auid;
2N/A
2N/A if (euid == AU_NOAUDITID)
2N/A euid = geteuid();
2N/A
2N/A if (egid == AU_NOAUDITID)
2N/A egid = getegid();
2N/A
2N/A if (ruid == AU_NOAUDITID)
2N/A ruid = getuid();
2N/A
2N/A if (rgid == AU_NOAUDITID)
2N/A rgid = getgid();
2N/A
2N/A if (tid == NULL)
2N/A tid = &(info.ap_termid);
2N/A
2N/A if (sid == 0)
2N/A sid = info.ap_asid;
2N/A
2N/A if (pid == 0)
2N/A pid = info.ap_pid;
2N/A
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_process_ex(auid, euid, egid, ruid, rgid, pid, sid, tid));
2N/A}
2N/A
2N/A/*
2N/A * Generate subject information.
2N/A * If labels are present, generate the subject label token.
2N/A * If the group audit policy is set, generate the subject group token.
2N/A *
2N/A * The required flag does not apply here.
2N/A *
2N/A * Non-attributable records are indicated by an auid of AU_NOAUDITID;
2N/A * no subject token or group token is generated for a non-attributable
2N/A * record.
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_subject(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A struct adt_internal_state *sp = event->ae_session;
2N/A
2N/A if (sp->as_info.ai_auid == AU_NOAUDITID)
2N/A return;
2N/A
2N/A assert(sp->as_have_user_data == ADT_HAVE_ALL);
2N/A
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_subject_ex(sp->as_info.ai_auid,
2N/A sp->as_euid, sp->as_egid, sp->as_ruid, sp->as_rgid,
2N/A sp->as_pid, sp->as_info.ai_asid,
2N/A &(sp->as_info.ai_termid)));
2N/A if (is_system_labeled()) {
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_label(sp->as_label));
2N/A }
2N/A /*
2N/A * Add optional tokens if in the process model.
2N/A * In a session model, the groups list is undefined and label
2N/A * is in the state.
2N/A */
2N/A if (sp->as_session_model == ADT_PROCESS_MODEL) {
2N/A if (sp->as_kernel_audit_policy & AUDIT_GROUP) {
2N/A int group_count;
2N/A int maxgrp = getgroups(0, NULL);
2N/A gid_t *grouplist = alloca(maxgrp * sizeof (gid_t));
2N/A
2N/A if ((group_count = getgroups(maxgrp, grouplist)) > 0) {
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_newgroups(group_count, grouplist));
2N/A }
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * adt_to_text()
2N/A *
2N/A * The format string, normally null, is sort of a wrapper around
2N/A * the input. adt_write_text() is a wrapper around au_write that
2N/A * handles the format string
2N/A *
2N/A */
2N/A#define TEXT_LENGTH 49
2N/A
2N/A#define WRITE_TEXT(handle, val, format) { \
2N/A if (asprintf(&cvt, format, val) != -1) { \
2N/A DPRINTF((" text=%s\n", cvt)); \
2N/A (void) au_write(handle, au_to_text(cvt)); \
2N/A free(cvt); \
2N/A } else { \
2N/A (void) au_write(handle, au_to_text("asprintf failure")); \
2N/A } \
2N/A}
2N/A
2N/Astatic void
2N/Aadt_to_text(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *format)
2N/A{
2N/A static int have_syslogged = 0;
2N/A char *string;
2N/A char *cvt; /* used by WRITE_TEXT */
2N/A int arrayCount;
2N/A
2N/A DPRINTF((" adt_to_text dd_datatype=%d\n", def->dd_datatype));
2N/A switch (def->dd_datatype) {
2N/A case ADT_DATE: {
2N/A /*
2N/A * Consider creating a separate token type for dates
2N/A * -- store as longs and format them in praudit.
2N/A * For now, a date is input as a time_t and output as
2N/A * a text token. If we do this, we need to consider
2N/A * carrying timezone info so that praudit can
2N/A * represent times in an unambiguous manner.
2N/A */
2N/A time_t date;
2N/A struct tm tm;
2N/A char buffer[TEXT_LENGTH + 1];
2N/A
2N/A date = ((union convert *)p_data)->tlong;
2N/A if (strftime(buffer, sizeof (buffer), "%x",
2N/A localtime_r(&date, &tm)) > TEXT_LENGTH) {
2N/A if (required) {
2N/A (void) strncpy(buffer, "invalid date",
2N/A TEXT_LENGTH);
2N/A } else {
2N/A break;
2N/A }
2N/A }
2N/A DPRINTF((" text=%s\n", buffer));
2N/A WRITE_TEXT(event->ae_event_handle, buffer,
2N/A format != NULL ? format : "%s");
2N/A break;
2N/A }
2N/A case ADT_MSG: {
2N/A /*
2N/A * The "input size" is overloaded to mean the list number
2N/A * and the msg_selector indexes the desired string in
2N/A * that list
2N/A */
2N/A struct msg_text *list;
2N/A int list_index;
2N/A
2N/A list = &adt_msg_text[(enum adt_msg_list)def->dd_input_size];
2N/A list_index = ((union convert *)p_data)->msg_selector;
2N/A
2N/A if ((list_index + list->ml_offset < list->ml_min_index) ||
2N/A (list_index + list->ml_offset > list->ml_max_index)) {
2N/A string = "Invalid message index";
2N/A } else {
2N/A string = list->ml_msg_list[list_index +
2N/A list->ml_offset];
2N/A }
2N/A
2N/A if (string == NULL) { /* null is valid; means skip */
2N/A if (required) {
2N/A string = empty;
2N/A } else {
2N/A break;
2N/A }
2N/A }
2N/A DPRINTF((" text=%s\n", string));
2N/A WRITE_TEXT(event->ae_event_handle, string,
2N/A format != NULL ? format : "%s");
2N/A break;
2N/A }
2N/A case ADT_UID:
2N/A case ADT_GID:
2N/A case ADT_UINT:
2N/A case ADT_UINT32:
2N/A WRITE_TEXT(event->ae_event_handle,
2N/A ((union convert *)p_data)->tuint,
2N/A format != NULL ? format : "%u");
2N/A break;
2N/A case ADT_INT:
2N/A case ADT_INT32:
2N/A WRITE_TEXT(event->ae_event_handle,
2N/A ((union convert *)p_data)->tint,
2N/A format != NULL ? format : "%d");
2N/A break;
2N/A case ADT_LONG:
2N/A WRITE_TEXT(event->ae_event_handle,
2N/A ((union convert *)p_data)->tlong,
2N/A format != NULL ? format : "%ld");
2N/A break;
2N/A case ADT_UIDSTAR:
2N/A case ADT_GIDSTAR:
2N/A case ADT_UINT32STAR: {
2N/A uint32_t *int_list;
2N/A
2N/A int_list = ((union convert *)p_data)->tuint32star;
2N/A p_data = adt_adjust_address(p_data, sizeof (int *),
2N/A sizeof (int));
2N/A arrayCount = ((union convert *)p_data)->tint;
2N/A
2N/A string = NULL;
2N/A
2N/A if ((arrayCount > 0) && (int_list != NULL)) {
2N/A int written;
2N/A int i;
2N/A int total = 0;
2N/A
2N/A for (i = 0; i < arrayCount; i++) {
2N/A char *tmp_string;
2N/A
2N/A written = asprintf(&tmp_string,
2N/A format != NULL ? format : "%u ",
2N/A *int_list++);
2N/A if (written == -1) {
2N/A goto mem_err;
2N/A }
2N/A total += written;
2N/A if (i == 0) {
2N/A string = tmp_string;
2N/A } else {
2N/A char *new_string;
2N/A
2N/A new_string = realloc(string, total + 1);
2N/A if (new_string == NULL) {
2N/A goto mem_err;
2N/A }
2N/A (void) strcat(new_string, tmp_string);
2N/A free(tmp_string);
2N/A string = new_string;
2N/A }
2N/A }
2N/A } else if (required) {
2N/A string = empty;
2N/A } else {
2N/A break;
2N/A }
2N/A WRITE_TEXT(event->ae_event_handle, string, "%s");
2N/A free(string);
2N/A break;
2N/A mem_err:
2N/A free(string);
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_text("Memory Allocation Failure"));
2N/A break;
2N/A }
2N/A case ADT_ULONG:
2N/A WRITE_TEXT(event->ae_event_handle,
2N/A ((union convert *)p_data)->tulong,
2N/A format != NULL ? format : "%lu");
2N/A break;
2N/A case ADT_UINT64:
2N/A WRITE_TEXT(event->ae_event_handle,
2N/A ((union convert *)p_data)->tuint64,
2N/A format != NULL ? format : "%llu");
2N/A break;
2N/A case ADT_CHARSTAR:
2N/A string = ((union convert *)p_data)->tcharstar;
2N/A
2N/A if (string == NULL) {
2N/A if (required) {
2N/A string = empty;
2N/A } else {
2N/A break;
2N/A }
2N/A }
2N/A DPRINTF((" text=%s\n", string));
2N/A WRITE_TEXT(event->ae_event_handle, string,
2N/A format != NULL ? format : "%s");
2N/A break;
2N/A case ADT_CHAR2STAR: {
2N/A char **string_list;
2N/A
2N/A string_list = ((union convert *)p_data)->tchar2star;
2N/A p_data = adt_adjust_address(p_data, sizeof (char **),
2N/A sizeof (int));
2N/A arrayCount = ((union convert *)p_data)->tint;
2N/A
2N/A if ((arrayCount > 0) && (string_list != NULL)) {
2N/A int i;
2N/A
2N/A for (i = 0; i < arrayCount; i++) {
2N/A if (string_list[i] != NULL) {
2N/A WRITE_TEXT(event->ae_event_handle,
2N/A string_list[i],
2N/A format != NULL ? format : "%s");
2N/A }
2N/A }
2N/A } else if (required) {
2N/A WRITE_TEXT(event->ae_event_handle, empty,
2N/A format != NULL ? format : "%s");
2N/A } else {
2N/A break;
2N/A }
2N/A break;
2N/A }
2N/A default:
2N/A if (!have_syslogged) { /* don't flood the log */
2N/A adt_write_syslog("unsupported data conversion",
2N/A ENOTSUP);
2N/A have_syslogged = 1;
2N/A }
2N/A break;
2N/A
2N/A }
2N/A DFLUSH
2N/A}
2N/A
2N/A/*
2N/A * AUT_UAUTH
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_uauth(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *format)
2N/A{
2N/A char *string;
2N/A
2N/A DPRINTF((" adt_to_uauth dd_datatype=%d\n", def->dd_datatype));
2N/A
2N/A string = ((union convert *)p_data)->tcharstar;
2N/A
2N/A if (string == NULL) {
2N/A if (required) {
2N/A string = empty;
2N/A } else {
2N/A return;
2N/A }
2N/A }
2N/A DPRINTF((" text=%s\n", string));
2N/A (void) au_write(event->ae_event_handle, au_to_uauth(string));
2N/A}
2N/A
2N/A/*
2N/A * AUT_USER
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_user(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *format)
2N/A{
2N/A uid_t uid;
2N/A char *username;
2N/A
2N/A DPRINTF((" adt_to_user dd_datatype=%d\n", def->dd_datatype));
2N/A
2N/A uid = ((union convert *)p_data)->tuid;
2N/A p_data = adt_adjust_address(p_data, sizeof (uid_t), sizeof (uid_t));
2N/A
2N/A username = ((union convert *)p_data)->tcharstar;
2N/A
2N/A if (username == NULL) {
2N/A if (required) {
2N/A username = empty;
2N/A } else {
2N/A return;
2N/A }
2N/A }
2N/A DPRINTF((" username=%s\n", username));
2N/A (void) au_write(event->ae_event_handle, au_to_user(uid, username));
2N/A}
2N/A
2N/A/*
2N/A * AUT_XCLIENT
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_xclient(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *format)
2N/A{
2N/A uint32_t client;
2N/A
2N/A DPRINTF((" adt_to_xclient dd_datatype=%d\n", def->dd_datatype));
2N/A
2N/A client = ((union convert *)p_data)->tuint32;
2N/A
2N/A if (client == 0 && required == 0) {
2N/A return;
2N/A }
2N/A DPRINTF((" client=%u\n", client));
2N/A (void) au_write(event->ae_event_handle, au_to_xclient(client));
2N/A}
2N/A
2N/A/*
2N/A * AUT_ZONENAME
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_zonename(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A char *name;
2N/A
2N/A name = ((union convert *)p_data)->tcharstar;
2N/A
2N/A if (name != NULL) {
2N/A DPRINTF((" name=%s\n", name));
2N/A (void) au_write(event->ae_event_handle, au_to_zonename(name));
2N/A } else {
2N/A DPRINTF((" Null name\n"));
2N/A if (required) {
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_zonename(empty));
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * ADT_IN_PEER dummy token
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_in_peer(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A long sa_buf[(sizeof (short) + PATH_MAX + sizeof (long) - 1) /
2N/A sizeof (long)];
2N/A char sun_path[PATH_MAX];
2N/A struct sockaddr *sa = (struct sockaddr *)sa_buf;
2N/A struct sockaddr_un *sa_un = (struct sockaddr_un *)sa_buf;
2N/A struct sockaddr_in *sa_in = (struct sockaddr_in *)sa_buf;
2N/A struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa_buf;
2N/A int socket;
2N/A socklen_t len;
2N/A
2N/A DPRINTF((" adt_to_in_peer dd_datatype=%d\n", def->dd_datatype));
2N/A
2N/A /* The consumer is expected to provide a valid socket. */
2N/A socket = ((union convert *)p_data)->tfd;
2N/A if (socket < 0) {
2N/A DPRINTF((" Socket fd %d\n", socket));
2N/A if (required != 0) {
2N/A adt_write_syslog("adt_to_in_peer no required socket",
2N/A EINVAL);
2N/A }
2N/A return;
2N/A }
2N/A
2N/A /* Try inet family first. */
2N/A len = sizeof (sa_buf);
2N/A if (getpeername(socket, sa, &len) == -1) {
2N/A if (required != 0) {
2N/A adt_write_syslog("adt_to_in_peer getpeername", errno);
2N/A }
2N/A return;
2N/A }
2N/A
2N/A switch (sa->sa_family) {
2N/A case AF_UNIX:
2N/A len = sizeof (sa_buf);
2N/A if (getsockname(socket, sa, &len) == -1) {
2N/A if (required != 0) {
2N/A adt_write_syslog("adt_to_in_peer getsockname",
2N/A errno);
2N/A }
2N/A break;
2N/A }
2N/A if (len < sizeof (sa_un->sun_family)) {
2N/A break;
2N/A }
2N/A sa_un->sun_path[len - sizeof (sa_un->sun_family)] = '\0';
2N/A /*
2N/A * Pathname returned by getsockname() may be relative. We need
2N/A * to make it absolute.
2N/A */
2N/A if (realpath(sa_un->sun_path, sun_path) == NULL) {
2N/A /* Record unresolved path if nothing else. */
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_path(sa_un->sun_path));
2N/A break;
2N/A }
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_path(sun_path));
2N/A break;
2N/A case AF_INET6:
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_in_addr_ex(&sa_in6->sin6_addr));
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_iport((ushort_t)(sa_in6->sin6_port)));
2N/A break;
2N/A case AF_INET:
2N/A case AF_INET_SDP:
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_in_addr(&sa_in->sin_addr));
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_iport((ushort_t)(sa_in->sin_port)));
2N/A break;
2N/A default:
2N/A if (required != 0) {
2N/A adt_write_syslog("adt_to_in_peer invalid socket family",
2N/A EINVAL);
2N/A }
2N/A break;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * ADT_IN_REMOTE dummy token
2N/A *
2N/A * Similar to ADT_IN_PEER except the input is
2N/A * an IP address type (ADT_IPv4 | ADT_IPv6) and an address V4/V6
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_in_remote(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A int32_t type;
2N/A
2N/A DPRINTF((" adt_to_in_remote dd_datatype=%d\n", def->dd_datatype));
2N/A
2N/A type = ((union convert *)p_data)->tuint32;
2N/A
2N/A if (type == 0) {
2N/A if (required == 0) {
2N/A return;
2N/A }
2N/A /* required and not specified */
2N/A adt_write_syslog("adt_to_in_remote required address not "
2N/A "specified", EINVAL);
2N/A type = ADT_IPv4;
2N/A }
2N/A p_data = adt_adjust_address(p_data, sizeof (int32_t),
2N/A sizeof (uint32_t));
2N/A
2N/A switch (type) {
2N/A case ADT_IPv4:
2N/A (void) au_write(event->ae_event_handle, au_to_in_addr(
2N/A (struct in_addr *)&(((union convert *)p_data)->tuint32)));
2N/A break;
2N/A case ADT_IPv6:
2N/A (void) au_write(event->ae_event_handle, au_to_in_addr_ex(
2N/A (struct in6_addr *)&(((union convert *)p_data)->tuint32)));
2N/A break;
2N/A default:
2N/A adt_write_syslog("adt_to_in_remote invalid type", EINVAL);
2N/A return;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * adt_to_iport takes a uint16_t IP port.
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_iport(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A ushort_t port;
2N/A
2N/A DPRINTF((" adt_to_iport dd_datatype=%d\n", def->dd_datatype));
2N/A
2N/A port = ((union convert *)p_data)->tuint16;
2N/A
2N/A if (port == 0) {
2N/A if (required == 0) {
2N/A return;
2N/A }
2N/A /* required and not specified */
2N/A adt_write_syslog("adt_to_iport no required port", EINVAL);
2N/A }
2N/A (void) au_write(event->ae_event_handle, au_to_iport(port));
2N/A
2N/A}
2N/A
2N/A/*
2N/A * AUT_ATTR64
2N/A */
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_attr(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A struct stat64 *attr;
2N/A struct stat64 empty;
2N/A
2N/A attr = ((union convert *)p_data)->tstatstar;
2N/A if (attr == NULL) {
2N/A if (!required) {
2N/A return;
2N/A }
2N/A bzero((void *)&empty, sizeof (struct stat64));
2N/A attr = &empty;
2N/A }
2N/A
2N/A (void) au_write(event->ae_event_handle, au_to_attr(attr));
2N/A}
2N/A
2N/A/* ARGSUSED */
2N/Astatic void
2N/Aadt_to_arg(datadef *def, void *p_data, int required,
2N/A struct adt_event_state *event, char *notUsed)
2N/A{
2N/A char arg_id;
2N/A uint64_t arg64;
2N/A uint32_t arg32;
2N/A char *desc = NULL;
2N/A datatype_t type = def->dd_datatype;
2N/A
2N/A switch (type) {
2N/A case ADT_UINT32:
2N/A /* get the argument value */
2N/A arg32 = ((union convert *)p_data)->tuint32;
2N/A p_data = adt_adjust_address(p_data, sizeof (uint32_t),
2N/A sizeof (char));
2N/A break;
2N/A case ADT_UINT64:
2N/A /* get the argument value */
2N/A arg64 = ((union convert *)p_data)->tuint64;
2N/A p_data = adt_adjust_address(p_data, sizeof (uint64_t),
2N/A sizeof (char));
2N/A break;
2N/A default:
2N/A adt_write_syslog("unsupported data conversion", ENOTSUP);
2N/A if (!required) {
2N/A return;
2N/A }
2N/A type = ADT_UINT32;
2N/A arg_id = 0;
2N/A arg32 = 0;
2N/A desc = empty;
2N/A goto finish;
2N/A }
2N/A
2N/A /* get the argument id */
2N/A arg_id = ((union convert *)p_data)->tchar;
2N/A
2N/A /* get the argument description */
2N/A p_data = adt_adjust_address(p_data, sizeof (char), sizeof (char *));
2N/A desc = ((union convert *)p_data)->tcharstar;
2N/A if (desc == NULL) {
2N/A if (!required) {
2N/A return;
2N/A }
2N/A arg_id = 0;
2N/A arg32 = 0;
2N/A arg64 = 0ULL;
2N/A desc = empty;
2N/A /* required and not specified */
2N/A adt_write_syslog("adt_to_arg required token not specified",
2N/A EINVAL);
2N/A }
2N/Afinish:
2N/A if (type == ADT_UINT32) {
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_arg32(arg_id, desc, arg32));
2N/A } else {
2N/A (void) au_write(event->ae_event_handle,
2N/A au_to_arg64(arg_id, desc, arg64));
2N/A }
2N/A}
2N/A
2N/A
2N/A/*
2N/A * This is a compact table that defines only the tokens that are
2N/A * actually generated in the adt.xml file. It can't be a pure
2N/A * indexed table because the adt.xml language defines internal extension
2N/A * tokens for some processing. VIZ. ADT_CMD_ALT, ADT_AUT_PRIV_* (see
2N/A * adt_xlate.h), and the -AUT_PATH value.
2N/A */
2N/A
2N/A#define MAX_TOKEN_JMP 24
2N/A
2N/Astatic struct token_jmp token_table[MAX_TOKEN_JMP] =
2N/A{
2N/A {AUT_ARG, adt_to_arg},
2N/A {AUT_ATTR64, adt_to_attr},
2N/A {AUT_CMD, adt_to_cmd},
2N/A {ADT_CMD_ALT, adt_to_cmd1},
2N/A {AUT_FMRI, adt_to_frmi},
2N/A {ADT_IN_PEER, adt_to_in_peer},
2N/A {ADT_IN_REMOTE, adt_to_in_remote},
2N/A {AUT_IPORT, adt_to_iport},
2N/A {AUT_LABEL, adt_to_label},
2N/A {AUT_NEWGROUPS, adt_to_newgroups},
2N/A {AUT_PATH, adt_to_path},
2N/A {-AUT_PATH, adt_to_pathlist}, /* private extension of token values */
2N/A {ADT_AUT_PRIV_L, adt_to_priv_limit},
2N/A {ADT_AUT_PRIV_I, adt_to_priv_inherit},
2N/A {ADT_AUT_PRIV_E, adt_to_priv_effective},
2N/A {AUT_PROCESS, adt_to_process},
2N/A {AUT_RETURN, adt_to_return},
2N/A {AUT_SUBJECT, adt_to_subject},
2N/A {AUT_TEXT, adt_to_text},
2N/A {AUT_TID, adt_to_tid},
2N/A {AUT_UAUTH, adt_to_uauth},
2N/A {AUT_USER, adt_to_user},
2N/A {AUT_XCLIENT, adt_to_xclient},
2N/A {AUT_ZONENAME, adt_to_zonename}
2N/A};
2N/A
2N/A/*
2N/A * {AUT_ACL, adt_to_acl}, not used
2N/A * {AUT_ARBITRARY, adt_to_arbitrary}, AUT_ARBITRARY is undefined
2N/A * {AUT_XATOM, adt_to_atom}, not used
2N/A * {AUT_EXEC_ARGS, adt_to_exec_args}, not used
2N/A * {AUT_EXEC_ENV, adt_to_exec_env}, not used
2N/A * {AUT_EXIT, adt_to_exit}, obsolete
2N/A * {AUT_FILE, adt_to_file}, AUT_FILE is undefined
2N/A * {AUT_XCOLORMAP, adt_to_colormap}, not used
2N/A * {AUT_XCURSOR, adt_to_cursor}, not used
2N/A * {AUT_XFONT, adt_to_font}, not used
2N/A * {AUT_XGC, adt_to_gc}, not used
2N/A * {AUT_GROUPS, adt_to_groups}, obsolete
2N/A * {AUT_HEADER, adt_to_header}, generated by au_close
2N/A * {AUT_IP, adt_to_ip}, not used
2N/A * {AUT_IPC, adt_to_ipc}, not used
2N/A * {AUT_IPC_PERM, adt_to_ipc_perm}, not used
2N/A * {AUT_OPAQUE, adt_to_opaque}, not used
2N/A * {AUT_XPIXMAP, adt_to_pixmap}, not used
2N/A * {AUT_XPROPERTY, adt_to_property}, not used
2N/A * {AUT_SEQ, adt_to_seq}, not used
2N/A * {AUT_SOCKET, adt_to_socket}, not used
2N/A * {AUT_SOCKET_INET, adt_to_socket_inet}, AUT_SOCKET_INET is undefined
2N/A * {AUT_TRAILER, adt_to_trailer}, generated by au_close
2N/A */
2N/A
2N/A/* find function to generate token */
2N/A
2N/Astatic adt_token_func_t
2N/Aadt_getTokenFunction(char token_id)
2N/A{
2N/A int i;
2N/A struct token_jmp *p_jmp = token_table;
2N/A
2N/A for (i = 0; i < MAX_TOKEN_JMP; i++) {
2N/A if (token_id == p_jmp->jmp_id) {
2N/A return (p_jmp->jmp_to);
2N/A }
2N/A p_jmp++;
2N/A }
2N/A errno = EINVAL;
2N/A return (NULL);
2N/A}
2N/A
2N/A/*
2N/A * adjustAddress -- given the address of data, its size, and the type of
2N/A * the next data field, calculate the offset to the next piece of data.
2N/A * Depending on the caller, "current" and "next" mean the current pointer
2N/A * and the next pointer or the last pointer and the current pointer.
2N/A */
2N/Avoid *
2N/Aadt_adjust_address(void *current_address, size_t current_size,
2N/A size_t next_size)
2N/A{
2N/A ptrdiff_t adjustment;
2N/A ptrdiff_t remainder;
2N/A
2N/A adjustment = (size_t)current_address + current_size;
2N/A
2N/A if (next_size) {
2N/A remainder = adjustment % next_size;
2N/A if (remainder != 0)
2N/A adjustment += next_size - remainder;
2N/A }
2N/A return ((char *)adjustment);
2N/A}