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

/*
 *      Label library contract private interfaces.
 *
 *      Binary labels to String labels with dimming word lists.
 *      Dimming word list titles.
 *      Default user labels.
 */

#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>

#include <sys/mman.h>

#include <tsol/label.h>

#include "clnt.h"
#include "labeld.h"

/*
 *      cvt memory:
 *
 * cvt: char    *long_words[display_size];      Pointers to long words
 *      char    *short_words[display_size];     Pointers to short words
 * dim: char    display[display_size];          Dim | Set
 *
 *          strings associated with long and short words.
 *
 */

/*
 *      Sensitivity Label words.
 */

static  char *slcvt = NULL;
static  int   slcvtsize = 0;
static  char *sldim;

static  char *slstring = NULL;
static  int   slstringsize = 0;
static  brange_t sbounds;

/*
 *      Clearance words.
 */

static  char *clrcvt = NULL;
static  int   clrcvtsize = 0;
static  char *clrdim;

static  char *clrstring = NULL;
static  int   clrstringsize = 0;
static  brange_t cbounds;

static
int
alloc_words(char **words, const size_t size)
{
        if (*words == NULL) {
                if ((*words = malloc(size)) == NULL)
                        return (0);
        } else {
                if ((*words = realloc(*words, size)) == NULL) {
                        return (0);
                }
        }
        return (1);
}

/*
 *      build_strings - Build the static strings and dimming list for a
 *                      converted label.
 *
 *      Entry   new_string = Newly converted string.
 *              new_words_size = Size of words associated with newly converted
 *                               label.
 *              number_of_words = Number of words associated with newly
 *                                converted label.
 *              full =  1, if static words lists to be updated.
 *                      0, if only string and dimming list to be updated.
 *
 *      Exit    static_string_size = Updated if needed.
 *              static_string = Updated to new label string.
 *              static_words_size = Updated if needed.
 *              static_words = Updated to new words list, if needed.
 *              static_dimming = Updated to new dimming state.
 *              long_words = Updated to new long words pointers, if needed.
 *              short_words = Updated to new short words pointers, if needed.
 *
 *
 *      Returns 0, If unable to allocate memory.
 *              1, If successful.
 *
 *      Calls   alloc_string, alloc_words, memcpy, strcpy, strlen.
 */

static
int
build_strings(int *static_string_size, char **static_string, char *new_string,
    int *static_words_size, int new_words_size, char **static_words,
    char **static_dimming, int number_of_words, char *long_words,
    char *short_words, char *dimming_list, int full)
{
        char    **l;
        char    **s;
        char    *w;
        char    *l_w = long_words;
        char    *s_w = short_words;
        int     i;
        int     len;
        int     newsize;

        if (*static_string_size == 0) { /* Allocate string memory. */
                if ((*static_string_size = alloc_string(static_string,
                    *static_string_size, 'C')) == 0)
                        /* can't get string memory for string */
                        return (0);
        }

again:
        if (*static_string_size < (int)strlen(new_string)+1) {
                /* need longer string */
                if ((newsize = alloc_string(static_string, *static_string_size,
                    'C')) == 0)
                        /* can't get more string memory */
                        return (0);

                *static_string_size += newsize;
                goto again;
        }
        bcopy(new_string, *static_string, strlen(new_string) + 1);

        if (full) {
                if (*static_words_size < new_words_size &&
                    !alloc_words(static_words, new_words_size)) {
                        /* can't get more words memory */
                        return (0);
                } else {
                        *static_words_size = new_words_size;
                }
                /*LINTED*/
                l = (char **)*static_words;
                s = l + number_of_words;
                *static_dimming = (char *)(s + number_of_words);
                w = *static_dimming + number_of_words;
                for (i = 0; i < number_of_words; i++) {
                        *l = w;
                        (void) strcpy(w, l_w);
                        w += (len = strlen(l_w) + 1);
                        l_w += len;
                        if (*s_w == '\000') {
                                *s = NULL;
                                s_w++;
                        } else {
                                *s = w;
                                (void) strcpy(w, s_w);
                                w += (len = strlen(s_w) + 1);
                                s_w += len;
                        }

                        l++;
                        s++;
                }  /* for each word entry */
        }  /* if (full) */

        bcopy(dimming_list, *static_dimming, number_of_words);
        return (1);
}  /* build_strings */

