root/usr/src/lib/libtsol/common/misc.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 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */


/*
 *      Miscellaneous user interfaces to trusted label functions.
 *
 */


#include <ctype.h>
#include <stdlib.h>
#include <strings.h>

#include <sys/mman.h>

#include <tsol/label.h>

#include "labeld.h"
#include "clnt.h"
#include <sys/tsol/label_macro.h>
#include <secdb.h>
#include <user_attr.h>

static  bslabel_t slow, shigh;  /* static Admin Low and High SLs */
static  bclear_t  clow, chigh;  /* static Admin Low and High CLRs */

static char color[MAXCOLOR];


#define incall callp->param.acall.cargs.inset_arg
#define inret callp->param.aret.rvals.inset_ret
/*
 *      blinset - Check in a label set.
 *
 *      Entry   label = Sensitivity Label to check.
 *              id    = Label set identifier of set to check.
 *
 *      Exit    None.
 *
 *      Returns -1, If label set unavailable, or server failure.
 *               0, If label not in label set.
 *               1, If label is in the label set.
 *
 *      Calls   __call_labeld(BLINSET), BLTYPE, BSLLOW, BSLHIGH.
 *
 *      Uses    slow, shigh.
 */

int
blinset(const bslabel_t *label, const set_id *id)
{
        if (id->type == SYSTEM_ACCREDITATION_RANGE) {
                if (!BLTYPE(&slow, SUN_SL_ID)) {
                        /* initialize static labels. */

                        BSLLOW(&slow);
                        BSLHIGH(&shigh);
                }

                if (BLTYPE(label, SUN_SL_ID) &&
                    (BLEQUAL(label, &slow) || BLEQUAL(label, &shigh)))

                        return (1);
        }
        if (id->type == USER_ACCREDITATION_RANGE ||
            id->type == SYSTEM_ACCREDITATION_RANGE) {
                labeld_data_t   call;
                labeld_data_t   *callp = &call;
                size_t  bufsize = sizeof (labeld_data_t);
                size_t  datasize = CALL_SIZE(inset_call_t, 0);

                call.callop = BLINSET;
                incall.label = *label;
                incall.type = id->type;

                if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {
                        /* process error */

                        return (-1);
                }
                return (inret.inset);
        } else {
                /*
                 * Only System and User Accreditation Ranges presently
                 * implemented.
                 */
                return (-1);
        }
}
#undef  incall
#undef  inret

#define slvcall callp->param.acall.cargs.slvalid_arg
#define slvret callp->param.aret.rvals.slvalid_ret
/*
 *      bslvalid - Check Sensitivity Label for validity.
 *
 *      Entry   label = Sensitivity Label to check.
 *
 *      Exit    None.
 *
 *      Returns -1, If unable to access label encodings file, or server failure.
 *               0, If label not valid.
 *               1, If label is valid.
 *
 *      Calls   __call_labeld(BSLVALID), BLTYPE, BSLLOW, BSLHIGH.
 *
 *      Uses    slow, shigh.
 *
 */

int
bslvalid(const bslabel_t *label)
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(slvalid_call_t, 0);

        if (!BLTYPE(&slow, SUN_SL_ID)) {
                /* initialize static labels. */

                BSLLOW(&slow);
                BSLHIGH(&shigh);
        }

        if (BLTYPE(label, SUN_SL_ID) &&
            (BLEQUAL(label, &slow) || BLEQUAL(label, &shigh))) {

                return (1);
        }

        call.callop = BSLVALID;
        slvcall.label = *label;

        if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {
                /* process error */

                return (-1);
        }
        return (slvret.valid);
}
#undef  slvcall
#undef  slvret

#define clrvcall callp->param.acall.cargs.clrvalid_arg
#define clrvret callp->param.aret.rvals.clrvalid_ret
/*
 *      bclearvalid - Check Clearance for validity.
 *
 *      Entry   clearance = Clearance to check.
 *
 *      Exit    None.
 *
 *      Returns -1, If unable to access label encodings file, or server failure.
 *               0, If label not valid.
 *               1, If label is valid.
 *
 *      Calls   __call_labeld(BCLEARVALID), BLTYPE, BCLEARLOW, BCLEARHIGH.
 *
 *      Uses    clow, chigh.
 *
 */

int
bclearvalid(const bclear_t *clearance)
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(clrvalid_call_t, 0);

        if (!BLTYPE(&clow, SUN_CLR_ID)) {
                /* initialize static labels. */

                BCLEARLOW(&clow);
                BCLEARHIGH(&chigh);
        }

        if (BLTYPE(clearance, SUN_CLR_ID) &&
            (BLEQUAL(clearance, &clow) || BLEQUAL(clearance, &chigh))) {

                return (1);
        }

        call.callop = BCLEARVALID;
        clrvcall.clear = *clearance;

        if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {
                /* process error */

                return (-1);
        }
        return (clrvret.valid);
}
#undef  clrvcall
#undef  clrvret

#define inforet callp->param.aret.rvals.info_ret
/*
 *      labelinfo - Get information about the label encodings file.
 *
 *      Entry   info = Address of label_info structure to update.
 *
 *      Exit    info = Updated.
 *
 *      Returns -1, If unable to access label encodings file, or server failure.
 *               1, If successful.
 *
 *      Calls   __call_labeld(LABELINFO).
 */

int
labelinfo(struct label_info *info)
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(info_call_t, 0);
        int     rval;

        call.callop = LABELINFO;

        if ((rval = __call_labeld(&callp, &bufsize, &datasize)) != SUCCESS) {
                /* process error */

                return (-1);
        }
        *info = inforet.info;
        return (rval);
}
#undef  inforet

