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/*
2N/A * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * This file contains the code that creates ASR audit messages.
2N/A */
2N/A#include <errno.h>
2N/A#include <inttypes.h>
2N/A#include <libscf.h>
2N/A#include <string.h>
2N/A#include <sys/fm/protocol.h>
2N/A#include <unistd.h>
2N/A#include <uuid/uuid.h>
2N/A
2N/A#include "asr.h"
2N/A#include "asr_buf.h"
2N/A#include "asr_mem.h"
2N/A#include "asr_err.h"
2N/A#include "asr_nvl.h"
2N/A
2N/A#define PKG_INFO_CMD "/usr/bin/pkg info"
2N/A#define PAD_COMPONENT 2
2N/A#define PAD_ITEM 3
2N/A
2N/A/* Default initial buffer sizes. They will grow if needed. */
2N/A#define ASR_AUDIT_BUFSIZE (1024*2048)
2N/A#define ASR_AUDIT_LINESIZE 128
2N/A#define ASR_AUDIT_PAYLOAD_GENERIC "generic"
2N/A
2N/A#define CHECK_FOR_ERR(e) if ((e)) goto finally
2N/A#define CHECK_NOT_NULL(pointer) if ((pointer) == NULL) goto finally
2N/A
2N/A/*
2N/A * Logs a topology error to the ASR log.
2N/A */
2N/Astatic int
2N/Aasr_topo_error(asr_handle_t *ah, int err)
2N/A{
2N/A asr_log_error(ah, EASR_TOPO,
2N/A "asr_topo: %s", topo_strerror(err));
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Gets a copy of an FMRI string from a name/value list.
2N/A * The returned string must be freed when no longer needed.
2N/A * If there is an error NULL will be returned and asr_errno will be set.
2N/A */
2N/Astatic char *
2N/Aasr_get_fmri_strcpy(asr_topo_enum_data_t *edata, nvlist_t *fmri)
2N/A{
2N/A char *fmristr, *ret_fmri = NULL;
2N/A int err;
2N/A
2N/A if (fmri == NULL)
2N/A return (NULL);
2N/A if (topo_fmri_nvl2str(edata->asr_topoh, fmri, &fmristr, &err) != 0) {
2N/A (void) asr_topo_error(edata->asr_hdl, err);
2N/A goto finally;
2N/A }
2N/A if (fmristr != NULL) {
2N/A ret_fmri = asr_strdup(fmristr);
2N/A if (ret_fmri == NULL)
2N/A (void) asr_set_errno(EASR_NOMEM);
2N/A topo_hdl_strfree(edata->asr_topoh, fmristr);
2N/A }
2N/Afinally:
2N/A nvlist_free(fmri);
2N/A return (ret_fmri);
2N/A}
2N/A
2N/A/*
2N/A * Gets the FRU from a topo node as a string.
2N/A */
2N/Astatic char *
2N/Aasr_get_fru(asr_topo_enum_data_t *edata, tnode_t *node)
2N/A{
2N/A nvlist_t *fmri;
2N/A int err;
2N/A
2N/A if (topo_node_fru(node, &fmri, NULL, &err) != 0) {
2N/A return (NULL);
2N/A }
2N/A return (asr_get_fmri_strcpy(edata, fmri));
2N/A}
2N/A
2N/A/*
2N/A * Gets the ASRU from a topo node as a string.
2N/A */
2N/Astatic char *
2N/Aasr_get_asru(asr_topo_enum_data_t *edata, tnode_t *node)
2N/A{
2N/A nvlist_t *fmri;
2N/A int err;
2N/A
2N/A if (topo_node_asru(node, &fmri, NULL, &err) != 0) {
2N/A return (NULL);
2N/A }
2N/A return (asr_get_fmri_strcpy(edata, fmri));
2N/A}
2N/A
2N/A/*
2N/A * Gets the resouce from a topo node as a string.
2N/A */
2N/Astatic char *
2N/Aasr_get_resource(asr_topo_enum_data_t *edata, tnode_t *node)
2N/A{
2N/A nvlist_t *fmri;
2N/A int err;
2N/A
2N/A if (topo_node_resource(node, &fmri, &err) != 0) {
2N/A return (NULL);
2N/A }
2N/A return (asr_get_fmri_strcpy(edata, fmri));
2N/A}
2N/A
2N/A/*
2N/A * Prints the additional-information element filled with data from the given
2N/A * topo node property.
2N/A * The name of the property is returned for further processing of the
2N/A * property.
2N/A */
2N/Astatic int
2N/Aadd_topo_ai_prop(
2N/A asr_topo_enum_data_t *edata, nvlist_t *prop, char **name, asr_buf_t *value)
2N/A{
2N/A int err = 0;
2N/A nvpair_t *nvp;
2N/A uint_t nelem;
2N/A int i;
2N/A char *type;
2N/A
2N/A if (prop == NULL || (nvp = nvlist_next_nvpair(prop, NULL)) == NULL)
2N/A return (ASR_FAILURE);
2N/A
2N/A if ((nvp = nvlist_next_nvpair(prop, NULL)) == NULL ||
2N/A nvpair_name(nvp) == NULL ||
2N/A strcmp(TOPO_PROP_VAL_NAME, nvpair_name(nvp)) != 0)
2N/A return (ASR_FAILURE);
2N/A else
2N/A (void) nvpair_value_string(nvp, name);
2N/A
2N/A if ((nvp = nvlist_next_nvpair(prop, nvp)) == NULL ||
2N/A nvpair_name(nvp) == NULL ||
2N/A strcmp(nvpair_name(nvp), TOPO_PROP_VAL_TYPE) != 0 ||
2N/A nvpair_type(nvp) != DATA_TYPE_UINT32)
2N/A return (ASR_FAILURE);
2N/A else
2N/A (void) nvpair_value_uint32(nvp, (uint32_t *)&type);
2N/A
2N/A if (nvpair_name(nvp) == NULL ||
2N/A (nvp = nvlist_next_nvpair(prop, nvp)) == NULL)
2N/A return (ASR_FAILURE);
2N/A
2N/A switch (nvpair_type(nvp)) {
2N/A case DATA_TYPE_INT32:
2N/A {
2N/A int32_t val;
2N/A (void) nvpair_value_int32(nvp, &val);
2N/A (void) asr_buf_append(value, " %d", val);
2N/A break;
2N/A }
2N/A case DATA_TYPE_UINT32:
2N/A {
2N/A uint32_t val;
2N/A (void) nvpair_value_uint32(nvp, &val);
2N/A (void) asr_buf_append(value, " 0x%x", val);
2N/A break;
2N/A }
2N/A case DATA_TYPE_INT64:
2N/A {
2N/A int64_t val;
2N/A (void) nvpair_value_int64(nvp, &val);
2N/A (void) asr_buf_append(value, " %lld", (longlong_t)val);
2N/A break;
2N/A }
2N/A case DATA_TYPE_UINT64:
2N/A {
2N/A uint64_t val;
2N/A (void) nvpair_value_uint64(nvp, &val);
2N/A (void) asr_buf_append(value, " 0x%llx", (u_longlong_t)val);
2N/A break;
2N/A }
2N/A case DATA_TYPE_DOUBLE:
2N/A {
2N/A double val;
2N/A (void) nvpair_value_double(nvp, &val);
2N/A (void) asr_buf_append(value, " %lf", (double)val);
2N/A break;
2N/A }
2N/A case DATA_TYPE_STRING:
2N/A {
2N/A char *val;
2N/A (void) nvpair_value_string(nvp, &val);
2N/A (void) asr_buf_append(value, " %s", val);
2N/A break;
2N/A }
2N/A case DATA_TYPE_NVLIST:
2N/A {
2N/A nvlist_t *val;
2N/A char *fmri;
2N/A (void) nvpair_value_nvlist(nvp, &val);
2N/A if (topo_fmri_nvl2str(
2N/A edata->asr_topoh, val, &fmri, &err) != 0) {
2N/A asr_nvl_tostringi(value, prop, 1, '"', " : ");
2N/A } else {
2N/A (void) asr_buf_append(value, " %s", fmri);
2N/A topo_hdl_strfree(edata->asr_topoh, fmri);
2N/A }
2N/A break;
2N/A }
2N/A case DATA_TYPE_INT32_ARRAY:
2N/A {
2N/A int32_t *val;
2N/A (void) nvpair_value_int32_array(nvp, &val, &nelem);
2N/A (void) asr_buf_append_str(value, " [ ");
2N/A for (i = 0; i < nelem; i++)
2N/A (void) asr_buf_append(value, "%d ", val[i]);
2N/A (void) asr_buf_append_str(value, "]");
2N/A break;
2N/A }
2N/A case DATA_TYPE_UINT32_ARRAY:
2N/A {
2N/A uint32_t *val;
2N/A (void) nvpair_value_uint32_array(nvp, &val, &nelem);
2N/A (void) asr_buf_append_str(value, " [ ");
2N/A for (i = 0; i < nelem; i++)
2N/A (void) asr_buf_append(value, "%u ", val[i]);
2N/A (void) asr_buf_append(value, "]");
2N/A break;
2N/A }
2N/A case DATA_TYPE_INT64_ARRAY:
2N/A {
2N/A int64_t *val;
2N/A (void) nvpair_value_int64_array(nvp, &val, &nelem);
2N/A (void) asr_buf_append_str(value, " [ ");
2N/A for (i = 0; i < nelem; i++)
2N/A (void) asr_buf_append(value, "%"PRId64" ", val[i]);
2N/A (void) asr_buf_append(value, "]");
2N/A break;
2N/A }
2N/A case DATA_TYPE_UINT64_ARRAY:
2N/A {
2N/A uint64_t *val;
2N/A (void) nvpair_value_uint64_array(nvp, &val, &nelem);
2N/A (void) asr_buf_append_str(value, " [ ");
2N/A for (i = 0; i < nelem; i++)
2N/A (void) asr_buf_append(value, "%"PRIu64" ", val[i]);
2N/A (void) asr_buf_append_str(value, "]");
2N/A break;
2N/A }
2N/A case DATA_TYPE_STRING_ARRAY:
2N/A {
2N/A char **val;
2N/A (void) nvpair_value_string_array(nvp, &val, &nelem);
2N/A (void) asr_buf_append_str(value, " [ ");
2N/A for (i = 0; i < nelem; i++)
2N/A (void) asr_buf_append(value, "\"%s\" ", val[i]);
2N/A (void) asr_buf_append_str(value, "]");
2N/A break;
2N/A }
2N/A default:
2N/A (void) asr_buf_append(value, " unknown data type (%d)",
2N/A nvpair_type(nvp));
2N/A break;
2N/A }
2N/A
2N/A asr_buf_trim(value);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Prints additional information for an entire topo node group.
2N/A * Any properties that are part of the standard ASR audit message
2N/A * will be returned in the std name value list.
2N/A */
2N/Astatic int
2N/Aadd_topo_ai_grp(asr_topo_enum_data_t *edata, nvlist_t *grp,
2N/A nvlist_t *std, asr_buf_t *out)
2N/A{
2N/A char *gname, *pname;
2N/A nvpair_t *nvp;
2N/A nvlist_t *prop;
2N/A int err = 0;
2N/A asr_buf_t *val, *buf;
2N/A char *skip = "|protocol|authority|";
2N/A char *stdvals = "|serial|part|state|status|";
2N/A
2N/A nvp = nvlist_next_nvpair(grp, NULL);
2N/A if (nvp == NULL)
2N/A return (ASR_FAILURE);
2N/A pname = nvpair_name(nvp);
2N/A if (pname == NULL)
2N/A return (ASR_FAILURE);
2N/A if (strcmp(TOPO_PROP_GROUP_NAME, pname) != 0)
2N/A return (ASR_FAILURE);
2N/A else
2N/A if (nvpair_value_string(nvp, &gname) != 0)
2N/A return (ASR_FAILURE);
2N/A
2N/A buf = asr_buf_alloc(ASR_AUDIT_LINESIZE);
2N/A if (buf == NULL)
2N/A return (ASR_FAILURE);
2N/A
2N/A err = asr_buf_append(buf, "|%s|", gname);
2N/A if (err != 0) {
2N/A asr_buf_free(buf);
2N/A return (ASR_FAILURE);
2N/A }
2N/A
2N/A /*
2N/A * If this is a value we should skip then stop now.
2N/A */
2N/A if (strstr(skip, buf->asrb_data) != NULL) {
2N/A asr_buf_free(buf);
2N/A return (ASR_OK);
2N/A }
2N/A
2N/A val = asr_buf_alloc(ASR_AUDIT_LINESIZE);
2N/A if (val == NULL) {
2N/A asr_buf_free(buf);
2N/A return (ASR_FAILURE);
2N/A }
2N/A
2N/A for (nvp = nvlist_next_nvpair(grp, NULL); nvp != NULL && err == 0;
2N/A nvp = nvlist_next_nvpair(grp, nvp)) {
2N/A if ((strcmp(TOPO_PROP_VAL, nvpair_name(nvp)) == 0) &&
2N/A nvpair_type(nvp) == DATA_TYPE_NVLIST) {
2N/A if ((err = nvpair_value_nvlist(nvp, &prop)) != 0)
2N/A break;
2N/A asr_buf_reset(val);
2N/A if ((err = add_topo_ai_prop(
2N/A edata, prop, &pname, val)) != 0)
2N/A break;
2N/A if ((err = asr_buf_append(buf, "|%s|", pname)) != 0)
2N/A break;
2N/A if (strstr(stdvals, buf->asrb_data))
2N/A err = nvlist_add_string(std, pname,
2N/A asr_buf_data(val));
2N/A if (err == 0)
2N/A err = asr_buf_append_xml_ai(
2N/A out, 3, pname, asr_buf_data(val));
2N/A }
2N/A }
2N/A
2N/A asr_buf_free(buf);
2N/A asr_buf_free(val);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Prints out additional information for a topology node.
2N/A */
2N/Astatic int
2N/Aadd_topo_ai(asr_topo_enum_data_t *edata, tnode_t *node,
2N/A nvlist_t *std, asr_buf_t *out)
2N/A{
2N/A int err = 0;
2N/A nvpair_t *nvp;
2N/A nvlist_t *grps = topo_prop_getprops(node, &err);
2N/A nvlist_t *grp;
2N/A
2N/A for (nvp = nvlist_next_nvpair(grps, NULL); nvp != NULL;
2N/A nvp = nvlist_next_nvpair(grps, nvp)) {
2N/A if (strcmp(TOPO_PROP_GROUP, nvpair_name(nvp)) != 0 ||
2N/A nvpair_type(nvp) != DATA_TYPE_NVLIST)
2N/A continue;
2N/A
2N/A (void) nvpair_value_nvlist(nvp, &grp);
2N/A err |= add_topo_ai_grp(edata, grp, std, out);
2N/A }
2N/A asr_nvl_free(grps);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Converts an FMRI string to an ASR name.
2N/A * The string will contain the FMRI data after the <authority>/
2N/A */
2N/Achar *
2N/Aasr_fmri_str_to_name(char *fmri)
2N/A{
2N/A char *id;
2N/A
2N/A for (id = fmri; *id != '\0'; id++)
2N/A if (*id == '/' && id != fmri &&
2N/A *(id + 1) != ':' && *(id + 1) != '/')
2N/A break;
2N/A if (*id == '/')
2N/A id++;
2N/A return (id);
2N/A}
2N/A
2N/A/*
2N/A * Contains the definition of a hardware component, inclusive of a path to this
2N/A * hardware component
2N/A * Adds name, id, serial, part, revision, path, state, status &
2N/A * additional-information
2N/A */
2N/Astatic int
2N/Aadd_hardware_component(asr_topo_enum_data_t *edata, tnode_t *node)
2N/A{
2N/A asr_buf_t *out = edata->asr_data;
2N/A int err = 0;
2N/A int rollback_index = out->asrb_length;
2N/A char *serial = NULL, *part = NULL, *revision = NULL;
2N/A char *state = NULL, *status = NULL;
2N/A
2N/A char *fru = asr_get_fru(edata, node);
2N/A char *resource = asr_get_resource(edata, node);
2N/A char *asru = asr_get_asru(edata, node);
2N/A char *name;
2N/A
2N/A nvlist_t *std = asr_nvl_alloc();
2N/A asr_buf_t *ai = asr_buf_alloc(64);
2N/A
2N/A CHECK_NOT_NULL(std);
2N/A CHECK_NOT_NULL(ai);
2N/A
2N/A if (fru != NULL)
2N/A err |= asr_buf_append_xml_ai(ai, 3, "fru", fru);
2N/A if (resource != NULL)
2N/A err |= asr_buf_append_xml_ai(ai, 3, "resource", resource);
2N/A if (asru != NULL)
2N/A err |= asr_buf_append_xml_ai(ai, 3, "asru", asru);
2N/A
2N/A err |= add_topo_ai(edata, node, std, ai);
2N/A err |= asr_buf_append_pad(out, PAD_COMPONENT);
2N/A err |= asr_buf_append_str(out, "<component><hardware-component>\n");
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A if (resource != NULL)
2N/A name = asr_fmri_str_to_name(resource);
2N/A else if (fru != NULL)
2N/A name = asr_fmri_str_to_name(fru);
2N/A else
2N/A name = topo_node_name(node);
2N/A
2N/A err |= asr_buf_append_xml_nvtoken(out, PAD_ITEM, "name", name);
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A (void) nvlist_lookup_string(std, "serial", &serial);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "serial", serial);
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A (void) nvlist_lookup_string(std, "part", &part);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "part", part);
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A (void) nvlist_lookup_string(std, "revision", &revision);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "revision", revision);
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A (void) nvlist_lookup_string(std, "state", &state);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "state", state);
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A (void) nvlist_lookup_string(std, "status", &status);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "status", status);
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A err |= asr_buf_append_buf(out, ai);
2N/A err |= asr_buf_append_pad(out, PAD_COMPONENT);
2N/A err |= asr_buf_append_str(out, "</hardware-component></component>\n");
2N/A
2N/Afinally:
2N/A if (fru != NULL)
2N/A free(fru);
2N/A if (resource != NULL)
2N/A free(resource);
2N/A if (asru != NULL)
2N/A free(asru);
2N/A if (err && rollback_index) {
2N/A out->asrb_length = rollback_index;
2N/A }
2N/A if (std != NULL)
2N/A asr_nvl_free(std);
2N/A if (ai != NULL)
2N/A asr_buf_free(ai);
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Walks the topology. Used as a callback function to the topology walker.
2N/A */
2N/A/* ARGSUSED */
2N/Astatic int
2N/Aasr_audit_topo_enum(topo_hdl_t *thp, tnode_t *node, void *arg)
2N/A{
2N/A asr_topo_enum_data_t *edata = arg;
2N/A
2N/A (void) add_hardware_component(edata, node);
2N/A
2N/A return (TOPO_WALK_NEXT);
2N/A}
2N/A
2N/A/*
2N/A * Prints all the hardware-component ASR elements.
2N/A * Searches the FMA topology and creates a hardware-component for each
2N/A * topology node found.
2N/A */
2N/Astatic int
2N/Aadd_hardware_components(asr_handle_t *ah, asr_buf_t *out)
2N/A{
2N/A return (asr_topo_walk(ah, asr_audit_topo_enum, out));
2N/A}
2N/A
2N/Astatic char *
2N/Aadd_pkg_info(nvlist_t *pkg, char *name1, char *name2)
2N/A{
2N/A char *value = asr_nvl_str(pkg, name1);
2N/A if (value == NULL)
2N/A value = asr_nvl_str(pkg, name2);
2N/A return (value);
2N/A}
2N/A
2N/A/*
2N/A * A description of a software package reminiscent of pkginfo
2N/A * Adds all values in an uncategorized element so all info can be sent.
2N/A * Newer verisons of message.xsd should include these new values.
2N/A */
2N/Astatic int
2N/Aadd_software_package(asr_buf_t *out, nvlist_t *pkg)
2N/A{
2N/A int err = 0;
2N/A int rollback_index = out->asrb_length;
2N/A
2N/A char *name = add_pkg_info(pkg, "Name", "PKGINST");
2N/A char *summary = add_pkg_info(pkg, "Summary", "NAME");
2N/A char *category = add_pkg_info(pkg, "Category", "CATEGORY");
2N/A char *state = add_pkg_info(pkg, "State", "STATUS");
2N/A char *arch = asr_nvl_str(pkg, "ARCH");
2N/A char *publisher = asr_nvl_str(pkg, "Publisher");
2N/A char *version = add_pkg_info(pkg, "Version", "VERSION");
2N/A char *release = asr_nvl_str(pkg, "Build Release");
2N/A char *branch = asr_nvl_str(pkg, "Branch");
2N/A char *basedir = asr_nvl_str(pkg, "BASEDIR");
2N/A char *vendor = asr_nvl_str(pkg, "VENDOR");
2N/A char *desc = add_pkg_info(pkg, "Description", "DESC");
2N/A char *instdate = add_pkg_info(pkg, "Packaging Date", "INSTDATE");
2N/A char *size = asr_nvl_str(pkg, "Size");
2N/A char *fmri = asr_nvl_str(pkg, "FMRI");
2N/A
2N/A if (name == NULL || version == NULL)
2N/A return (0);
2N/A
2N/A err |= asr_buf_append_pad(out, PAD_COMPONENT);
2N/A err |= asr_buf_append_str(out,
2N/A "<component>"
2N/A "<uncategorized name='software-package'>"
2N/A "<software-package>\n");
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "name", name);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "summary", summary);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "description", desc);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "category", category);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "state", state);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "publisher", publisher);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "arch", arch);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "version", version);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "release", release);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "branch", branch);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "basedir", basedir);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "vendor", vendor);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "instdate", instdate);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "size", size);
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "fmri", fmri);
2N/A
2N/A err |= asr_buf_append_pad(out, PAD_COMPONENT);
2N/A err |= asr_buf_append_str(out,
2N/A "</software-package>"
2N/A "</uncategorized>"
2N/A "</component>\n");
2N/A
2N/A if (err && rollback_index) {
2N/A out->asrb_length = rollback_index;
2N/A }
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Reads a file containing pkginfo output and prints the results to the out
2N/A * buffer as ASR audit software-package elements.
2N/A */
2N/Astatic int
2N/Aadd_pkginfo_data(asr_handle_t *ah, asr_buf_t *out, FILE *in)
2N/A{
2N/A int err = 0;
2N/A char *buf, *name, *value, *sep;
2N/A nvlist_t *pkg = NULL;
2N/A asr_buf_t *line = NULL;
2N/A
2N/A if (in == NULL)
2N/A return (ASR_FAILURE);
2N/A
2N/A if ((line = asr_buf_alloc(ASR_AUDIT_LINESIZE)) == NULL)
2N/A return (ASR_FAILURE);
2N/A
2N/A do {
2N/A asr_buf_reset(line);
2N/A if (asr_buf_readln(line, in) == 0)
2N/A break;
2N/A buf = asr_buf_data(line);
2N/A if ((sep = strstr(buf, ":")) == NULL) {
2N/A if ((buf == NULL || buf[0] == '\n' || buf[0] == '\0') &&
2N/A pkg != NULL) {
2N/A if (add_software_package(out, pkg) != 0)
2N/A asr_log_warn(ah, "failed to add pkg "
2N/A "info to audit event");
2N/A asr_nvl_free(pkg);
2N/A pkg = NULL;
2N/A }
2N/A continue;
2N/A }
2N/A if (pkg == NULL) {
2N/A pkg = asr_nvl_alloc();
2N/A if (pkg == NULL) {
2N/A err = 1;
2N/A break;
2N/A }
2N/A }
2N/A
2N/A for (name = buf; *name == ' ' && *name != '\0'; name++)
2N/A ;
2N/A
2N/A *sep = '\0';
2N/A value = sep + 1;
2N/A
2N/A for (value = sep + 1; *value == ' ' && *value != '\0'; value++)
2N/A ;
2N/A
2N/A sep = strstr(value, "\n");
2N/A if (sep != NULL)
2N/A *sep = '\0';
2N/A (void) asr_nvl_add_str(pkg, name, value);
2N/A } while (err == 0);
2N/A
2N/A if (pkg != NULL)
2N/A asr_nvl_free(pkg);
2N/A asr_buf_free(line);
2N/A return (err);
2N/A}
2N/A
2N/Astatic char *
2N/Aasr_tmpfile(asr_handle_t *ah)
2N/A{
2N/A asr_buf_t *file;
2N/A char *rootdir = asr_getprop_strd(ah, ASR_PROP_ROOTDIR, "/");
2N/A char *datadir = asr_get_datadir(ah);
2N/A uuid_t uuid;
2N/A char uuidbuf[UUID_PRINTABLE_STRING_LENGTH];
2N/A
2N/A if (rootdir == NULL || datadir == NULL)
2N/A return (NULL);
2N/A
2N/A uuid_generate(uuid);
2N/A uuid_unparse(uuid, uuidbuf);
2N/A
2N/A file = asr_buf_alloc(PATH_MAX);
2N/A if (asr_buf_append(file, "%s%s/%s", rootdir, datadir, uuidbuf) != 0) {
2N/A asr_buf_free(file);
2N/A return (NULL);
2N/A }
2N/A return (asr_buf_free_struct(file));
2N/A}
2N/A
2N/A/*
2N/A * Collects software package information and print it out as ASR
2N/A * software-package elements.
2N/A */
2N/Astatic int
2N/Aadd_software_packages(asr_handle_t *ah, asr_buf_t *out)
2N/A{
2N/A int err = 0;
2N/A FILE *outfile;
2N/A
2N/A if ((outfile = popen(PKG_INFO_CMD, "r")) == NULL) {
2N/A (void) asr_error(EASR_SYSTEM,
2N/A "Error calling %s (%s) ", PKG_INFO_CMD, strerror(errno));
2N/A return (ASR_FAILURE);
2N/A }
2N/A
2N/A err = add_pkginfo_data(ah, out, outfile);
2N/A (void) pclose(outfile);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Prints out a SCF service as an ASR software-module element containing
2N/A * name & description
2N/A * name=FMRI
2N/A * description = STATE STIME
2N/A */
2N/Astatic int
2N/Aadd_software_module(asr_buf_t *out, char *fmri, scf_service_t *svc)
2N/A{
2N/A int err = 0;
2N/A char *state = NULL;
2N/A char *desc = "";
2N/A int rollback_index = 0;
2N/A
2N/A CHECK_NOT_NULL(out);
2N/A CHECK_NOT_NULL(fmri);
2N/A CHECK_NOT_NULL(svc);
2N/A
2N/A state = smf_get_state(fmri);
2N/A if (state != NULL) {
2N/A desc = state;
2N/A }
2N/A
2N/A rollback_index = out->asrb_length;
2N/A err |= asr_buf_append_pad(out, PAD_COMPONENT);
2N/A err |= asr_buf_append_str(out, "<component><software-module>\n");
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "name", fmri);
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A err |= asr_buf_append_xml_nv(out, PAD_ITEM, "description", desc);
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A err |= asr_buf_append_pad(out, PAD_COMPONENT);
2N/A err |= asr_buf_append_str(out, "</software-module></component>\n");
2N/A
2N/Afinally:
2N/A if (state != NULL) {
2N/A free(state);
2N/A }
2N/A if (err && rollback_index) {
2N/A out->asrb_length = rollback_index;
2N/A }
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Collects all SCF services and prints them out as ASR software-module
2N/A * elements
2N/A */
2N/Astatic int
2N/Aadd_software_modules(asr_buf_t *out)
2N/A{
2N/A int r;
2N/A int err = 1;
2N/A char *fmri;
2N/A scf_handle_t *handle = NULL;
2N/A scf_scope_t *scope = NULL;
2N/A scf_service_t *svc = NULL;
2N/A scf_instance_t *inst = NULL;
2N/A scf_iter_t *svc_iter = NULL;
2N/A scf_iter_t *inst_iter = NULL;
2N/A size_t sz = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH) + 1;
2N/A
2N/A fmri = malloc(sz + 1);
2N/A CHECK_NOT_NULL(fmri);
2N/A
2N/A handle = scf_handle_create(SCF_VERSION);
2N/A CHECK_NOT_NULL(handle);
2N/A
2N/A scope = scf_scope_create(handle);
2N/A CHECK_NOT_NULL(scope);
2N/A
2N/A svc = scf_service_create(handle);
2N/A CHECK_NOT_NULL(svc);
2N/A
2N/A inst = scf_instance_create(handle);
2N/A CHECK_NOT_NULL(inst);
2N/A
2N/A svc_iter = scf_iter_create(handle);
2N/A CHECK_NOT_NULL(svc_iter);
2N/A
2N/A inst_iter = scf_iter_create(handle);
2N/A CHECK_NOT_NULL(inst_iter);
2N/A
2N/A err = scf_handle_bind(handle);
2N/A CHECK_FOR_ERR(err == -1);
2N/A
2N/A err = scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope);
2N/A CHECK_FOR_ERR(err == -1);
2N/A
2N/A err = scf_iter_scope_services(svc_iter, scope);
2N/A CHECK_FOR_ERR(err == -1);
2N/A
2N/A while ((r = scf_iter_next_service(svc_iter, svc)) > 0) {
2N/A err = scf_iter_service_instances(inst_iter, svc);
2N/A CHECK_FOR_ERR(err == -1);
2N/A
2N/A while ((r = scf_iter_next_instance(inst_iter, inst)) > 0) {
2N/A int frmi_len = scf_instance_to_fmri(inst, fmri, sz);
2N/A if (frmi_len < 0) {
2N/A err++;
2N/A goto finally;
2N/A }
2N/A (void) add_software_module(out, fmri, svc);
2N/A }
2N/A if (r < 0)
2N/A break;
2N/A }
2N/A if (r < 0) {
2N/A err++;
2N/A }
2N/A
2N/Afinally:
2N/A if (inst_iter != NULL)
2N/A scf_iter_destroy(inst_iter);
2N/A if (svc_iter != NULL)
2N/A scf_iter_destroy(svc_iter);
2N/A if (inst != NULL)
2N/A scf_instance_destroy(inst);
2N/A if (svc != NULL)
2N/A scf_service_destroy(svc);
2N/A if (scope != NULL)
2N/A scf_scope_destroy(scope);
2N/A if (handle != NULL)
2N/A scf_handle_destroy(handle);
2N/A if (fmri != NULL)
2N/A free(fmri);
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Aadd_payload_data(asr_buf_t *out, char *fname, char *name)
2N/A{
2N/A int err = 0;
2N/A int line;
2N/A FILE *in = fopen(fname, "r");
2N/A
2N/A if (in == NULL)
2N/A return (1);
2N/A if (name == NULL)
2N/A name = ASR_AUDIT_PAYLOAD_GENERIC;
2N/A
2N/A if (asr_buf_append_pad(out, PAD_COMPONENT) != 0 ||
2N/A asr_buf_append(out, "<payload name='%s'><![CDATA[\n", name) != 0) {
2N/A (void) fclose(in);
2N/A return (ASR_FAILURE);
2N/A }
2N/A
2N/A do {
2N/A err = asr_buf_append_pad(out, PAD_COMPONENT);
2N/A line = asr_buf_readln(out, in);
2N/A } while (line != 0 && err == 0);
2N/A
2N/A err |= asr_buf_append_str(out, "]]>\n");
2N/A err |= asr_buf_append_pad(out, PAD_COMPONENT);
2N/A err |= asr_buf_append_str(out, "</payload>\n");
2N/A err |= fclose(in);
2N/A return (err);
2N/A}
2N/A
2N/Astatic int
2N/Aadd_payload_cmd(asr_handle_t *ah, asr_buf_t *out, char *name, char *payload)
2N/A{
2N/A int err;
2N/A asr_buf_t *cmd;
2N/A char *outfile = asr_tmpfile(ah);
2N/A
2N/A if (outfile == NULL)
2N/A return (ASR_FAILURE);
2N/A
2N/A if ((cmd = asr_buf_alloc(ASR_AUDIT_LINESIZE)) == NULL) {
2N/A free(outfile);
2N/A return (ASR_FAILURE);
2N/A }
2N/A
2N/A if (asr_buf_append(cmd, "%s > %s", payload, outfile) != 0) {
2N/A asr_buf_free(cmd);
2N/A free(outfile);
2N/A return (ASR_FAILURE);
2N/A }
2N/A
2N/A if ((err = system(asr_buf_data(cmd))) != 0) {
2N/A (void) asr_error(EASR_SYSTEM,
2N/A "Error (%d) calling audit payload command (%s)",
2N/A err, asr_buf_data(cmd));
2N/A asr_buf_free(cmd);
2N/A (void) unlink(outfile);
2N/A free(outfile);
2N/A return (ASR_FAILURE);
2N/A }
2N/A asr_buf_free(cmd);
2N/A
2N/A err = add_payload_data(out, outfile, name);
2N/A (void) unlink(outfile);
2N/A free(outfile);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A/*
2N/A * Collects software package information and print it out as ASR
2N/A * software-package elements.
2N/A */
2N/Astatic int
2N/Aadd_payload(asr_handle_t *ah, asr_buf_t *out)
2N/A{
2N/A int result = 0;
2N/A int rollback_index = out->asrb_length;
2N/A char *name = asr_getprop_str(ah, ASR_PROP_AUDIT_PAYLOAD_NAME);
2N/A char *cmd = asr_getprop_str(ah, ASR_PROP_AUDIT_PAYLOAD_CMD);
2N/A
2N/A if (cmd == NULL || cmd[0] == '\0')
2N/A return (result);
2N/A
2N/A result = add_payload_cmd(ah, out, name, cmd);
2N/A
2N/A if (result != ASR_OK && rollback_index > 0) {
2N/A out->asrb_length = rollback_index;
2N/A }
2N/A return (result);
2N/A}
2N/A
2N/A/*
2N/A * Creates an ASR audit message and places it in out_msg. The message must
2N/A * be released when finished using it.
2N/A * Returns non-zero, sets out_msg to NULL and sets asr_errno
2N/A * if there is an error.
2N/A */
2N/Aint
2N/Aasr_audit(asr_handle_t *ah, asr_message_t **out_msg)
2N/A{
2N/A int err;
2N/A asr_message_t *msg = NULL;
2N/A asr_buf_t *buf = asr_buf_alloc(ASR_AUDIT_BUFSIZE);
2N/A
2N/A if (buf == NULL)
2N/A return (asr_set_errno(EASR_NOMEM));
2N/A
2N/A err = asr_msg_start(ah, buf);
2N/A err |= asr_buf_append_xml_elem(buf, 1, "component-list");
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A if (asr_getprop_bool(ah, ASR_PROP_AUDIT_SEND_FRU, B_TRUE)) {
2N/A err = add_hardware_components(ah, buf);
2N/A CHECK_FOR_ERR(err);
2N/A }
2N/A
2N/A if (asr_getprop_bool(ah, ASR_PROP_AUDIT_SEND_PKG, B_TRUE)) {
2N/A err = add_software_packages(ah, buf);
2N/A CHECK_FOR_ERR(err);
2N/A }
2N/A
2N/A if (asr_getprop_bool(ah, ASR_PROP_AUDIT_SEND_SVC, B_TRUE)) {
2N/A err = add_software_modules(buf);
2N/A CHECK_FOR_ERR(err);
2N/A }
2N/A
2N/A err = asr_buf_append_xml_end(buf, 1, "component-list");
2N/A CHECK_FOR_ERR(err);
2N/A
2N/A if (asr_getprop_bool(ah, ASR_PROP_AUDIT_SEND_PAYLOAD, B_TRUE)) {
2N/A if (add_payload(ah, buf) != 0)
2N/A asr_log_warn(ah, "Unable to add audit payload.");
2N/A }
2N/A
2N/A err = asr_msg_end(buf);
2N/A
2N/Afinally:
2N/A if (err == 0) {
2N/A if ((msg = asr_message_alloc(buf, ASR_MSG_AUDIT)) == NULL)
2N/A err = EASR_NOMEM;
2N/A } else {
2N/A asr_buf_free(buf);
2N/A }
2N/A
2N/A *out_msg = msg;
2N/A return (err);
2N/A}