#define bsfcall callp->param.acall.cargs.bslcvt_arg
#define bsfret callp->param.aret.rvals.bslcvt_ret
/*
 *      bslcvtfull - Convert Sensitivity Label and initialize static
 *                      information.
 *
 *      Entry   label = Sensitivity Label to convert and get dimming list.
 *                      This label should lie within the bounds or the
 *                      results may not be meaningful.
 *              bounds = Lower and upper bounds for words lists. Must be
 *                      dominated by clearance.
 *              flags = VIEW_INTERNAL, don't promote/demote admin low/high.
 *                      VIEW_EXTERNAL, promote/demote admin low/high.
 *
 *      Exit    string = ASCII coded Sensitivity Label.
 *              long_words = Array of pointers to visible long word names.
 *              short_words = Array of pointers to visible short word names.
 *              display = Array of indicators as to whether the word is present
 *                        in the converted label (CVT_SET), and/or changeable
 *                        (CVT_DIM).
 *              first_compartment = Zero based index of first compartment.
 *              display_size = Number of entries in the display/words lists.
 *
 *      Returns -1, If unable to access label encodings database, or
 *                      invalid label.
 *               0, If unable to allocate static memory.
 *               1, If successful.
 *
 *      Calls   RPC - LABELS_BSLCONVERT, STTBLEVEL, SETBSLABEL, TCLNT,
 *                      build_strings, clnt_call, clnt_perror.
 *
 *      Uses    sbounds, slrcvt, slrcvtsize, slrdim, slrstring,
 *                      slrstringsize.
 */

int
bslcvtfull(const bslabel_t *label, const blrange_t *bounds, int flags,
    char **string, char **long_words[], char **short_words[], char *display[],
    int *first_compartment, int *display_size)
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(bslcvt_call_t, 0);
        int     new_words_size;
        int     rval;

        call.callop = BSLCVT;
        bsfcall.label = *label;
        bsfcall.bounds.upper_bound = *bounds->upper_bound;
        bsfcall.bounds.lower_bound = *bounds->lower_bound;
        bsfcall.flags = LABELS_FULL_CONVERT;
        set_label_view(&bsfcall.flags, flags);

        if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == NOSERVER) {
#ifdef  DEBUG
                (void) fprintf(stderr, "No label server.\n");
#endif  /* DEBUG */
                return (-1);
        } else if (rval != SUCCESS) {
                return (-1);
        } else {
                if (callp->reterr != 0)
                        return (-1);
        }

        *first_compartment = bsfret.first_comp;
        *display_size = bsfret.d_len;

        new_words_size = bsfret.l_len + bsfret.s_len + bsfret.d_len +
            (2 * sizeof (char *)) * bsfret.d_len;

        if (build_strings(&slstringsize, &slstring, &bsfret.buf[bsfret.string],
            &slcvtsize, new_words_size, &slcvt, &sldim, bsfret.d_len,
            &bsfret.buf[bsfret.lwords], &bsfret.buf[bsfret.swords],
            &bsfret.buf[bsfret.dim], 1) != 1) {
                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (0);
        }

        /* save for bslcvt call */
        sbounds.upper_bound = *bounds->upper_bound;
        sbounds.lower_bound = *bounds->lower_bound;

        *string = slstring;
        *display = sldim;
        /*LINTED*/
        *long_words = (char **)slcvt;
        /*LINTED*/
        *short_words = (char **)(slcvt + *display_size * sizeof (char *));
        if (callp != &call)
                /* release return buffer */
                (void) munmap((void *)callp, bufsize);
        return (1);
}  /* bslcvtfull */
#undef  bsfcall
#undef  bsfret

#define bsccall callp->param.acall.cargs.bslcvt_arg
#define bscret callp->param.aret.rvals.bslcvt_ret
/*
 *      bslcvt - Convert Sensitivity Label and update dimming information.
 *
 *      Entry   label = Sensitivity Label to convert and get dimming list.
 *                      This label should lie within the bounds of the
 *                      corresponding bslcvtfull call or the results may
 *                      not be meaningful.
 *              flags = VIEW_INTERNAL, don't promote/demote admin low/high.
 *                      VIEW_EXTERNAL, promote/demote admin low/high.
 *
 *      Exit    string = ASCII coded Sensitivity Label.
 *              display = Array of indicators as to whether the word is present
 *                        in the converted label (CVT_SET), and/or changeable
 *                        (CVT_DIM).
 *
 *      Returns -1, If unable to access label encodings database, or
 *                      invalid label.
 *               0, If unable to allocate static memory.
 *               1, If successful.
 *
 *      Calls   RPC - LABELS_BSLCONVERT, SETBLEVEL, SETBSLABEL, build_strings
 *                      clnt_call, clnt_perror.
 *
 *      Uses    sbounds, slrdim, slrstring.
 */

