/*
* 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) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
*/
/*
* get audit preselection mask values
*/
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <bsm/audit.h>
#include <bsm/libbsm.h>
#include <adt_xlate.h> /* adt_write_syslog */
#define SUCCESS 0x1 /* '+' success mask */
#define FAILURE 0x2 /* '-' failure mask */
#define INVERSE 0x4 /* '^' invert the mask */
static int
match_class(char *s, char *prefix, uint_t m, int v)
{
au_class_ent_t *p_class;
(void) strcat(s, prefix);
if (cacheauclass(&p_class, m) == 1) {
if (v == 0) {
(void) strncat(s, p_class->ac_name, AU_CLASS_NAME_MAX);
} else {
(void) strncat(s, p_class->ac_desc, AU_CLASS_DESC_MAX);
}
(void) strcat(s, ",");
return (0);
}
return (-1);
}
/*
* getauditflagschar() - convert bit flag to character string
*
* input: masks->am_success - audit on success
* masks->am_failure - audit on failure
* verbose - string format. 0 if short name; 1 if long name;
*
* output: auditstring - resultant audit string
*
* returns: 0 - entry read ok
* -1 - error
*/
int
getauditflagschar(char *auditstring, au_mask_t *masks, int verbose)
{
char *prefix; /* +, -, or null */
unsigned int m; /* for masking with masks */
au_mask_t all; /* value for the string "all" */
int plus_all = 0; /* true if +all */
int minus_all = 0; /* true if -all */
int l;
/* initialize input buffer */
*auditstring = '\0';
/* no masks, no flags; we're outta here */
if ((masks->am_success == 0) && (masks->am_failure == 0)) {
if (match_class(auditstring, "", 0, verbose) != 0)
return (-1);
/* kludge to get rid of trailing comma */
l = strlen(auditstring) - 1;
if (auditstring[l] == ',')
auditstring[l] = '\0';
return (0);
}
/* Get the mask value for the string "all" */
all.am_success = 0;
all.am_failure = 0;
if (getauditflagsbin("all", &all) != 0)
return (-1);
if (all.am_success == masks->am_success) {
if (all.am_failure == masks->am_failure) {
(void) strcat(auditstring, "all");
return (0);
}
(void) strcat(auditstring, "+all,");
plus_all = 1;
} else if (all.am_failure == masks->am_failure) {
(void) strcat(auditstring, "-all,");
minus_all = 1;
}
for (m = (unsigned)0x80000000; m != 0; m >>= 1) {
if (m & masks->am_success & masks->am_failure)
prefix = plus_all ? "-" : (minus_all ? "+" : "");
else if (m & masks->am_success)
prefix = "+";
else if (m & masks->am_failure)
prefix = "-";
else
continue;
if (match_class(auditstring, prefix, m, verbose) != 0)
return (-1);
}
if (*(prefix = auditstring + strlen(auditstring) - 1) == ',')
*prefix = '\0';
return (0);
}
/*
* Audit flags:
*
* [+ | - | ^ | ^+ | ^-]<classname>{,[+ | - | ^ | ^+ | ^-]<classname>}*
*
* <classname>, add class mask to success and failure mask.
* +<classname>, add class mask only to success mask.
* -<classname>, add class mask only to failure mask.
* ^<classname>, remove class mask from success and failure mask.
* ^+<classname>, remove class mask from success mask.
* ^-<classname>, remove class mask from failure mask.
*/
/*
* __chkflags - check if the audit flags are valid for this system
*
* Entry flags = audit flags string.
* cont = B_TRUE, continue parsing even if error.
* B_FALSE, return failure on error.
*
* Exit mask = audit mask as defined by flags.
*
* Return B_TRUE if no errors, or continue == B_TRUE.
* B_FALSE and if error != NULL, flags in error.
*/
boolean_t
__chkflags(char *flags, au_mask_t *mask, boolean_t cont, char **error)
{
uint32_t prefix;
au_class_ent_t *class;
char name[AU_CLASS_NAME_MAX+1];
int i;
if (flags == NULL || mask == NULL) {
return (B_FALSE);
}
mask->am_success = 0;
mask->am_failure = 0;
while (*flags != '\0') {
prefix = (SUCCESS | FAILURE);
/* skip white space */
while (isspace(*flags)) {
flags++;
}
if (flags == '\0') {
break;
}
if (error != NULL) {
/* save error pointer */
*error = flags;
}
/* get the prefix */
if (*flags == '+') {
flags++;
prefix ^= FAILURE;
} else if (*flags == '-') {
flags++;
prefix ^= SUCCESS;
} else if (*flags == '^') {
flags++;
prefix |= INVERSE;
if (*flags == '+') {
flags++;
prefix ^= FAILURE;
} else if (*flags == '-') {
flags++;
prefix ^= SUCCESS;
}
}
/* get class name */
for (i = 0; (i < sizeof (name) - 1) &&
!(*flags == '\0' || *flags == ','); i++) {
name[i] = *flags++;
}
name[i++] = '\0';
if (*flags == ',') {
/* skip comma (',') */
flags++;
}
if (cacheauclassnam(&class, name) != 1) {
if (!cont) {
return (B_FALSE);
} else {
char msg[512];
(void) snprintf(msg, sizeof (msg), "invalid "
"audit flag %s", name);
adt_write_syslog(msg, EINVAL);
}
} else {
/* add class mask */
if ((prefix & (INVERSE | SUCCESS)) == SUCCESS) {
mask->am_success |= class->ac_class;
} else if ((prefix & (INVERSE | SUCCESS)) ==
(INVERSE | SUCCESS)) {
mask->am_success &= ~(class->ac_class);
}
if ((prefix & (INVERSE | FAILURE)) == FAILURE) {
mask->am_failure |= class->ac_class;
} else if ((prefix & (INVERSE | FAILURE)) ==
(INVERSE | FAILURE)) {
mask->am_failure &= ~(class->ac_class);
}
}
}
return (B_TRUE);
}
/*
* getauditflagsbin() - converts character string to success and
* failure bit masks
*
* input: auditstring - audit string
*
* output: masks->am_success - audit on success
* masks->am_failure - audit on failure
*
* returns: 0 - ok
* -1 - error - string or mask NULL.
*/
int
getauditflagsbin(char *auditstring, au_mask_t *masks)
{
if (__chkflags(auditstring, masks, B_TRUE, NULL)) {
return (0);
}
return (-1);
}