#define lvret callp->param.aret.rvals.vers_ret
/*
 *      labelvers - Get version string of the label encodings file.
 *
 *      Entry   version = Address of string pointer to return.
 *              len = Length of string if pre-allocated.
 *
 *      Exit    version = Updated.
 *
 *      Returns -1, If unable to access label encodings file, or server failure.
 *               0, If unable to allocate version string,
 *                      or pre-allocated version string to short
 *                      (and **version = '\0').
 *              length (including null) of version string, If successful.
 *
 *      Calls   __call_labeld(LABELVERS)
 *                      malloc, strlen.
 */

ssize_t
labelvers(char **version, size_t len)
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(vers_call_t, 0);
        size_t  ver_len;

        call.callop = LABELVERS;

        if (__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) {

                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (-1);
        }

        /* unpack length */

        ver_len = strlen(lvret.vers) + 1;
        if (*version == NULL) {
                if ((*version = malloc(ver_len)) == NULL) {
                        if (callp != &call)
                                /* release return buffer */
                                (void) munmap((void *)callp, bufsize);
                        return (0);
                }
        } else if (ver_len > len) {
                **version = '\0';
                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (0);
        }
        (void) strcpy(*version, lvret.vers);

        if (callp != &call)
                /* release return buffer */
                (void) munmap((void *)callp, bufsize);
        return (ver_len);
}  /* labelvers */
#undef  lvret

#define ccall callp->param.acall.cargs.color_arg
#define cret callp->param.aret.rvals.color_ret
/*
 *      bltocolor - get ASCII color name of label.
 *
 *      Entry   label = Sensitivity Level of color to get.
 *              size  = Size of the color_name array.
 *              color_name = Storage for ASCII color name string to be returned.
 *
 *      Exit    None.
 *
 *      Returns NULL, If error (label encodings file not accessible,
 *                         invalid label, no color for this label).
 *              Address of color_name parameter containing ASCII color name
 *                      defined for the label.
 *
 *      Calls   __call_labeld(BLTOCOLOR), strlen.
 */

char *
bltocolor_r(const blevel_t *label, size_t size, char *color_name)
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(color_call_t, 0);
        char    *colorp;

        call.callop = BLTOCOLOR;
        ccall.label = *label;

        if ((__call_labeld(&callp, &bufsize, &datasize) != SUCCESS) ||
            (callp->reterr != 0) ||
            (strlen(cret.color) >= size)) {

                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (NULL);
        }

        colorp = strcpy(color_name, cret.color);

        if (callp != &call)
                /* release return buffer */
                (void) munmap((void *)callp, bufsize);
        return (colorp);
}  /* bltocolor_r */
#undef  ccall
#undef  cret

/*
 *      bltocolor - get ASCII color name of label.
 *
 *      Entry   label = Sensitivity Level of color to get.
 *
 *      Exit    None.
 *
 *      Returns NULL, If error (label encodings file not accessible,
 *                         invalid label, no color for this label).
 *              Address of statically allocated string containing ASCII
 *                      color name defined for the classification contained
 *                      in label.
 *
 *      Uses    color.
 *
 *      Calls   bltocolor_r.
 */

char *
bltocolor(const blevel_t *label)
{
        return (bltocolor_r(label, sizeof (color), color));
}  /* bltocolor */

blevel_t *
blabel_alloc(void)
{
        return (m_label_alloc(MAC_LABEL));
}

void
blabel_free(blevel_t *label_p)
{
        free(label_p);
}

size32_t
blabel_size(void)
{
        return (sizeof (blevel_t));
}

/*
 *      getuserrange - get label range for user
 *
 *      Entry   username of user
 *
 *      Exit    None.
 *
 *      Returns NULL, If memory allocation failure or userdefs failure.
 *              otherwise returns the allocates m_range_t with the
 *              user's min and max labels set.
 */

m_range_t *
getuserrange(const char *username)
{
        char            *kv_str = NULL;
        userattr_t      *userp = NULL;
        m_range_t       *range;
        m_label_t       *def_min, *def_clr;

        /*
         * Get some memory
         */

        if ((range = malloc(sizeof (m_range_t))) == NULL) {
                return (NULL);
        }
        if ((range->lower_bound = m_label_alloc(MAC_LABEL)) == NULL) {
                free(range);
                return (NULL);
        }
        def_min = range->lower_bound;
        if ((range->upper_bound = m_label_alloc(USER_CLEAR)) == NULL) {
                m_label_free(range->lower_bound);
                free(range);
                return (NULL);
        }
        def_clr = range->upper_bound;

        /* If the user has an explicit min_label or clearance, use it. */
        if ((userp = getusernam(username)) != NULL) {
                if ((kv_str = kva_match(userp->attr, USERATTR_MINLABEL))
                    != NULL) {
                        (void) str_to_label(kv_str, &range->lower_bound,
                            MAC_LABEL, L_NO_CORRECTION, NULL);
                        def_min = NULL;         /* don't get default later */
                }
                if ((kv_str = kva_match(userp->attr, USERATTR_CLEARANCE))
                    != NULL) {
                        (void) str_to_label(kv_str, &range->upper_bound,
                            USER_CLEAR, L_NO_CORRECTION, NULL);
                        def_clr = NULL;         /* don't get default later */
                }
                free_userattr(userp);
        }
        if (def_min || def_clr) {
                /* Need to use system default clearance and/or min_label */
                if ((userdefs(def_min, def_clr)) == -1) {
                        m_label_free(range->lower_bound);
                        m_label_free(range->upper_bound);
                        free(range);
                        return (NULL);
                }
        }

        return (range);
}