root/usr/src/lib/libbsm/common/getauditflags.c
/*
 * 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);
}