/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
*/
/* auditd smf(5)/libscf(3LIB) interface - set and display audit parameters */
#include <audit_scf.h>
#include <audit_policy.h>
/* propvec array must be NULL terminated */
scf_propvec_t prop_vect[MAX_PROPVECS + 1];
/*
* prt_error() - prt_error_va() wrapper; see prt_error_va() for more contextual
* information. Note, that the function disregards errno; if you need to print
* out strerror()/errno use directly prt_error_va().
* Inputs - program error format and message.
*/
/*PRINTFLIKE1*/
static void
prt_error(char *fmt, ...)
{
va_list args;
errno = 0;
va_start(args, fmt);
prt_error_va(fmt, args);
va_end(args);
}
/*
* prt_error_va() - prints an error message along with corresponding system
* error number. Inputs - program error format and the va_list already prepared
* by the preceding functions.
*
*/
/*PRINTFLIKE1*/
void
prt_error_va(char *fmt, va_list args)
{
(void) vfprintf(stderr, fmt, args);
(void) fputc('\n', stderr);
if (errno)
(void) fprintf(stderr, "error: %s(%d)\n",
strerror(errno), errno);
(void) fflush(stderr);
}
/*
* prt_scf_err() - scf_error()/scf_strerror() wrapper.
*/
static void
prt_scf_err(void)
{
(void) fprintf(stderr, "error: %s\n", scf_strerror(scf_error()));
}
/*
* buf_concat() - concatenate two buffers.
*/
static boolean_t
buf_concat(char **dst, size_t *dst_sz, char *src, int src_len)
{
size_t buf_limit = PGRP_MAXATT * PGRP_MAXATT; /* sane buffer limit */
size_t dst_sz_new = *dst_sz;
char *dst_new;
if (src_len > buf_limit) {
prt_error(gettext("Source string length over limit."));
return (B_FALSE);
}
src_len -= (*dst_sz - strlen(*dst) - 1);
if (src_len > 0) {
dst_sz_new += (src_len / PGRP_MAXATT) * PGRP_MAXATT;
dst_sz_new += (src_len % PGRP_MAXATT) != 0 ? PGRP_MAXATT : 0;
if (dst_sz_new > buf_limit) {
prt_error(gettext("Outside of the supported buffer "
"size."));
return (B_FALSE);
}
if ((dst_new = realloc(*dst, dst_sz_new)) == NULL) {
prt_error(gettext("No available memory."));
return (B_FALSE);
}
*dst = dst_new;
*dst_sz = dst_sz_new;
}
if (strlcat(*dst, src, *dst_sz) >= *dst_sz) {
prt_error(gettext("Internal error, source string too long."));
return (B_FALSE);
}
return (B_TRUE);
}
/*
* remove_space() - removes a white space characters from the provided NUL
* terminated (or up to len characters) string. len = 0 - no len limit, wait for
* NUL character.
*/
static void
remove_space(char *str, int len)
{
boolean_t chklen = B_TRUE;
char *str_ptr = str;
if (len >= 0 && str != NULL && *str != '\0') {
if (len == 0) {
chklen = B_FALSE;
} else {
len--;
}
while (*str != '\0' && len-- >= 0) {
if (isspace(*str) == 0) {
*str_ptr++ = *str;
}
if (!chklen) {
len++;
}
str++;
}
*str_ptr = '\0';
}
}
/*
* add_prop_vect_scf() - adds vector to the array of vectors later passed to
* get_/set_val_scf(). The first argument (vector) points to particular position
* in the vector of properties.
*/
static void
add_prop_vect_scf(scf_propvec_t *vector, const char *prop_str,
scf_type_t prop_type, void *prop_val_ptr)
{
vector->pv_prop = prop_str;
vector->pv_type = prop_type;
vector->pv_ptr = prop_val_ptr;
}
/*
* add_prop_vect_mval_scf() - updates vector in the array of vectors later
* passed to get_/set_val_scf() with a pointer to value of multivalued property.
* The first argument (vector) points to particular position in the vector of
* properties. The function is typically called several times based on amount of
* properties the multi-valued property should address; each of such calls
* preserves the vector (argument) pointing to the same position in the vector
* of properties, while it is expected that the prop_val_ptr changes.
* Use free_prop_vect_mval() for easy cleanup of the allocated resources.
*/
static boolean_t
add_prop_vect_mval_scf(scf_propvec_t *vector, const char *prop_str,
scf_type_t prop_type, void *prop_val_ptr)
{
scf_propvec_mval_t *pv_ptr_node_last;
scf_propvec_mval_t *pv_ptr_node_new;
if (vector->pv_prop == NULL) {
vector->pv_prop = prop_str;
vector->pv_mval = B_TRUE;
vector->pv_type = prop_type;
}
if ((pv_ptr_node_new = calloc(1, sizeof (*pv_ptr_node_new))) == NULL) {
prt_error(gettext("No free memory available."));
return (B_FALSE);
}
if (vector->pv_ptr == NULL) {
vector->pv_ptr = pv_ptr_node_new;
} else {
pv_ptr_node_last = vector->pv_ptr;
while (pv_ptr_node_last->next != NULL) {
pv_ptr_node_last = pv_ptr_node_last->next;
}
pv_ptr_node_last->next = pv_ptr_node_new;
}
pv_ptr_node_new->pv_ptr = prop_val_ptr;
return (B_TRUE);
}
/*
* get_val_scf() - get a property values from the audit service
*
* Arguments: vector = pointers to the head end of array of property vectors
* pgrp_name = property group of property in AUDITD_FMRI
*
*/
static boolean_t
get_val_scf(scf_propvec_t *vector, char *pgrp_name)
{
scf_propvec_t *bad_prop_vec = NULL;
/*
* Get the property vector from the editing snapshot (B_FALSE).
* For documentation on property vectors see <libscf_priv.h>.
*/
if (scf_read_propvec(AUDITD_FMRI, pgrp_name, B_FALSE, vector,
&bad_prop_vec) != SCF_SUCCESS) {
prt_scf_err();
if (bad_prop_vec != NULL) {
prt_error(gettext("Reading the %s property in the %s "
"property group failed."), bad_prop_vec->pv_prop,
pgrp_name);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* set_val_scf() - set property values of the audit service.
*
* arguments: vector = pointers to the head end of array of property vectors
* pgrp_name = property group of property in AUDITD_FMRI
*
*/
static boolean_t
set_val_scf(scf_propvec_t *vector, char *pgrp_name)
{
scf_propvec_t *bad_prop_vec = NULL;
/* for documentation on property vectors see <libscf_priv.h> */
if (scf_write_propvec(AUDITD_FMRI, pgrp_name, vector,
&bad_prop_vec) != SCF_SUCCESS) {
prt_scf_err();
if (bad_prop_vec != NULL) {
prt_error(gettext("Setting the %s property in the %s "
"property group failed."), bad_prop_vec->pv_prop,
pgrp_name);
}
return (B_FALSE);
}
return (B_TRUE);
}
/*
* free_prop_vect_mval() - deallocate heap memory used for multi-valued
* properties; see add_prop_vect_mval_scf().
*/
static void
free_prop_vect_mval(void)
{
scf_propvec_t *prop_vect_ptr = prop_vect;
scf_propvec_mval_t *pv_ptr_node_last;
scf_propvec_mval_t *pv_ptr_node;
while (prop_vect_ptr->pv_prop != NULL) {
if (prop_vect_ptr->pv_mval) {
pv_ptr_node = prop_vect_ptr->pv_ptr;
while (pv_ptr_node != NULL) {
pv_ptr_node_last = pv_ptr_node;
pv_ptr_node = pv_ptr_node->next;
free(pv_ptr_node_last);
}
}
prop_vect_ptr++;
}
}
/*
* free_prop_vect() - deallocate heap memory used for propvect values.
*/
static void
free_prop_vect(void)
{
scf_propvec_t *prop_vect_ptr;
prop_vect_ptr = prop_vect;
while (prop_vect_ptr->pv_prop != NULL && !prop_vect_ptr->pv_mval) {
if (stack_inbounds(prop_vect_ptr->pv_ptr) == 0) {
free(prop_vect_ptr->pv_ptr);
}
prop_vect_ptr++;
}
}
/*
* chk_prop_vect() - check for prop_vect boundaries and possibly process
* (typically) full prop_vect.
*/
static boolean_t
chk_prop_vect(scf_propvec_t **prop_vect_ptr, char *pgrp_name)
{
if (*prop_vect_ptr < prop_vect ||
*prop_vect_ptr >= (prop_vect + MAX_PROPVECS)) {
DPRINT((dbfp, "prop_vect is full; flushing\n"));
if (!set_val_scf(prop_vect, pgrp_name)) {
return (B_FALSE);
}
free_prop_vect();
bzero(prop_vect, sizeof (prop_vect));
*prop_vect_ptr = prop_vect;
}
return (B_TRUE);
}
/*
* scf_free() - free scf handles
*/
static void
scf_free(asi_scfhandle_t *handle)
{
if (handle == NULL) {
return;
}
scf_property_destroy(handle->prop);
scf_pg_destroy(handle->pgrp);
scf_instance_destroy(handle->inst);
if (handle->hndl != NULL) {
if (scf_handle_unbind(handle->hndl) == -1) {
prt_error(gettext("Internal error."));
prt_scf_err();
}
scf_handle_destroy(handle->hndl);
}
}
/*
* scf_init() - initiate scf handles
*/
static boolean_t
scf_init(asi_scfhandle_t *handle)
{
bzero(handle, sizeof (asi_scfhandle_t));
if ((handle->hndl = scf_handle_create(SCF_VERSION)) == NULL ||
scf_handle_bind(handle->hndl) != 0 ||
(handle->inst = scf_instance_create(handle->hndl)) == NULL ||
(handle->pgrp = scf_pg_create(handle->hndl)) == NULL ||
(handle->prop = scf_property_create(handle->hndl)) == NULL) {
prt_scf_err();
scf_free(handle);
return (B_FALSE);
}
return (B_TRUE);
}
/*
* scf_free_iter() - free scf iter handles
*/
static void
scf_free_iter(asi_scfhandle_iter_t *handle_iter)
{
if (handle_iter == NULL) {
return;
}
scf_iter_destroy(handle_iter->pgrp);
scf_iter_destroy(handle_iter->prop);
scf_value_destroy(handle_iter->prop_val);
}
/*
* scf_init_iter() - initiate scf iter handles
*/
static boolean_t
scf_init_iter(asi_scfhandle_iter_t *handle_iter,
asi_scfhandle_t *handle)
{
bzero(handle_iter, sizeof (asi_scfhandle_iter_t));
if ((handle_iter->pgrp = scf_iter_create(handle->hndl)) == NULL ||
(handle_iter->prop = scf_iter_create(handle->hndl)) == NULL ||
(handle_iter->prop_val = scf_value_create(handle->hndl)) == NULL) {
prt_scf_err();
scf_free_iter(handle_iter);
return (B_FALSE);
}
return (B_TRUE);
}
/*
* scf_free_iter_prop() - free scf iter handles (multi-valued property)
*/
static void
scf_free_iter_prop(asi_scfhandle_iter_prop_t *handle_iter_prop)
{
if (handle_iter_prop == NULL) {
return;
}
scf_iter_destroy(handle_iter_prop->prop);
scf_value_destroy(handle_iter_prop->prop_val);
}
/*
* scf_init_iter_prop() - initiate scf iter handles (multi-valued property)
*/
static boolean_t
scf_init_iter_prop(asi_scfhandle_iter_prop_t *handle_iter_prop,
asi_scfhandle_t *handle)
{
bzero(handle_iter_prop, sizeof (asi_scfhandle_iter_prop_t));
if ((handle_iter_prop->prop = scf_iter_create(handle->hndl)) == NULL ||
(handle_iter_prop->prop_val = scf_value_create(handle->hndl))
== NULL) {
prt_scf_err();
scf_free_iter_prop(handle_iter_prop);
return (B_FALSE);
}
return (B_TRUE);
}
/*
* get_prop_str_singleval() - get the single-valued property key-val pair
*/
static boolean_t
get_prop_str_singleval(char **attstr_buf, size_t *attstr_buf_sz, char *key_buf,
scf_property_t *prop, scf_value_t *prop_val)
{
char *val_buf;
ssize_t val_buf_sz;
char *att_buf;
int att_len;
scf_type_t prop_type;
if (scf_property_type(prop, &prop_type) == -1) {
prt_scf_err();
return (B_FALSE);
}
switch (prop_type) {
case SCF_TYPE_BOOLEAN: {
uint8_t pval_bool;
if (scf_value_get_boolean(prop_val, &pval_bool) == -1) {
prt_scf_err();
return (B_FALSE);
}
att_len = asprintf(&att_buf, "%s=%d;", key_buf, pval_bool);
if (att_len == -1) {
prt_error(gettext("No available memory."));
return (B_FALSE);
}
break;
}
case SCF_TYPE_ASTRING: {
val_buf_sz = scf_limit(SCF_LIMIT_MAX_VALUE_LENGTH);
if (val_buf_sz == -1) {
prt_scf_err();
return (B_FALSE);
}
if ((val_buf = malloc(++val_buf_sz)) == NULL) {
prt_error(gettext("No available memory."));
return (B_FALSE);
}
if (scf_value_get_as_string(prop_val, val_buf,
val_buf_sz) == -1) {
prt_scf_err();
free(val_buf);
return (B_FALSE);
}
att_len = asprintf(&att_buf, "%s=%s;", key_buf, val_buf);
if (att_len == -1) {
prt_error(gettext("No available memory."));
free(val_buf);
return (B_FALSE);
}
free(val_buf);
break;
}
case SCF_TYPE_COUNT: {
uint64_t pval_count;
if (scf_value_get_count(prop_val, &pval_count) == -1) {
prt_scf_err();
return (B_FALSE);
}
att_len = asprintf(&att_buf, "%s=%llu;", key_buf,
(unsigned long long) pval_count);
if (att_len == -1) {
prt_error(gettext("No available memory."));
return (B_FALSE);
}
break;
}
default:
(void) printf(gettext("Unsupported value type: %s [%d]\n"),
key_buf, prop_type);
return (B_FALSE);
}
if (!buf_concat(attstr_buf, attstr_buf_sz, att_buf, att_len)) {
free(att_buf);
return (B_FALSE);
}
free(att_buf);
return (B_TRUE);
}
/*
* get_prop_str_multival() - get the multi-valued property key-val pairs.
* Each of the values is represented by single key-val pair, where key is the
* same for all the values.
*/
static boolean_t
get_prop_str_multival(char **attstr_buf, size_t *attstr_buf_sz, char *key_buf,
asi_scfhandle_t *handle)
{
asi_scfhandle_iter_prop_t handle_iter_prop;
if (!scf_init_iter_prop(&handle_iter_prop, handle)) {
prt_error(gettext("Unable to initialize scf iter handles "
"(multi-valued property)."));
return (B_FALSE);
}
if (scf_iter_property_values(handle_iter_prop.prop, handle->prop)
!= 0) {
prt_scf_err();
scf_free_iter_prop(&handle_iter_prop);
return (B_FALSE);
}
while (scf_iter_next_value(handle_iter_prop.prop,
handle_iter_prop.prop_val) == 1) {
if (!get_prop_str_singleval(attstr_buf, attstr_buf_sz, key_buf,
handle->prop, handle_iter_prop.prop_val)) {
scf_free_iter_prop(&handle_iter_prop);
return (B_FALSE);
}
}
scf_free_iter_prop(&handle_iter_prop);
return (B_TRUE);
}
/*
* get_props_kva_all() - get all properties and fill in the pgrp_kva.
*/
static boolean_t
get_props_kva_all(asi_scfhandle_t *handle, asi_scfhandle_iter_t *handle_iter,
kva_t **pgrp_kva)
{
char *key_buf;
ssize_t key_buf_sz;
char *attstr_buf; /* attribute string buffer */
size_t attstr_buf_sz = PGRP_MAXATT;
if ((attstr_buf = calloc(1, attstr_buf_sz)) == NULL) {
prt_error(gettext("No available memory."));
return (B_FALSE);
}
if ((key_buf_sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) {
prt_scf_err();
free(attstr_buf);
return (B_FALSE);
}
if ((key_buf = malloc(++key_buf_sz)) == NULL) {
prt_error(gettext("No available memory."));
free(attstr_buf);
return (B_FALSE);
}
while (scf_iter_next_property(handle_iter->prop, handle->prop) == 1) {
if (scf_property_get_name(handle->prop, key_buf,
key_buf_sz) == -1) {
prt_scf_err();
goto err_out;
}
if (scf_property_get_value(handle->prop,
handle_iter->prop_val) == 0) {
/* single-valued property call path */
if (!get_prop_str_singleval(&attstr_buf, &attstr_buf_sz,
key_buf, handle->prop, handle_iter->prop_val)) {
goto err_out;
}
} else {
if (scf_error() != SCF_ERROR_CONSTRAINT_VIOLATED) {
prt_scf_err();
goto err_out;
}
/* multi-valued property call path */
if (!get_prop_str_multival(&attstr_buf, &attstr_buf_sz,
key_buf, handle)) {
goto err_out;
}
}
}
free(key_buf);
DPRINT((dbfp, "Property string to be parsed: %s\n",
*attstr_buf == '\0' ? "(empty)" : attstr_buf));
if (*attstr_buf == '\0' || (*pgrp_kva = _str2kva(attstr_buf, KV_ASSIGN,
KV_DELIMITER)) == NULL) {
prt_error(gettext("Empty or invalid attribute string."));
free(attstr_buf);
return (B_FALSE);
}
free(attstr_buf);
return (B_TRUE);
err_out:
free(key_buf);
free(attstr_buf);
return (B_FALSE);
}
/*
* get_pgrp_kva() - get and save properties and values of given property group
* (or all properties and values of all property groups of type pgrp_type in
* case pgrp_name == NULL) into scf_pgrp_kva_node_t.
*/
static boolean_t
get_pgrp_kva(asi_scfhandle_t *handle, asi_scfhandle_iter_t *handle_iter,
scf_pgrp_kva_node_t **pgrp_kva_ll, char *pgrp_name, char *pgrp_type)
{
scf_pgrp_kva_node_t *node = NULL;
scf_pgrp_kva_node_t *node_prev = NULL;
scf_pgrp_kva_node_t *node_head = NULL;
char *pgrp_name_buf = NULL;
ssize_t pgrp_name_buf_sz;
int rc;
if ((pgrp_name_buf_sz = scf_limit(SCF_LIMIT_MAX_NAME_LENGTH)) == -1) {
prt_scf_err();
return (B_FALSE);
}
pgrp_name_buf_sz++;
DPRINT((dbfp, "Look for property group: %s (type: %s)\n",
pgrp_name == NULL ? "(not specified)" : pgrp_name, pgrp_type));
if (scf_iter_instance_pgs_typed(handle_iter->pgrp, handle->inst,
(const char *)pgrp_type) == -1) {
prt_scf_err();
return (B_FALSE);
}
while ((rc = scf_iter_next_pg(handle_iter->pgrp, handle->pgrp)) == 1) {
if (pgrp_name_buf == NULL &&
(pgrp_name_buf = malloc(pgrp_name_buf_sz)) == NULL) {
prt_error(gettext("No available memory."));
pgrp_kva_ll_free(node);
return (B_FALSE);
}
if (scf_pg_get_name(handle->pgrp, pgrp_name_buf,
pgrp_name_buf_sz) == -1) {
prt_scf_err();
free(pgrp_name_buf);
pgrp_kva_ll_free(node);
return (B_FALSE);
}
if (pgrp_name != NULL &&
strcmp(pgrp_name_buf, pgrp_name) != 0) {
continue;
}
if ((node = calloc(1, sizeof (scf_pgrp_kva_node_t))) == NULL) {
prt_error(gettext("No available memory."));
free(pgrp_name_buf);
pgrp_kva_ll_free(node_prev);
return (B_FALSE);
}
node->pgrp_name = pgrp_name_buf;
pgrp_name_buf = NULL;
if (node_head == NULL) {
node_head = node;
}
if (node_prev != NULL) {
node_prev->next = node;
node->prev = node_prev;
}
node_prev = node;
if (scf_iter_pg_properties(handle_iter->prop,
handle->pgrp) != 0) {
prt_scf_err();
pgrp_kva_ll_free(node);
return (B_FALSE);
}
if (!get_props_kva_all(handle, handle_iter,
&(node->pgrp_kva))) {
pgrp_kva_ll_free(node);
return (B_FALSE);
}
}
if (rc == -1) {
prt_scf_err();
pgrp_kva_ll_free(node);
return (B_FALSE);
}
#if DEBUG
{
scf_pgrp_kva_node_t *node_debug = node_head;
char attr_string[PGRP_MAXATT];
while (node_debug != NULL) {
if (_kva2str(node_debug->pgrp_kva, attr_string,
PGRP_MAXATT, KV_ASSIGN, KV_DELIMITER) == 0) {
DPRINT((dbfp, "Found property group - %s: %s\n",
node_debug->pgrp_name, attr_string));
} else {
DPRINT((dbfp, "Could not get attribute string "
"for %s\n", node_debug->pgrp_name));
}
node_debug = node_debug->next;
}
}
#endif
*pgrp_kva_ll = node_head;
return (B_TRUE);
}
/*
* chk_policy_context() - does some policy based checks, checks the context
* (zone, smf) in which the policy could make some sense.
*/
static boolean_t
chk_policy_context(char *policy_str)
{
/*
* "all" and "none" policy flags, since they represent
* sub/set of auditing policies, are not stored in the
* AUDITD_FMRI service instance configuration.
*/
DPRINT((dbfp, "Walking policy - %s: ", policy_str));
if (strcmp("all", policy_str) == 0 ||
strcmp("none", policy_str) == 0) {
DPRINT((dbfp, "skipped\n"));
return (B_FALSE);
}
/*
* In the local zone (!= GLOBAL_ZONEID) we do not touch
* "ahlt" and "perzone" policy flags, since these are
* relevant only in the global zone.
*/
if ((getzoneid() != GLOBAL_ZONEID) &&
(strcmp("ahlt", policy_str) == 0 ||
strcmp("perzone", policy_str) == 0)) {
DPRINT((dbfp, "skipped\n"));
return (B_FALSE);
}
return (B_TRUE);
}
/*
* do_getqctrl_scf() - get the values of qctrl properties of the audit service
*/
boolean_t
do_getqctrl_scf(struct au_qctrl *cval)
{
scf_propvec_t *prop_vect_ptr;
scf_qctrl_t cval_scf;
bzero(prop_vect, sizeof (prop_vect));
prop_vect_ptr = prop_vect;
add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QHIWATER,
SCF_TYPE_COUNT, &cval_scf.scf_qhiwater);
add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QLOWATER,
SCF_TYPE_COUNT, &cval_scf.scf_qlowater);
add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QBUFSZ,
SCF_TYPE_COUNT, &cval_scf.scf_qbufsz);
add_prop_vect_scf(prop_vect_ptr, QUEUECTRL_QDELAY,
SCF_TYPE_COUNT, &cval_scf.scf_qdelay);
if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
return (B_FALSE);
}
cval->aq_hiwater = (size_t)cval_scf.scf_qhiwater;
cval->aq_lowater = (size_t)cval_scf.scf_qlowater;
cval->aq_bufsz = (size_t)cval_scf.scf_qbufsz;
cval->aq_delay = (clock_t)cval_scf.scf_qdelay;
return (B_TRUE);
}
/*
* do_getqbufsz_scf() - get the qbufsz audit service property value
*/
boolean_t
do_getqbufsz_scf(size_t *cval)
{
uint64_t cval_l;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, QUEUECTRL_QBUFSZ, SCF_TYPE_COUNT, &cval_l);
if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
return (B_FALSE);
}
*cval = (size_t)cval_l;
return (B_TRUE);
}
/*
* do_getqdelay_scf() - get the qdelay audit service property value
*/
boolean_t
do_getqdelay_scf(clock_t *cval)
{
uint64_t cval_l;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, QUEUECTRL_QDELAY, SCF_TYPE_COUNT, &cval_l);
if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
return (B_FALSE);
}
*cval = (clock_t)cval_l;
return (B_TRUE);
}
/*
* do_getqhiwater_scf() - get the qhiwater audit service property value
*/
boolean_t
do_getqhiwater_scf(size_t *cval)
{
uint64_t cval_l;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, QUEUECTRL_QHIWATER, SCF_TYPE_COUNT,
&cval_l);
if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
return (B_FALSE);
}
*cval = (size_t)cval_l;
return (B_TRUE);
}
/*
* do_getqlowater_scf() - get the qlowater audit service property value
*/
boolean_t
do_getqlowater_scf(size_t *cval)
{
uint64_t cval_l;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, QUEUECTRL_QLOWATER, SCF_TYPE_COUNT,
&cval_l);
if (!get_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL)) {
return (B_FALSE);
}
*cval = (size_t)cval_l;
return (B_TRUE);
}
/*
* do_getpolicy_scf() - get the audit policy flags from service
*/
boolean_t
do_getpolicy_scf(uint32_t *policy_mask)
{
int i;
scf_propvec_t *prop_vect_ptr;
char *cur_policy_str;
policy_sw_t policy_arr[POLICY_TBL_SZ + 1];
policy_sw_t *policy_arr_ptr;
prop_vect_ptr = prop_vect;
policy_arr_ptr = policy_arr;
bzero(prop_vect, sizeof (prop_vect));
bzero(policy_arr, sizeof (policy_arr));
/* prepare the smf(5) query */
for (i = 0; i < POLICY_TBL_SZ; i++) {
cur_policy_str = policy_table[i].policy_str;
/* Do some basic policy dependent checks */
if (!chk_policy_context(cur_policy_str)) {
continue;
}
DPRINT((dbfp, "will be queried\n"));
add_prop_vect_scf(prop_vect_ptr++, cur_policy_str,
SCF_TYPE_BOOLEAN, &policy_arr_ptr->flag);
policy_arr_ptr->policy = cur_policy_str;
policy_arr_ptr++;
}
if (!get_val_scf(prop_vect, ASI_PGROUP_POLICY)) {
return (B_FALSE);
}
/* set the policy mask */
policy_arr_ptr = policy_arr;
*policy_mask = 0;
while (policy_arr_ptr->policy != NULL) {
if (policy_arr_ptr->flag) {
*policy_mask |= get_policy(policy_arr_ptr->policy);
}
policy_arr_ptr++;
}
return (B_TRUE);
}
/*
* do_setpolicy_scf() - sets the policy flags in audit service configuration
*/
boolean_t
do_setpolicy_scf(uint32_t policy)
{
int i;
char *cur_policy_str;
scf_propvec_t *prop_vect_ptr;
boolean_t bool_arr[POLICY_TBL_SZ];
boolean_t *bool_arr_ptr;
prop_vect_ptr = prop_vect;
bool_arr_ptr = bool_arr;
bzero(prop_vect, sizeof (prop_vect));
bzero(bool_arr, sizeof (bool_arr));
for (i = 0; i < POLICY_TBL_SZ; i++) {
cur_policy_str = policy_table[i].policy_str;
/* Do some basic policy dependent checks */
if (!chk_policy_context(cur_policy_str)) {
continue;
}
if (policy_table[i].policy_mask & policy) {
*bool_arr_ptr = B_TRUE;
} else {
*bool_arr_ptr = B_FALSE;
}
DPRINT((dbfp, "%s%s\n", (*bool_arr_ptr == B_TRUE ? "+" : "-"),
cur_policy_str));
add_prop_vect_scf(prop_vect_ptr++, cur_policy_str,
SCF_TYPE_BOOLEAN, bool_arr_ptr++);
}
return (set_val_scf(prop_vect, ASI_PGROUP_POLICY));
}
/*
* do_setqctrl_scf() - set the values of qctrl properties of the audit service
*/
boolean_t
do_setqctrl_scf(struct au_qctrl *cval)
{
scf_propvec_t *prop_vect_ptr;
scf_qctrl_t cval_scf;
/* sanity checks */
cval_scf.scf_qhiwater = (uint64_t)cval->aq_hiwater;
cval_scf.scf_qlowater = (uint64_t)cval->aq_lowater;
cval_scf.scf_qbufsz = (uint64_t)cval->aq_bufsz;
cval_scf.scf_qdelay = (uint64_t)cval->aq_delay;
if (cval_scf.scf_qhiwater == 0) {
cval_scf.scf_qhiwater = AQ_HIWATER;
}
if (cval_scf.scf_qlowater == 0) {
cval_scf.scf_qlowater = AQ_LOWATER;
}
if (cval_scf.scf_qbufsz == 0) {
cval_scf.scf_qbufsz = AQ_BUFSZ;
}
if (cval_scf.scf_qdelay == 0) {
cval_scf.scf_qdelay = AQ_DELAY;
}
if (!CHK_BDRY_QHIWATER(cval_scf.scf_qlowater, cval_scf.scf_qhiwater)) {
(void) printf(gettext("Specified audit queue hiwater mark is "
"outside of allowed boundaries.\n"));
return (B_FALSE);
}
if (!CHK_BDRY_QLOWATER(cval_scf.scf_qlowater, cval_scf.scf_qhiwater)) {
(void) printf(gettext("Specified audit queue lowater mark is "
"outside of allowed boundaries.\n"));
return (B_FALSE);
}
if (!CHK_BDRY_QBUFSZ(cval_scf.scf_qbufsz)) {
(void) printf(gettext("Specified audit queue buffer size is "
"outside of allowed boundaries.\n"));
return (B_FALSE);
}
if (!CHK_BDRY_QDELAY(cval_scf.scf_qdelay)) {
(void) printf(gettext("Specified audit queue delay is "
"outside of allowed boundaries.\n"));
return (B_FALSE);
}
cval_scf.scf_qhiwater = (uint64_t)cval->aq_hiwater;
cval_scf.scf_qlowater = (uint64_t)cval->aq_lowater;
cval_scf.scf_qbufsz = (uint64_t)cval->aq_bufsz;
cval_scf.scf_qdelay = (uint64_t)cval->aq_delay;
bzero(prop_vect, sizeof (prop_vect));
prop_vect_ptr = prop_vect;
add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QHIWATER, SCF_TYPE_COUNT,
&cval_scf.scf_qhiwater);
add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QLOWATER, SCF_TYPE_COUNT,
&cval_scf.scf_qlowater);
add_prop_vect_scf(prop_vect_ptr++, QUEUECTRL_QBUFSZ, SCF_TYPE_COUNT,
&cval_scf.scf_qbufsz);
add_prop_vect_scf(prop_vect_ptr, QUEUECTRL_QDELAY, SCF_TYPE_COUNT,
&cval_scf.scf_qdelay);
return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
}
/*
* do_setqbufsz_scf() - set the qbufsz property value of the audit service
*/
boolean_t
do_setqbufsz_scf(size_t *cval)
{
uint64_t cval_l;
if (!CHK_BDRY_QBUFSZ(*cval) && *cval != 0) {
(void) printf(gettext("Specified audit queue buffer size is "
"outside of allowed boundaries.\n"));
return (B_FALSE);
}
cval_l = (uint64_t)*cval;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, QUEUECTRL_QBUFSZ, SCF_TYPE_COUNT, &cval_l);
return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
}
/*
* do_setqdelay_scf() - set the qdelay property value of the audit service
*/
boolean_t
do_setqdelay_scf(clock_t *cval)
{
uint64_t cval_l;
if (!CHK_BDRY_QDELAY(*cval) && *cval != 0) {
(void) printf(gettext("Specified audit queue delay is "
"outside of allowed boundaries.\n"));
return (B_FALSE);
}
cval_l = (uint64_t)*cval;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, QUEUECTRL_QDELAY, SCF_TYPE_COUNT, &cval_l);
return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
}
/*
* do_setqhiwater_scf() - set the qhiwater property value of the audit service
*/
boolean_t
do_setqhiwater_scf(size_t *cval)
{
uint64_t cval_l;
size_t cval_lowater;
if (!do_getqlowater_scf(&cval_lowater)) {
(void) printf(gettext("Could not get configured value of "
"queue lowater mark.\n"));
return (B_FALSE);
}
if (cval_lowater == 0) {
cval_lowater = AQ_LOWATER;
}
if (!CHK_BDRY_QHIWATER(cval_lowater, *cval) && *cval != 0) {
(void) printf(gettext("Specified audit queue hiwater mark is "
"outside of allowed boundaries.\n"));
return (B_FALSE);
}
cval_l = (uint64_t)*cval;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, QUEUECTRL_QHIWATER, SCF_TYPE_COUNT,
&cval_l);
return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
}
/*
* do_setqlowater_scf() - set the qlowater property value of the audit service
*/
boolean_t
do_setqlowater_scf(size_t *cval)
{
uint64_t cval_l;
size_t cval_hiwater;
if (!do_getqhiwater_scf(&cval_hiwater)) {
(void) printf(gettext("Could not get configured value of "
"queue hiwater mark.\n"));
return (B_FALSE);
}
if (cval_hiwater == 0) {
cval_hiwater = AQ_HIWATER;
}
if (!CHK_BDRY_QLOWATER(*cval, cval_hiwater) && *cval != 0) {
(void) printf(gettext("Specified audit queue lowater mark is "
"outside of allowed boundaries.\n"));
return (B_FALSE);
}
cval_l = (uint64_t)*cval;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, QUEUECTRL_QLOWATER, SCF_TYPE_COUNT,
&cval_l);
return (set_val_scf(prop_vect, ASI_PGROUP_QUEUECTRL));
}
/*
* do_getflags_scf() - get the audit attributable flags from service
*/
boolean_t
do_getflags_scf(char **flags)
{
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, PRESELECTION_FLAGS, SCF_TYPE_ASTRING,
flags);
return (get_val_scf(prop_vect, ASI_PGROUP_PRESELECTION));
}
/*
* do_getnaflags_scf() - get the audit non-attributable flags from service
*/
boolean_t
do_getnaflags_scf(char **naflags)
{
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, PRESELECTION_NAFLAGS, SCF_TYPE_ASTRING,
naflags);
return (get_val_scf(prop_vect, ASI_PGROUP_PRESELECTION));
}
/*
* do_getars_scf() - get the audit remote server configuration (server)
*/
boolean_t
do_getars_scf(ars_config_t *server_cfg)
{
scf_propvec_t *prop_vect_ptr = prop_vect;
scf_ars_t cval_scf;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect_ptr++, ARS_ACTIVE,
SCF_TYPE_BOOLEAN, &cval_scf.scf_active);
add_prop_vect_scf(prop_vect_ptr++, ARS_LISTEN_ADDRESS,
SCF_TYPE_ASTRING, &cval_scf.scf_listen_address);
add_prop_vect_scf(prop_vect_ptr++, ARS_LISTEN_PORT,
SCF_TYPE_COUNT, &cval_scf.scf_listen_port);
add_prop_vect_scf(prop_vect_ptr++, ARS_LOGIN_GRACE_TIME,
SCF_TYPE_COUNT, &cval_scf.scf_login_grace_time);
add_prop_vect_scf(prop_vect_ptr, ARS_MAX_STARTUPS,
SCF_TYPE_ASTRING, &cval_scf.scf_max_startups);
if (!get_val_scf(prop_vect, ASI_PGROUP_ARS)) {
return (B_FALSE);
}
server_cfg->active = (uint_t)cval_scf.scf_active;
server_cfg->listen_address = cval_scf.scf_listen_address;
server_cfg->login_grace_time = (time_t)cval_scf.scf_login_grace_time;
if (sscanf(cval_scf.scf_max_startups, "%u:%u:%u",
&server_cfg->max_startups.begin,
&server_cfg->max_startups.rate,
&server_cfg->max_startups.full) != 3) {
server_cfg->max_startups.begin = 0;
server_cfg->max_startups.rate = 0;
server_cfg->max_startups.full =
(uint_t)atoi(cval_scf.scf_max_startups);
}
server_cfg->listen_port = (in_port_t)cval_scf.scf_listen_port;
free(cval_scf.scf_max_startups);
return (B_TRUE);
}
/*
* do_setflags_scf() - set the attributable mask property value of the audit
* service
*/
boolean_t
do_setflags_scf(char *flags)
{
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, PRESELECTION_FLAGS, SCF_TYPE_ASTRING,
flags);
return (set_val_scf(prop_vect, ASI_PGROUP_PRESELECTION));
}
/*
* do_setnaflags_scf() - set the attributable mask property value of the audit
* service
*/
boolean_t
do_setnaflags_scf(char *naflags)
{
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect, PRESELECTION_NAFLAGS, SCF_TYPE_ASTRING,
naflags);
return (set_val_scf(prop_vect, ASI_PGROUP_PRESELECTION));
}
/*
* do_destroypgrp_scf() - destroy a property group.
*/
boolean_t
do_destroypgrp_scf(char *pgrp_name)
{
char *asi_fmri;
asi_scfhandle_t handle;
if (asprintf(&asi_fmri, "%s%s%s", AUDITD_FMRI,
SCF_FMRI_PROPERTYGRP_PREFIX, pgrp_name) == -1) {
prt_error(gettext("Out of memory."));
return (B_FALSE);
}
DPRINT((dbfp, "%s will be decoded\n", asi_fmri));
/*
* scf_init() creates slightly more handles than is needed; this is
* perceived as acceptable since it allows better code readability
* while it has marginal impact on the executed command.
*/
if (!scf_init(&handle)) {
prt_error(gettext("Unable to initialize scf handles."));
free(asi_fmri);
return (B_FALSE);
}
if (scf_handle_decode_fmri(handle.hndl, asi_fmri, NULL, NULL,
handle.inst, handle.pgrp, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
goto err_out;
}
if (scf_pg_delete(handle.pgrp) == -1) {
goto err_out;
}
scf_free(&handle);
free(asi_fmri);
return (B_TRUE);
err_out:
prt_scf_err();
scf_free(&handle);
free(asi_fmri);
return (B_FALSE);
}
/*
* do_createpgrp_scf() - create a property group.
*/
boolean_t
do_createpgrp_scf(char *pgrp_name, char *pgrp_type, scf_propvec_t *prop_vect)
{
asi_scfhandle_t handle;
/*
* scf_init() creates slightly more handles then is needed; this
* is perceived as acceptable since it allows better code readibility
* while it has marginal impact on the executed command.
*/
if (!scf_init(&handle)) {
prt_error(gettext("Unable to initialize scf handles."));
return (B_FALSE);
}
if (scf_handle_decode_fmri(handle.hndl, AUDITD_FMRI, NULL, NULL,
handle.inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
goto err_out;
}
if (scf_instance_add_pg(handle.inst, pgrp_name, pgrp_type, 0,
handle.pgrp) == -1) {
goto err_out;
}
if (set_val_scf(prop_vect, pgrp_name)) {
scf_free(&handle);
return (B_TRUE);
}
if (!do_destroypgrp_scf(pgrp_name)) {
prt_error(gettext("Could not destroy invalid property "
"group: %s"), pgrp_name);
}
err_out:
prt_scf_err();
scf_free(&handle);
return (B_FALSE);
}
/*
* do_createcgrp_scf() - create a property group representing connection group
* in the audit remote server model. All properties are to be set to their
* default values.
*/
boolean_t
do_createcgrp_scf(char *pgrp_name)
{
scf_propvec_t *prop_vect_ptr = prop_vect;
scf_cgrp_t cval_scf_default = {
CGRP_ACTIVE_DEFAULT,
CGRP_HOSTS_DEFAULT,
CGRP_BINFILE_DIR_DEFAULT,
CGRP_BINFILE_FSIZE_DEFAULT,
CGRP_BINFILE_MINFREE_DEFAULT
};
boolean_t rval;
bzero(prop_vect, sizeof (prop_vect));
add_prop_vect_scf(prop_vect_ptr++, CGRP_ACTIVE, SCF_TYPE_BOOLEAN,
&cval_scf_default.scf_active);
add_prop_vect_scf(prop_vect_ptr++, CGRP_HOSTS, SCF_TYPE_ASTRING,
cval_scf_default.scf_hosts);
add_prop_vect_scf(prop_vect_ptr++, CGRP_BINFILE_DIR, SCF_TYPE_ASTRING,
cval_scf_default.scf_binfile_dir);
add_prop_vect_scf(prop_vect_ptr++, CGRP_BINFILE_FSIZE, SCF_TYPE_ASTRING,
cval_scf_default.scf_binfile_fsize);
add_prop_vect_scf(prop_vect_ptr++, CGRP_BINFILE_MINFREE,
SCF_TYPE_COUNT, &cval_scf_default.scf_binfile_minfree);
if (!add_prop_vect_mval_scf(prop_vect_ptr, "read_authorization",
SCF_TYPE_ASTRING, "solaris.smf.manage.audit") ||
!add_prop_vect_mval_scf(prop_vect_ptr++, NULL, SCF_TYPE_INVALID,
"solaris.smf.value.audit")) {
rval = B_FALSE;
goto out;
}
add_prop_vect_scf(prop_vect_ptr, "value_authorization",
SCF_TYPE_ASTRING, "solaris.smf.value.audit");
rval = do_createpgrp_scf(pgrp_name, ASI_PGROUP_CGRP_TYPE, prop_vect);
out:
free_prop_vect_mval();
return (rval);
}
/*
* pgrp_avail_scf() - look for the property group in the audit service
* configuration. Test availability of: plugins, connection groups.
*/
boolean_t
pgrp_avail_scf(const char *pgrp_name)
{
asi_scfhandle_t handle;
char *asi_fmri;
boolean_t rv = B_TRUE;
if (pgrp_name == NULL || *pgrp_name == '\0') {
return (B_FALSE);
}
if (asprintf(&asi_fmri, "%s%s%s", AUDITD_FMRI,
SCF_FMRI_PROPERTYGRP_PREFIX, pgrp_name) == -1) {
prt_error(gettext("Out of memory."));
return (B_FALSE);
}
DPRINT((dbfp, "%s will be decoded\n", asi_fmri));
/*
* scf_init() creates slightly more handles then is needed; this
* is perceived as acceptable since it allows better code readibility
* while it has marginal impact on the executed command.
*/
if (!scf_init(&handle)) {
prt_error(gettext("Unable to initialize scf handles."));
free(asi_fmri);
return (B_FALSE);
}
if (scf_handle_decode_fmri(handle.hndl, asi_fmri, NULL, NULL,
handle.inst, handle.pgrp, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
rv = B_FALSE;
if (scf_error() != SCF_ERROR_NOT_FOUND) {
prt_scf_err();
}
DPRINT((dbfp, "No such property group found: %s (%s)\n",
pgrp_name, scf_strerror(scf_error())));
}
scf_free(&handle);
free(asi_fmri);
return (rv);
}
/*
* pgrp_ctr_scf() - return the number of property groups of given type; -1 on
* error. Test availability of: plugins, connection groups.
*/
int
pgrp_ctr_scf(const char *pgrp_type)
{
int rc;
int ctr = 0;
asi_scfhandle_t handle;
asi_scfhandle_iter_t handle_iter;
if (pgrp_type == NULL || *pgrp_type == '\0') {
return (-1);
}
DPRINT((dbfp, "Look for property groups of type: %s)\n", pgrp_type));
if (!scf_init(&handle)) {
prt_error(gettext("Unable to initialize scf handles."));
return (-1);
}
if (scf_handle_decode_fmri(handle.hndl, AUDITD_FMRI, NULL, NULL,
handle.inst, NULL, NULL, SCF_DECODE_FMRI_EXACT) == -1) {
prt_scf_err();
scf_free(&handle);
return (-1);
}
if (!scf_init_iter(&handle_iter, &handle)) {
prt_error(gettext("Unable to initialize scf iter handles."));
scf_free(&handle);
return (-1);
}
if (scf_iter_instance_pgs_typed(handle_iter.pgrp, handle.inst,
(const char *)pgrp_type) == -1) {
prt_scf_err();
scf_free_iter(&handle_iter);
scf_free(&handle);
return (-1);
}
while ((rc = scf_iter_next_pg(handle_iter.pgrp, handle.pgrp)) == 1) {
ctr++;
}
if (rc == -1) {
prt_scf_err();
ctr = -1;
}
scf_free_iter(&handle_iter);
scf_free(&handle);
return (ctr);
}
/*
* do_getpgrp_scf() - get contents of property group from the audit service
* instance configuration.
*/
boolean_t
do_getpgrp_scf(char *pgrp_name, char *pgrp_type,
scf_pgrp_kva_node_t **pgrp_kva_ll)
{
char *asi_fmri;
asi_scfhandle_t handle;
asi_scfhandle_iter_t handle_iter;
boolean_t pgrp_all = B_FALSE;
boolean_t rv = B_TRUE;
if (pgrp_name == NULL || *pgrp_name == '\0') {
if (asprintf(&asi_fmri, "%s", AUDITD_FMRI) == -1) {
prt_error(gettext("Out of memory."));
return (B_FALSE);
}
pgrp_all = B_TRUE;
} else {
if (asprintf(&asi_fmri, "%s%s%s", AUDITD_FMRI,
SCF_FMRI_PROPERTYGRP_PREFIX, pgrp_name) == -1) {
prt_error(gettext("Out of memory."));
return (B_FALSE);
}
}
DPRINT((dbfp, "%s will be decoded\n", asi_fmri));
if (!scf_init(&handle)) {
prt_error(gettext("Unable to initialize scf handles."));
free(asi_fmri);
return (B_FALSE);
}
if (scf_handle_decode_fmri(handle.hndl, asi_fmri, NULL, NULL,
handle.inst, pgrp_all ? NULL : handle.pgrp, NULL,
SCF_DECODE_FMRI_EXACT) == -1) {
prt_scf_err();
scf_free(&handle);
free(asi_fmri);
return (B_FALSE);
}
if (!scf_init_iter(&handle_iter, &handle)) {
prt_error(gettext("Unable to initialize scf iter handles."));
scf_free(&handle);
free(asi_fmri);
return (B_FALSE);
}
rv = get_pgrp_kva(&handle, &handle_iter, pgrp_kva_ll,
pgrp_all ? NULL : pgrp_name, pgrp_type);
scf_free(&handle);
scf_free_iter(&handle_iter);
free(asi_fmri);
return (rv);
}
/*
* do_setpgrp_scf() - set key-val pairs for the given property group. Attributes
* in pgrp_att_rm are removed from the set of attributes before the properties
* update process.
*/
boolean_t
do_setpgrp_scf(char *pgrp_name, char *pgrp_att, char *pgrp_att_rm)
{
kva_t *pgrp_kva;
scf_simple_prop_t *pgrp_prop;
scf_type_t pgrp_prop_type;
scf_propvec_t *prop_vect_ptr;
int cnt;
int cnt_kva = 0;
int cnt_dup;
kv_t *data;
kv_t *data_dup;
boolean_t rval = B_TRUE;
bzero(prop_vect, sizeof (prop_vect));
prop_vect_ptr = prop_vect;
/* get rid of white-space chars */
remove_space(pgrp_att, PGRP_MAXATT);
DPRINT((dbfp, "attributes (no white-space): %s\n", pgrp_att));
if ((pgrp_kva = _str2kva(pgrp_att, KV_ASSIGN, KV_DELIMITER)) == NULL) {
prt_error(gettext("Could not parse attributes."));
return (B_FALSE);
}
/* remove unwanted attributes */
if (pgrp_att_rm != NULL) {
char *key;
char *pgrp_att_rm_ptr = pgrp_att_rm;
char *lasts;
while ((key = strtok_r(pgrp_att_rm_ptr, ";", &lasts)) != NULL) {
pgrp_att_rm_ptr = NULL;
_kva_free_value(pgrp_kva, key);
}
}
/* set attributes */
cnt = pgrp_kva->length;
data = pgrp_kva->data;
while (cnt > 0) {
if (data->value == NULL) {
cnt--;
cnt_kva++;
data++;
continue;
}
/* detect key duplicates */
if (cnt_kva > 0) {
cnt_dup = cnt_kva;
data_dup = data;
data_dup--;
for (; cnt_dup > 0; cnt_dup--, data_dup--) {
if (strcmp(data_dup->key, data->key) == 0) {
prt_error(gettext("Duplicate attribute:"
" %s"), data->key);
rval = B_FALSE;
goto err_out;
}
}
}
cnt_kva++;
if (!chk_prop_vect(&prop_vect_ptr, pgrp_name)) {
rval = B_FALSE;
goto err_out;
}
if ((pgrp_prop = scf_simple_prop_get(NULL, AUDITD_FMRI,
pgrp_name, data->key)) == NULL) {
prt_error(gettext("Could not get configuration for "
"attribute: %s"), data->key);
prt_scf_err();
rval = B_FALSE;
goto err_out;
}
if ((pgrp_prop_type = scf_simple_prop_type(pgrp_prop)) == -1) {
prt_error(gettext("Could not get property type: %s"),
data->key);
prt_scf_err();
rval = B_FALSE;
goto err_out;
}
switch (pgrp_prop_type) {
case SCF_TYPE_BOOLEAN: {
boolean_t *pval_bool;
pval_bool = (boolean_t *)malloc(sizeof (boolean_t));
if (pval_bool == NULL) {
prt_error(gettext("No free memory available."));
rval = B_FALSE;
goto err_out;
}
*pval_bool = (boolean_t)atoi(data->value);
add_prop_vect_scf(prop_vect_ptr++, data->key,
SCF_TYPE_BOOLEAN, pval_bool);
break;
}
case SCF_TYPE_ASTRING: {
char *pval_str;
if ((pval_str = strdup(data->value)) == NULL) {
prt_error(gettext("No free memory available."));
rval = B_FALSE;
goto err_out;
}
add_prop_vect_scf(prop_vect_ptr++, data->key,
SCF_TYPE_ASTRING, pval_str);
break;
}
case SCF_TYPE_COUNT: {
uint64_t *pval_count;
pval_count = (uint64_t *)malloc(sizeof (uint64_t));
if (pval_count == NULL) {
prt_error(gettext("No free memory available."));
rval = B_FALSE;
goto err_out;
}
*pval_count = (uint64_t)atoll(data->value);
add_prop_vect_scf(prop_vect_ptr++, data->key,
SCF_TYPE_COUNT, pval_count);
break;
}
default:
prt_error(gettext("Unsupported property type: %s (%d)"),
data->key, pgrp_prop_type);
break;
}
DPRINT((dbfp, "Prepared %s: %s\n", data->key, data->value));
scf_simple_prop_free(pgrp_prop);
data++;
cnt--;
}
if (!set_val_scf(prop_vect, pgrp_name)) {
rval = B_FALSE;
}
err_out:
free_prop_vect();
_kva_free(pgrp_kva);
return (rval);
}
/*
* pgrp_kva_ll_free() - free the memory used by property group kva linked list.
*/
void
pgrp_kva_ll_free(scf_pgrp_kva_node_t *node)
{
scf_pgrp_kva_node_t *node_next;
if (node == NULL) {
return;
}
while (node->prev != NULL) {
node = node->prev;
}
while (node != NULL) {
free(node->pgrp_name);
_kva_free(node->pgrp_kva);
node_next = node->next;
free(node);
node = node_next;
}
}
/*
* get_policy() - get policy mask entry.
*/
uint32_t
get_policy(char *policy)
{
int i;
for (i = 0; i < POLICY_TBL_SZ; i++) {
if (strcasecmp(policy, policy_table[i].policy_str) == 0) {
return (policy_table[i].policy_mask);
}
}
return (0);
}
/*
* get_laudit_cfg_state() - get per-configuration local audit state.
*/
boolean_t
get_laudit_cfg_state()
{
scf_pgrp_kva_node_t *plugin_kva_ll;
scf_pgrp_kva_node_t *plugin_kva_ll_head;
if (!do_getpgrp_scf(NULL, ASI_PGROUP_PLUGIN_TYPE, &plugin_kva_ll)) {
prt_error(gettext("Could not get plugin configuration."));
return (B_FALSE);
}
plugin_kva_ll_head = plugin_kva_ll;
for (; plugin_kva_ll != NULL; plugin_kva_ll = plugin_kva_ll->next) {
if (atoi(kva_match(plugin_kva_ll->pgrp_kva, "active")) == 1) {
break;
}
}
pgrp_kva_ll_free(plugin_kva_ll_head);
if (plugin_kva_ll == NULL) {
return (B_FALSE);
}
return (B_TRUE);
}
/*
* get_raudit_cfg_state() - get per-configuration remote audit state.
*/
boolean_t
get_raudit_cfg_state()
{
scf_pgrp_kva_node_t *cgrp_kva_ll = NULL;
scf_pgrp_kva_node_t *cgrp_kva_ll_ptr;
ars_config_t ars_cfg = { 0 };
char *att_str;
boolean_t rc = B_FALSE;
/* general ARS switch */
if (!do_getars_scf(&ars_cfg)) {
prt_error(gettext("Could not get audit remote server "
"configuration."));
return (B_FALSE);
}
free(ars_cfg.listen_address);
if (!ars_cfg.active) {
return (B_FALSE);
}
/* at least one active connection group */
if (!do_getpgrp_scf(NULL, ASI_PGROUP_CGRP_TYPE, &cgrp_kva_ll)) {
prt_error(gettext("Could not get connection group "
"configuration."));
return (B_FALSE);
}
cgrp_kva_ll_ptr = cgrp_kva_ll;
while (cgrp_kva_ll_ptr != NULL) {
if ((att_str = kva_match(cgrp_kva_ll_ptr->pgrp_kva,
CGRP_ACTIVE)) == NULL) {
size_t cgrp_name_prefix_len;
cgrp_name_prefix_len = strlen(ASI_PGROUP_CGRP_PREFIX);
prt_error(gettext("Could not get state of the "
"connection group: %s"),
&cgrp_kva_ll_ptr->pgrp_name[cgrp_name_prefix_len]);
break;
}
if ((boolean_t)atoi(att_str)) {
rc = B_TRUE;
break;
}
cgrp_kva_ll_ptr = cgrp_kva_ll_ptr->next;
}
pgrp_kva_ll_free(cgrp_kva_ll);
return (rc);
}