| /* |
| * 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. |
| */ |
| |
| #if !defined(_KERNEL) |
| #include <errno.h> |
| #endif /* !defined(_KERNEL) */ |
| |
| #include <sys/types.h> |
| #include <sys/mman.h> |
| #include <sys/tsol/label_macro.h> |
| |
| #include <sys/tsol/label.h> |
| |
| #if !defined(_KERNEL) |
| #include "clnt.h" |
| #include "labeld.h" |
| #endif /* !defined(_KERNEL) */ |
| |
| #if defined(_KERNEL) |
| #include <sys/systm.h> |
| #include <sys/sunddi.h> |
| #else |
| #include <stdlib.h> |
| #include <string.h> |
| #include <ctype.h> |
| #endif |
| |
| |
| |
| static _mac_label_impl_t low; |
| static _mac_label_impl_t high; |
| static int inited = 0; |
| |
| #if defined(_KERNEL) |
| #define malloc(l) kmem_alloc(l, KM_NOSLEEP) |
| #define freeit(a, l) kmem_free(a, l) |
| #else /* defined(_KERNEL) */ |
| #define freeit(a, l) free(a) |
| #endif /* defined(_KERNEL) */ |
| |
| /* 0x + Classification + '-' + ll + '-' + Compartments + end of string */ |
| #define _HEX_SIZE 2+(sizeof (Classification_t)*2)+4+\ |
| (sizeof (Compartments_t)*2)+1 |
| |
| /* 0x + Classification + '-' + ll + '-' + end of string */ |
| #define _MIN_HEX (2 + (sizeof (Classification_t)*2) + 4 + 1) |
| |
| static char digits[] = "0123456789abcdef"; |
| |
| #define HEX(h, i, l, s) \ |
| for (; i < s; /* */) {\ |
| h[i++] = digits[(unsigned int)(*l >> 4)];\ |
| h[i++] = digits[(unsigned int)(*l++&0xF)]; } |
| |
| static int |
| __hex(char **s, const m_label_t *l) |
| { |
| char *hex; |
| int i = 0; |
| uchar_t *hl; |
| int hex_len; |
| uchar_t *len; |
| |
| hl = (uchar_t *)&(((_mac_label_impl_t *)l)->_c_len); |
| len = hl; |
| |
| if (*len == 0) { |
| /* old binary label */ |
| hex_len = _HEX_SIZE; |
| } else { |
| hex_len = _MIN_HEX + (*len * sizeof (uint32_t) * 2); |
| } |
| |
| if ((hex = malloc(hex_len)) == NULL) { |
| return (-1); |
| } |
| |
| /* header */ |
| |
| hex[i++] = '0'; |
| hex[i++] = 'x'; |
| |
| /* classification */ |
| |
| hl++; /* start at classification */ |
| HEX(hex, i, hl, 6); |
| |
| /* Add compartments length */ |
| hex[i++] = '-'; |
| HEX(hex, i, len, 9); |
| hex[i++] = '-'; |
| |
| /* compartments */ |
| HEX(hex, i, hl, hex_len-1); |
| hex[i] = '\0'; |
| |
| /* truncate trailing zeros */ |
| |
| while (hex[i-1] == '0' && hex[i-2] == '0') { |
| i -= 2; |
| } |
| hex[i] = '\0'; |
| |
| if ((*s = strdup(hex)) == NULL) { |
| freeit(hex, hex_len); |
| return (-1); |
| } |
| |
| freeit(hex, hex_len); |
| return (0); |
| |
| } |
| |
| int |
| l_to_str_internal(const m_label_t *l, char **s) |
| { |
| if (inited == 0) { |
| inited = 1; |
| _BSLLOW(&low); |
| _BSLHIGH(&high); |
| } |
| |
| if (!(_MTYPE(l, SUN_MAC_ID) || _MTYPE(l, SUN_UCLR_ID))) { |
| #if !defined(_KERNEL) |
| errno = EINVAL; |
| #endif /* !defined(_KERNEL) */ |
| *s = NULL; |
| return (-1); |
| } |
| if (_MEQUAL(&low, (_mac_label_impl_t *)l)) { |
| if ((*s = strdup(ADMIN_LOW)) == NULL) { |
| return (-1); |
| } |
| return (0); |
| } |
| if (_MEQUAL(&high, (_mac_label_impl_t *)l)) { |
| if ((*s = strdup(ADMIN_HIGH)) == NULL) { |
| return (-1); |
| } |
| return (0); |
| } |
| |
| return (__hex(s, l)); |
| } |
| |
| #if !defined(_KERNEL) |
| /* |
| * label_to_str -- convert a label to the requested type of string. |
| * |
| * Entry l = label to convert; |
| * t = type of conversion; |
| * f = flags for conversion type; |
| * |
| * Exit *s = allocated converted string; |
| * Caller must call free() to free. |
| * |
| * Returns 0, success. |
| * -1, error, errno set; *s = NULL. |
| * |
| * Calls labeld |
| */ |
| |
| int |
| label_to_str(const m_label_t *l, char **s, const m_label_str_t t, uint_t f) |
| { |
| labeld_data_t call; |
| labeld_data_t *callp = &call; |
| size_t bufsize = sizeof (labeld_data_t); |
| size_t datasize; |
| int err; |
| int string_start = 0; |
| |
| if (inited == 0) { |
| inited = 1; |
| _BSLLOW(&low); |
| _BSLHIGH(&high); |
| } |
| |
| #define lscall callp->param.acall.cargs.ls_arg |
| #define lsret callp->param.aret.rvals.ls_ret |
| switch (t) { |
| case M_LABEL: |
| call.callop = LTOS; |
| lscall.label = *l; |
| lscall.flags = f; |
| datasize = CALL_SIZE(ls_call_t, 0); |
| if ((err = __call_labeld(&callp, &bufsize, &datasize)) == |
| SUCCESS) { |
| if (callp->reterr != 0) { |
| errno = EINVAL; |
| *s = NULL; |
| return (-1); |
| } |
| *s = strdup(lsret.buf); |
| if (callp != &call) { |
| /* release returned buffer */ |
| (void) munmap((void *)callp, bufsize); |
| } |
| if (*s == NULL) { |
| return (-1); |
| } |
| return (0); |
| } |
| switch (err) { |
| case NOSERVER: |
| /* server not present */ |
| /* special case admin_low and admin_high */ |
| |
| if (_MEQUAL(&low, (_mac_label_impl_t *)l)) { |
| if ((*s = strdup(ADMIN_LOW)) == NULL) { |
| return (-1); |
| } |
| return (0); |
| } else if (_MEQUAL(&high, (_mac_label_impl_t *)l)) { |
| if ((*s = strdup(ADMIN_HIGH)) == NULL) { |
| return (-1); |
| } |
| return (0); |
| } |
| errno = ENOTSUP; |
| break; |
| default: |
| errno = EINVAL; |
| break; |
| } |
| *s = NULL; |
| return (-1); |
| #undef lscall |
| #undef lsret |
| |
| case M_INTERNAL: { |
| return (l_to_str_internal(l, s)); |
| } |
| |
| #define ccall callp->param.acall.cargs.color_arg |
| #define cret callp->param.aret.rvals.color_ret |
| case M_COLOR: |
| datasize = CALL_SIZE(color_call_t, 0); |
| call.callop = BLTOCOLOR; |
| ccall.label = *l; |
| |
| if (__call_labeld(&callp, &bufsize, &datasize) == SUCCESS) { |
| if (callp->reterr != 0) { |
| errno = EINVAL; |
| *s = NULL; |
| return (-1); |
| } |
| *s = strdup(cret.color); |
| if (callp != &call) { |
| /* release returned buffer */ |
| (void) munmap((void *)callp, bufsize); |
| } |
| if (*s == NULL) { |
| return (-1); |
| } |
| return (0); |
| } else { |
| errno = ENOTSUP; |
| *s = NULL; |
| return (-1); |
| } |
| #undef ccall |
| #undef cret |
| |
| #define prcall callp->param.acall.cargs.pr_arg |
| #define prret callp->param.aret.rvals.pr_ret |
| case PRINTER_TOP_BOTTOM: |
| call.callop = PR_TOP; |
| break; |
| case PRINTER_LABEL: |
| call.callop = PR_LABEL; |
| break; |
| case PRINTER_CAVEATS: |
| call.callop = PR_CAVEATS; |
| string_start = 1; /* compensate for leading space */ |
| break; |
| case PRINTER_CHANNELS: |
| call.callop = PR_CHANNELS; |
| string_start = 1; /* compensate for leading space */ |
| break; |
| default: |
| errno = EINVAL; |
| *s = NULL; |
| return (-1); |
| } |
| /* do the common printer calls */ |
| datasize = CALL_SIZE(pr_call_t, 0); |
| prcall.label = *l; |
| prcall.flags = f; |
| if (__call_labeld(&callp, &bufsize, &datasize) == SUCCESS) { |
| if (callp->reterr != 0) { |
| errno = EINVAL; |
| *s = NULL; |
| return (-1); |
| } |
| *s = strdup(&prret.buf[string_start]); |
| if (callp != &call) { |
| /* release returned buffer */ |
| (void) munmap((void *)callp, bufsize); |
| } |
| if (*s == NULL) { |
| return (-1); |
| } |
| return (0); |
| } else { |
| errno = ENOTSUP; |
| *s = NULL; |
| return (-1); |
| } |
| #undef prcall |
| #undef prret |
| } |
| #endif /* !defined(_KERNEL) */ |