int
bslcvt(const bslabel_t *label, int flags, char **string, char *display[])
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(bslcvt_call_t, 0);
        int     rval;

        if (slcvt == NULL)
                return (-1);    /* conversion not initialized */

        call.callop = BSLCVT;
        bsccall.label = *label;
        bsccall.bounds = sbounds;       /* save from last bslcvtfull() call */
        bsccall.flags = 0;
        set_label_view(&bsccall.flags, flags);

        if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == NOSERVER) {
#ifdef  DEBUG
                (void) fprintf(stderr, "No label server.\n");
#endif  /* DEBUG */
                return (-1);
        } else if (rval != SUCCESS) {
                return (-1);
        } else {
                if (callp->reterr != 0)
                        return (-1);
        }

        if (build_strings(&slstringsize, &slstring, &bscret.buf[bscret.string],
            &slcvtsize, 0, &slcvt, &sldim, bscret.d_len,
            &bscret.buf[bscret.lwords], &bscret.buf[bscret.swords],
            &bscret.buf[bscret.dim], 0) != 1) {
                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (0);
        }

        *string = slstring;
        *display = sldim;
        if (callp != &call)
                /* release return buffer */
                (void) munmap((void *)callp, bufsize);
        return (1);
}  /* bslcvt */
#undef  bsccall
#undef  bscret

#define bcfcall callp->param.acall.cargs.bclearcvt_arg
#define bcfret callp->param.aret.rvals.bclearcvt_ret
/*
 *      bclearcvtfull - Convert Clearance and initialize static information.
 *
 *      Entry   clearance = Clearance to convert and get dimming list.
 *                          This clearance should lie within the bounds or
 *                          the results may not be meaningful.
 *              bounds = Lower and upper bounds for words lists. Must be
 *                      dominated by clearance.
 *              flags = VIEW_INTERNAL, don't promote/demote admin low/high.
 *                      VIEW_EXTERNAL, promote/demote admin low/high.
 *
 *      Exit    string = ASCII coded Clearance.
 *              long_words = Array of pointers to visible long word names.
 *              short_words = Array of pointers to visible short word names.
 *              display = Array of indicators as to whether the word is present
 *                        in the converted label (CVT_SET), and/or changeable
 *                        (CVT_DIM).
 *              first_compartment = Zero based index of first compartment.
 *              display_size = Number of entries in the display/words lists.
 *
 *      Returns -1, If unable to access label encodings database, or
 *                      invalid label.
 *               0, If unable to allocate static memory.
 *               1, If successful.
 *
 *      Calls   RPC - LABELS_BCLEARCONVERT, SETBCLEAR, SETBLEVEL, TCLNT,
 *                      build_strings, clnt_call, clnt_perror.
 *
 *      Uses    cbounds, clrcvt, clrcvtsize, clrdim, clrstring,
 *                      clrstringsize.
 */

int
bclearcvtfull(const bclear_t *clearance, const blrange_t *bounds,
    int flags, char **string, char **long_words[], char **short_words[],
    char *display[], int *first_compartment, int *display_size)
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(bclearcvt_call_t, 0);
        int     new_words_size;
        int     rval;

        call.callop = BCLEARCVT;
        bcfcall.clear = *clearance;
        bcfcall.bounds.upper_bound = *bounds->upper_bound;
        bcfcall.bounds.lower_bound = *bounds->lower_bound;
        bcfcall.flags = LABELS_FULL_CONVERT;
        set_label_view(&bcfcall.flags, flags);

        if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == NOSERVER) {
#ifdef  DEBUG
                (void) fprintf(stderr, "No label server.\n");
#endif  /* DEBUG */
                return (-1);
        } else if (rval != SUCCESS) {
                return (-1);
        } else {
                if (callp->reterr != 0)
                        return (-1);
        }

        *first_compartment = bcfret.first_comp;
        *display_size = bcfret.d_len;

        new_words_size = bcfret.l_len + bcfret.s_len + bcfret.d_len +
            (2 * sizeof (char *)) * bcfret.d_len;

        if (build_strings(&clrstringsize, &clrstring,
            &bcfret.buf[bcfret.string],
            &clrcvtsize, new_words_size, &clrcvt,
            &clrdim, bcfret.d_len,
            &bcfret.buf[bcfret.lwords], &bcfret.buf[bcfret.swords],
            &bcfret.buf[bcfret.dim], 1) != 1) {
                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (0);
        }

        /* save for bclearcvt call */
        cbounds.upper_bound = *bounds->upper_bound;
        cbounds.lower_bound = *bounds->lower_bound;

        *string = clrstring;
        *display = clrdim;
        /*LINTED*/
        *long_words = (char **)clrcvt;
        /*LINTED*/
        *short_words = (char **)(clrcvt + *display_size * sizeof (char *));
        if (callp != &call)
                /* release return buffer */
                (void) munmap((void *)callp, bufsize);
        return (1);
}  /* bclearcvtfull */
#undef  bcfcall
#undef  bcfret

