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