xref: /illumos-gate/usr/src/lib/libtsol/common/btos.c (revision e3ae4b35c024af1196582063ecee3ab79367227d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  *      Binary label to label string translations.
28  */
29 
30 #include <locale.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <wchar.h>
36 
37 #include <sys/mman.h>
38 
39 #include <tsol/label.h>
40 
41 #include "clnt.h"
42 #include "labeld.h"
43 #include <sys/tsol/label_macro.h>
44 
45 #if	!defined(TEXT_DOMAIN)		/* should be defined by Makefiles */
46 #define	TEXT_DOMAIN "SYS_TEST"
47 #endif	/* TEXT_DOMAIN */
48 
49 static bslabel_t slow;	/* static admin_low high sensitivity label */
50 static bslabel_t shigh;	/* static admin_high sensitivity label */
51 static bclear_t clrlow, clrhigh; /* static admin_low and admin_high Clearance */
52 
53 static char	*sstring;	/* return string for sb*tos */
54 static size_t	ssize;		/* current size of return string */
55 
56 static int
57 return_string(char **string, int str_len, char *val)
58 {
59 	char	*cpyptr;
60 	size_t	val_len = strlen(val) + 1;
61 
62 	if (*string == NULL) {
63 		if ((*string = malloc(val_len)) == NULL)
64 			return (0);
65 	} else if (val_len > str_len) {
66 		**string = '\0';
67 		return (0);
68 	}
69 
70 	cpyptr = *string;
71 	bcopy(val, cpyptr, val_len);
72 
73 	return (val_len);
74 }
75 
76 void
77 set_label_view(uint_t *callflags, uint_t flags)
78 {
79 	if (flags&VIEW_INTERNAL) {
80 		*callflags |= LABELS_VIEW_INTERNAL;
81 	} else if (flags&VIEW_EXTERNAL) {
82 		*callflags |= LABELS_VIEW_EXTERNAL;
83 	}
84 }
85 
86 int
87 alloc_string(char **string, size_t size, char val)
88 {
89 	if (*string == NULL) {
90 		if ((*string = malloc(ALLOC_CHUNK)) == NULL)
91 			return (0);
92 	} else {
93 		if ((*string = realloc(*string, size + ALLOC_CHUNK)) == NULL) {
94 			**string = val;
95 			return (0);
96 		}
97 	}
98 	**string = val;
99 	return (ALLOC_CHUNK);
100 }
101 
102 #define	slcall callp->param.acall.cargs.bsltos_arg
103 #define	slret callp->param.aret.rvals.bsltos_ret
104 /*
105  *	bsltos - Convert Binary Sensitivity Label to Sensitivity Label string.
106  *
107  *	Entry	label = Binary Sensitivity Label to be converted.
108  *		string = NULL ((char *) 0), if memory to be allocated,
109  *			 otherwise, pointer to preallocated memory.
110  *		str_len = Length of preallocated memory, else ignored.
111  *		flags = Logical sum of:
112  *				LONG_CLASSIFICATION or SHORT_CLASSIFICATION,
113  *				LONG_WORDS or SHORT_WORDS,
114  *				VIEW_INTERNAL or VIEW_EXTERNAL, and
115  *				NO_CLASSIFICATION.
116  *			LONG_CLASSIFICATION, use long classification names.
117  *			SHORT_CLASSIFICATION, use short classification
118  *						names (default).
119  *			NO_CLASSIFICATION, don't translate classification.
120  *			LONG_WORDS, use the long form of words (default).
121  *			SHORTWORDS, use the short form of words where available.
122  *			VIEW_INTERNAL, don't promote/demote admin low/high.
123  *			VIEW_EXTERNAL, promote/demote admin low/high.
124  *
125  *	Exit	string = Sensitivity Label string, or empty string if
126  *			 not enough preallocated memory.
127  *
128  *	Returns	-1, If unable to access label encodings database.
129  *		 0, If unable to allocate string,
130  *			or allocated string to short
131  *			(and **string = '\0').
132  *		length (including null) of Sensitivity Label string,
133  *			If successful.
134  *
135  *	Calls	RPC - LABELS_BSLTOS, BCLHIGH, BCLLOW, BCLTOSL, BLEQUAL,
136  *			BLTYPE, SETBSLABEL, UCLNT, memcpy, clnt_call,
137  *			clnt_perror, malloc, strcat, strlen.
138  *
139  *	Uses	ADMIN_HIGH, ADMIN_LOW, shigh, slow.
140  */
141 
142 ssize_t
143 bsltos(const bslabel_t *label, char **string, size_t str_len,
144     int flags)
145 {
146 	labeld_data_t	call;
147 	labeld_data_t	*callp = &call;
148 	size_t	bufsize = sizeof (labeld_data_t);
149 	size_t	datasize = CALL_SIZE(bsltos_call_t, 0);
150 	int	rval;
151 
152 	if (!BLTYPE(label, SUN_SL_ID)) {
153 		return (-1);
154 	}
155 
156 	call.callop = BSLTOS;
157 	slcall.label = *label;
158 	slcall.flags = (flags&NO_CLASSIFICATION) ? LABELS_NO_CLASS : 0;
159 	slcall.flags |= (flags&SHORT_CLASSIFICATION ||
160 	    !(flags&LONG_CLASSIFICATION)) ? LABELS_SHORT_CLASS : 0;
161 	slcall.flags |= (flags&SHORT_WORDS && !(flags&LONG_WORDS)) ?
162 	    LABELS_SHORT_WORDS : 0;
163 	set_label_view(&slcall.flags, flags);
164 
165 	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == SUCCESS) {
166 
167 		if (callp->reterr != 0)
168 			return (-1);
169 
170 		/* unpack Sensitivity Label */
171 
172 		rval = return_string(string, str_len, slret.slabel);
173 
174 		if (callp != &call)
175 			(void) munmap((void *)callp, bufsize);
176 		return (rval);
177 	} else if (rval == NOSERVER) {
178 		/* server not present */
179 		/* special case admin_high and admin_low */
180 
181 		if (!BLTYPE(&slow, SUN_SL_ID)) {
182 			/* initialize static labels */
183 
184 			BSLLOW(&slow);
185 			BSLHIGH(&shigh);
186 		}
187 
188 		if (BLEQUAL(label, &slow)) {
189 			return (return_string(string, str_len, ADMIN_LOW));
190 		} else if (BLEQUAL(label, &shigh)) {
191 			return (return_string(string, str_len, ADMIN_HIGH));
192 		}
193 	}
194 	return (-1);
195 }  /* bsltos */
196 #undef	slcall
197 #undef	slret
198 
199 #define	clrcall callp->param.acall.cargs.bcleartos_arg
200 #define	clrret callp->param.aret.rvals.bcleartos_ret
201 /*
202  *	bcleartos - Convert Binary Clearance to Clearance string.
203  *
204  *	Entry	clearance = Binary Clearance to be converted.
205  *		string = NULL ((char *) 0), if memory to be allocated,
206  *			 otherwise, pointer to preallocated memory.
207  *		str_len = Length of preallocated memory, else ignored.
208  *		flags = Logical sum of:
209  *				LONG_CLASSIFICATION or SHORT_CLASSIFICATION,
210  *				LONG_WORDS or SHORT_WORDS,
211  *				VIEW_INTERNAL or VIEW_EXTERNAL.
212  *			LONG_CLASSIFICATION, use long classification names.
213  *			SHORT_CLASSIFICATION, use short classification
214  *						names (default).
215  *			LONG_WORDS, use the long form of words (default).
216  *			SHORTWORDS, use the short form of words where available.
217  *			VIEW_INTERNAL, don't promote/demote admin low/high.
218  *			VIEW_EXTERNAL, promote/demote admin low/high.
219  *
220  *	Exit	string = Clearance string, or empty string if not
221  *			enough preallocated memory.
222  *
223  *	Returns	-1, If unable to access label encodings database.
224  *		 0, If unable to allocate string,
225  *			or allocated string to short
226  *			(and **string = '\0').
227  *		length (including null) of Clearance string,
228  *			If successful.
229  *
230  *	Calls	RPC - LABELS_BSLTOS, BCLHIGH, BCLLOW, BCLTOSL, BLEQUAL,
231  *			BLTYPE, SETBSLABEL, UCLNT, memcpy, clnt_call,
232  *			clnt_perror, malloc, strcat, strlen.
233  *
234  *	Uses	ADMIN_HIGH, ADMIN_LOW, clrhigh, clrlow.
235  */
236 
237 ssize_t
238 bcleartos(const bclear_t *clearance, char **string, size_t str_len,
239     int flags)
240 {
241 	labeld_data_t	call;
242 	labeld_data_t	*callp = &call;
243 	size_t	bufsize = sizeof (labeld_data_t);
244 	size_t	datasize = CALL_SIZE(bcleartos_call_t, 0);
245 	int	rval;
246 
247 	if (!BLTYPE(clearance, SUN_CLR_ID)) {
248 		return (-1);
249 	}
250 
251 	call.callop = BCLEARTOS;
252 	clrcall.clear = *clearance;
253 	clrcall.flags = (flags&SHORT_CLASSIFICATION ||
254 	    !(flags&LONG_CLASSIFICATION)) ? LABELS_SHORT_CLASS : 0;
255 	clrcall.flags |= (flags&SHORT_WORDS && !(flags&LONG_WORDS)) ?
256 	    LABELS_SHORT_WORDS : 0;
257 	set_label_view(&clrcall.flags, flags);
258 
259 	if ((rval = __call_labeld(&callp, &bufsize, &datasize)) == SUCCESS) {
260 
261 		if (callp->reterr != 0)
262 			return (-1);
263 
264 		/* unpack Clearance */
265 
266 		rval = return_string(string, str_len, clrret.cslabel);
267 
268 		if (callp != &call)
269 			/* release return buffer */
270 			(void) munmap((void *)callp, bufsize);
271 		return (rval);
272 	} else if (rval == NOSERVER) {
273 		/* server not present */
274 		/* special case admin_high and admin_low */
275 
276 		if (!BLTYPE(&clrlow, SUN_CLR_ID)) {
277 			/* initialize static labels */
278 
279 			BCLEARLOW(&clrlow);
280 			BCLEARHIGH(&clrhigh);
281 		}
282 		if (BLEQUAL(clearance, &clrlow)) {
283 			return (return_string(string, str_len, ADMIN_LOW));
284 		} else if (BLEQUAL(clearance, &clrhigh)) {
285 			return (return_string(string, str_len, ADMIN_HIGH));
286 		}
287 	}
288 	return (-1);
289 }  /* bcleartos */
290 #undef	clrcall
291 #undef	clrret
292 
293 /*
294  *	sbsltos - Convert Sensitivity Label to canonical clipped form.
295  *
296  *	Entry	label = Sensitivity Label to be converted.
297  *		len = Maximum length of translated string, excluding NULL.
298  *		      0, full string.
299  *		sstring = address of string to translate into.
300  *		ssize = size of memory currently allocated to sstring.
301  *
302  *	Exit	sstring = Newly translated string.
303  *		ssize = Updated if more memory pre-allocated.
304  *
305  *	Returns	NULL, If error, len too small, unable to translate, or get
306  *		      memory for string.
307  *		Address of string containing converted value.
308  *
309  *	Calls	alloc_string, bsltos, strcpy.
310  *
311  *	Uses	ssize, sstring.
312  */
313 
314 char *
315 sbsltos(const bslabel_t *label, size_t len)
316 {
317 	ssize_t	slen;		/* length including NULL */
318 	wchar_t *wstring;
319 	int	wccount;
320 
321 	if (ssize == 0) {
322 		/* Allocate string memory. */
323 		if ((ssize = alloc_string(&sstring, ssize, 's')) == 0)
324 			/* can't get initial memory for string */
325 			return (NULL);
326 	}
327 
328 again:
329 	if ((slen = bsltos(label, &sstring, ssize,
330 	    (SHORT_CLASSIFICATION | LONG_WORDS))) <= 0) {
331 		/* error in translation */
332 		if (slen == 0) {
333 			if (*sstring == '\0') {
334 				int newsize;
335 				/* sstring not long enough */
336 				if ((newsize = alloc_string(&sstring, ssize,
337 				    's')) == 0) {
338 					/* Can't get more memory */
339 					return (NULL);
340 				}
341 				ssize += newsize;
342 				goto again;
343 			}
344 		}
345 		return (NULL);
346 	}
347 	if (len == 0) {
348 		return (sstring);
349 	} else if (len < MIN_SL_LEN) {
350 		return (NULL);
351 	}
352 	if ((wstring = malloc(slen * sizeof (wchar_t))) == NULL)
353 		return (NULL);
354 	if ((wccount = mbstowcs(wstring, sstring, slen - 1)) == -1) {
355 		free(wstring);
356 		return (NULL);
357 	}
358 	if (wccount > len) {
359 		wchar_t *clipp = wstring + (len - 2);
360 
361 		/* Adjust string size to desired length */
362 
363 		clipp[0] = L'<';
364 		clipp[1] = L'-';
365 		clipp[2] = L'\0';
366 
367 		while (wcstombs(NULL, wstring, 0) >= ssize) {
368 			int newsize;
369 
370 			/* sstring not long enough */
371 			if ((newsize = alloc_string(&sstring, ssize, 's')) ==
372 			    0) {
373 				/* Can't get more memory */
374 				return (NULL);
375 			}
376 			ssize += newsize;
377 		}
378 
379 		if ((wccount = wcstombs(sstring, wstring, ssize)) == -1) {
380 			free(wstring);
381 			return (NULL);
382 		}
383 	}
384 	free(wstring);
385 
386 	return (sstring);
387 }  /* sbsltos */
388 
389 /*
390  *	sbcleartos - Convert Clearance to canonical clipped form.
391  *
392  *	Entry	clearance = Clearance to be converted.
393  *		len = Maximum length of translated string, excluding NULL.
394  *		      0, full string.
395  *		sstring = address of string to translate into.
396  *		ssize = size of memory currently allocated to sstring.
397  *
398  *	Exit	sstring = Newly translated string.
399  *		ssize = Updated if more memory pre-allocated.
400  *
401  *	Returns	NULL, If error, len too small, unable to translate, or get
402  *		      memory for string.
403  *		Address of string containing converted value.
404  *
405  *	Calls	alloc_string, bcleartos, strcpy.
406  *
407  *	Uses	ssize, sstring.
408  */
409 
410 char *
411 sbcleartos(const bclear_t *clearance, size_t len)
412 {
413 	ssize_t	slen;		/* length including NULL */
414 	wchar_t *wstring;
415 	int	wccount;
416 
417 	if (ssize == 0) {
418 		/* Allocate string memory. */
419 		if ((ssize = alloc_string(&sstring, ssize, 'c')) == 0)
420 			/* can't get initial memory for string */
421 			return (NULL);
422 	}
423 
424 again:
425 	if ((slen = bcleartos(clearance, &sstring, ssize,
426 	    (SHORT_CLASSIFICATION | LONG_WORDS))) <= 0) {
427 		/* error in translation */
428 		if (slen == 0) {
429 			if (*sstring == '\0') {
430 				int newsize;
431 				/* sstring not long enough */
432 				if ((newsize = alloc_string(&sstring, ssize,
433 				    'c')) == 0) {
434 					/* Can't get more memory */
435 					return (NULL);
436 				}
437 				ssize += newsize;
438 				goto again;
439 			}
440 		}
441 		return (NULL);
442 	}
443 	if (len == 0) {
444 		return (sstring);
445 	} else if (len < MIN_CLR_LEN) {
446 		return (NULL);
447 	}
448 	if ((wstring = malloc(slen * sizeof (wchar_t))) == NULL)
449 		return (NULL);
450 	if ((wccount = mbstowcs(wstring, sstring, slen - 1)) == -1) {
451 		free(wstring);
452 		return (NULL);
453 	}
454 	if (wccount > len) {
455 		wchar_t *clipp = wstring + (len - 2);
456 
457 		/* Adjust string size to desired length */
458 
459 		clipp[0] = L'<';
460 		clipp[1] = L'-';
461 		clipp[2] = L'\0';
462 
463 		while (wcstombs(NULL, wstring, 0) >= ssize) {
464 			int newsize;
465 
466 			/* sstring not long enough */
467 			if ((newsize = alloc_string(&sstring, ssize, 'c')) ==
468 			    0) {
469 				/* Can't get more memory */
470 				free(wstring);
471 				return (NULL);
472 			}
473 			ssize += newsize;
474 		}
475 		if ((wccount = wcstombs(sstring, wstring, ssize)) == -1) {
476 			free(wstring);
477 			return (NULL);
478 		}
479 	}
480 	free(wstring);
481 
482 	return (sstring);
483 }  /* sbcleartos */
484