#define bcccall callp->param.acall.cargs.bclearcvt_arg
#define bccret callp->param.aret.rvals.bclearcvt_ret
/*
 *      bclearcvt - Convert Clearance and update dimming inforamtion.
 *
 *      Entry   clearance = Clearance to convert and get dimming list.
 *                          This clearance should lie within the bounds of the
 *                          corresponding bclearcvtfull call or the results may
 *                          not be meaningful.
 *              flags = VIEW_INTERNAL, don't promote/demote admin low/high.
 *                      VIEW_EXTERNAL, promote/demote admin low/high.
 *
 *      Exit    string = ASCII coded Clearance.
 *              display = Array of indicators as to whether the word is present
 *                        in the converted label (CVT_SET), and/or changeable
 *                        (CVT_DIM).
 *
 *      Returns -1, If unable to access label encodings database, or
 *                      invalid label.
 *               0, If unable to allocate static memory.
 *               1, If successful.
 *
 *      Calls   RPC - LABELS_BCLEARCONVERT, SETBCLEAR, SETBLEVEL, build_strings,
 *                      clnt_call, clnt_perror.
 *
 *      Uses    cbounds, clrdim, clrstring.
 */

int
bclearcvt(const bclear_t *clearance, int flags, char **string,
    char *display[])
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(bclearcvt_call_t, 0);
        int     rval;

        if (clrcvt == NULL)
                return (-1);    /* conversion not initialized */

        call.callop = BCLEARCVT;
        bcccall.clear = *clearance;
        bcccall.bounds = cbounds;       /* save from last bslcvtfull() call */
        bcccall.flags = 0;
        set_label_view(&bcccall.flags, flags);

        if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == NOSERVER) {
#ifdef  DEBUG
                (void) fprintf(stderr, "No label server.\n");
#endif  /* DEBUG */
                return (-1);
        } else if (rval != SUCCESS) {
                return (-1);
        } else {
                if (callp->reterr != 0)
                        return (-1);
        }

        if (build_strings(&clrstringsize, &clrstring,
            &bccret.buf[bccret.string],
            &clrcvtsize, 0, &clrcvt, &clrdim, bccret.d_len,
            &bccret.buf[bccret.lwords], &bccret.buf[bccret.swords],
            &bccret.buf[bccret.dim], 0) != 1) {
                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (0);
        }

        *string = clrstring;
        *display = clrdim;
        if (callp != &call)
                /* release return buffer */
                (void) munmap((void *)callp, bufsize);
        return (1);
}  /* bclearcvt */
#undef  bcccall
#undef  bccret

#define lfret callp->param.aret.rvals.fields_ret
/*
 *      labelfields - Return names for the label fields.
 *
 *      Entry   None
 *
 *      Exit    fields = Updated.
 *
 *      Returns -1, If unable to access label encodings file, or
 *                      labels server failure.
 *               0, If unable to allocate memory.
 *               1, If successful.
 *
 *      Calls __call_labeld(LABELFIELDS).
 */

int
labelfields(struct name_fields *fields)
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(fields_call_t, 0);
        int     rval;

        call.callop = LABELFIELDS;

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

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

        /* unpack results */

        if ((fields->class_name = strdup(&lfret.buf[lfret.classi])) == NULL) {
                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (0);
        }
        if ((fields->comps_name = strdup(&lfret.buf[lfret.compsi])) == NULL) {
                free(fields->class_name);
                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (0);
        }
        if ((fields->marks_name = strdup(&lfret.buf[lfret.marksi])) == NULL) {
                free(fields->class_name);
                free(fields->comps_name);
                if (callp != &call)
                        /* release return buffer */
                        (void) munmap((void *)callp, bufsize);
                return (0);
        }

        if (callp != &call)
                /* release return buffer */
                (void) munmap((void *)callp, bufsize);
        return (rval);
}  /* labelfields */
#undef  lfret

#define udret callp->param.aret.rvals.udefs_ret
/*
 *      userdefs - Get default user Sensitivity Label and/or Clearance.
 *
 *      Entry   None.
 *
 *      Exit    sl = default user Sensitivity Label.
 *              clear = default user Clearance.
 *
 *      Returns -1, If unable to access label encodings file, or
 *                      labels server failure.
 *              1, If successful.
 *
 *      Calls   __call_labeld(UDEFS).
 */

int
userdefs(bslabel_t *sl, bclear_t *clear)
{
        labeld_data_t   call;
        labeld_data_t   *callp = &call;
        size_t  bufsize = sizeof (labeld_data_t);
        size_t  datasize = CALL_SIZE(udefs_call_t, 0);
        int     rval;

        call.callop = UDEFS;

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

                return (-1);
        }

        if (sl != NULL)
                *sl = udret.sl;
        if (clear != NULL)
                *clear = udret.clear;
        return (rval);
}  /* userdefs */
#undef  udret