xref: /aosp_15_r20/external/selinux/mcstrans/src/mcstrans.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker 
2*2d543d20SAndroid Build Coastguard Worker /* Copyright (c) 2008-2009 Nall Design Works
3*2d543d20SAndroid Build Coastguard Worker    Copyright 2006 Trusted Computer Solutions, Inc. */
4*2d543d20SAndroid Build Coastguard Worker 
5*2d543d20SAndroid Build Coastguard Worker /*
6*2d543d20SAndroid Build Coastguard Worker  Exported Interface
7*2d543d20SAndroid Build Coastguard Worker 
8*2d543d20SAndroid Build Coastguard Worker  int init_translations(void);
9*2d543d20SAndroid Build Coastguard Worker  void finish_context_translations(void);
10*2d543d20SAndroid Build Coastguard Worker  int trans_context(const char *, char **);
11*2d543d20SAndroid Build Coastguard Worker  int untrans_context(const char *, char **);
12*2d543d20SAndroid Build Coastguard Worker 
13*2d543d20SAndroid Build Coastguard Worker */
14*2d543d20SAndroid Build Coastguard Worker 
15*2d543d20SAndroid Build Coastguard Worker #include <math.h>
16*2d543d20SAndroid Build Coastguard Worker #include <glob.h>
17*2d543d20SAndroid Build Coastguard Worker #include <values.h>
18*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
19*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
20*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
21*2d543d20SAndroid Build Coastguard Worker #include <string.h>
22*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
23*2d543d20SAndroid Build Coastguard Worker #include <stdio_ext.h>
24*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
25*2d543d20SAndroid Build Coastguard Worker #include <selinux/selinux.h>
26*2d543d20SAndroid Build Coastguard Worker #include <selinux/context.h>
27*2d543d20SAndroid Build Coastguard Worker #include <syslog.h>
28*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
29*2d543d20SAndroid Build Coastguard Worker #include <pcre2.h>
30*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
31*2d543d20SAndroid Build Coastguard Worker #include <time.h>
32*2d543d20SAndroid Build Coastguard Worker #include <sys/time.h>
33*2d543d20SAndroid Build Coastguard Worker 
34*2d543d20SAndroid Build Coastguard Worker 
35*2d543d20SAndroid Build Coastguard Worker #include "mls_level.h"
36*2d543d20SAndroid Build Coastguard Worker #include "mcstrans.h"
37*2d543d20SAndroid Build Coastguard Worker 
38*2d543d20SAndroid Build Coastguard Worker #define N_BUCKETS 1453
39*2d543d20SAndroid Build Coastguard Worker 
40*2d543d20SAndroid Build Coastguard Worker #define log_error(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
41*2d543d20SAndroid Build Coastguard Worker 
42*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
43*2d543d20SAndroid Build Coastguard Worker #define log_debug(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
44*2d543d20SAndroid Build Coastguard Worker #else
45*2d543d20SAndroid Build Coastguard Worker #define log_debug(fmt, ...) do {} while (0)
46*2d543d20SAndroid Build Coastguard Worker #endif
47*2d543d20SAndroid Build Coastguard Worker 
48*2d543d20SAndroid Build Coastguard Worker static unsigned int maxbit=0;
49*2d543d20SAndroid Build Coastguard Worker 
50*2d543d20SAndroid Build Coastguard Worker /* Define data structures */
51*2d543d20SAndroid Build Coastguard Worker typedef struct context_map {
52*2d543d20SAndroid Build Coastguard Worker 	char *raw;
53*2d543d20SAndroid Build Coastguard Worker 	char *trans;
54*2d543d20SAndroid Build Coastguard Worker } context_map_t;
55*2d543d20SAndroid Build Coastguard Worker 
56*2d543d20SAndroid Build Coastguard Worker typedef struct context_map_node {
57*2d543d20SAndroid Build Coastguard Worker 	char *key;
58*2d543d20SAndroid Build Coastguard Worker 	context_map_t *map;
59*2d543d20SAndroid Build Coastguard Worker 	struct context_map_node *next;
60*2d543d20SAndroid Build Coastguard Worker } context_map_node_t;
61*2d543d20SAndroid Build Coastguard Worker 
62*2d543d20SAndroid Build Coastguard Worker typedef struct affix {
63*2d543d20SAndroid Build Coastguard Worker 	char *text;
64*2d543d20SAndroid Build Coastguard Worker 	struct affix *next;
65*2d543d20SAndroid Build Coastguard Worker } affix_t;
66*2d543d20SAndroid Build Coastguard Worker 
67*2d543d20SAndroid Build Coastguard Worker typedef struct word {
68*2d543d20SAndroid Build Coastguard Worker 	char *text;
69*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t cat;
70*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t normal;
71*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t inverse;
72*2d543d20SAndroid Build Coastguard Worker 	struct word *next;
73*2d543d20SAndroid Build Coastguard Worker } word_t;
74*2d543d20SAndroid Build Coastguard Worker 
75*2d543d20SAndroid Build Coastguard Worker typedef struct word_group {
76*2d543d20SAndroid Build Coastguard Worker 	char *name;
77*2d543d20SAndroid Build Coastguard Worker 	char *whitespace;
78*2d543d20SAndroid Build Coastguard Worker 	char *join;
79*2d543d20SAndroid Build Coastguard Worker 
80*2d543d20SAndroid Build Coastguard Worker 	affix_t *prefixes;
81*2d543d20SAndroid Build Coastguard Worker 	affix_t *suffixes;
82*2d543d20SAndroid Build Coastguard Worker 	word_t *words;
83*2d543d20SAndroid Build Coastguard Worker 
84*2d543d20SAndroid Build Coastguard Worker 	pcre2_code *prefix_regexp;
85*2d543d20SAndroid Build Coastguard Worker 	pcre2_code *word_regexp;
86*2d543d20SAndroid Build Coastguard Worker 	pcre2_code *suffix_regexp;
87*2d543d20SAndroid Build Coastguard Worker 
88*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t def;
89*2d543d20SAndroid Build Coastguard Worker 
90*2d543d20SAndroid Build Coastguard Worker 	word_t **sword;
91*2d543d20SAndroid Build Coastguard Worker 	unsigned int sword_len;
92*2d543d20SAndroid Build Coastguard Worker 
93*2d543d20SAndroid Build Coastguard Worker 	struct word_group *next;
94*2d543d20SAndroid Build Coastguard Worker } word_group_t;
95*2d543d20SAndroid Build Coastguard Worker 
96*2d543d20SAndroid Build Coastguard Worker typedef struct base_classification {
97*2d543d20SAndroid Build Coastguard Worker 	char *trans;
98*2d543d20SAndroid Build Coastguard Worker 	mls_level_t *level;
99*2d543d20SAndroid Build Coastguard Worker 	struct base_classification *next;
100*2d543d20SAndroid Build Coastguard Worker } base_classification_t;
101*2d543d20SAndroid Build Coastguard Worker 
102*2d543d20SAndroid Build Coastguard Worker typedef struct domain {
103*2d543d20SAndroid Build Coastguard Worker 	char *name;
104*2d543d20SAndroid Build Coastguard Worker 
105*2d543d20SAndroid Build Coastguard Worker 	context_map_node_t *raw_to_trans[N_BUCKETS];
106*2d543d20SAndroid Build Coastguard Worker 	context_map_node_t *trans_to_raw[N_BUCKETS];
107*2d543d20SAndroid Build Coastguard Worker 
108*2d543d20SAndroid Build Coastguard Worker 	base_classification_t *base_classifications;
109*2d543d20SAndroid Build Coastguard Worker 	word_group_t *groups;
110*2d543d20SAndroid Build Coastguard Worker 
111*2d543d20SAndroid Build Coastguard Worker 	pcre2_code *base_classification_regexp;
112*2d543d20SAndroid Build Coastguard Worker 	struct domain *next;
113*2d543d20SAndroid Build Coastguard Worker } domain_t;
114*2d543d20SAndroid Build Coastguard Worker 
115*2d543d20SAndroid Build Coastguard Worker static domain_t *domains;
116*2d543d20SAndroid Build Coastguard Worker 
117*2d543d20SAndroid Build Coastguard Worker typedef struct sens_constraint {
118*2d543d20SAndroid Build Coastguard Worker 	char op;
119*2d543d20SAndroid Build Coastguard Worker 	char *text;
120*2d543d20SAndroid Build Coastguard Worker 	unsigned int sens;
121*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t cat;
122*2d543d20SAndroid Build Coastguard Worker 	struct sens_constraint *next;
123*2d543d20SAndroid Build Coastguard Worker } sens_constraint_t;
124*2d543d20SAndroid Build Coastguard Worker 
125*2d543d20SAndroid Build Coastguard Worker static sens_constraint_t *sens_constraints;
126*2d543d20SAndroid Build Coastguard Worker 
127*2d543d20SAndroid Build Coastguard Worker typedef struct cat_constraint {
128*2d543d20SAndroid Build Coastguard Worker 	char op;
129*2d543d20SAndroid Build Coastguard Worker 	char *text;
130*2d543d20SAndroid Build Coastguard Worker 	int nbits;
131*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t mask;
132*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t cat;
133*2d543d20SAndroid Build Coastguard Worker 	struct cat_constraint *next;
134*2d543d20SAndroid Build Coastguard Worker } cat_constraint_t;
135*2d543d20SAndroid Build Coastguard Worker 
136*2d543d20SAndroid Build Coastguard Worker static cat_constraint_t *cat_constraints;
137*2d543d20SAndroid Build Coastguard Worker 
138*2d543d20SAndroid Build Coastguard Worker static unsigned int
hash(const char * str)139*2d543d20SAndroid Build Coastguard Worker hash(const char *str) {
140*2d543d20SAndroid Build Coastguard Worker 	unsigned int hash = 5381;
141*2d543d20SAndroid Build Coastguard Worker 	int c;
142*2d543d20SAndroid Build Coastguard Worker 
143*2d543d20SAndroid Build Coastguard Worker 	while ((c = *(unsigned const char *)str++))
144*2d543d20SAndroid Build Coastguard Worker 		hash = ((hash << 5) + hash) + c;
145*2d543d20SAndroid Build Coastguard Worker 
146*2d543d20SAndroid Build Coastguard Worker 	return hash;
147*2d543d20SAndroid Build Coastguard Worker }
148*2d543d20SAndroid Build Coastguard Worker 
149*2d543d20SAndroid Build Coastguard Worker static int
add_to_hashtable(context_map_node_t ** table,char * key,context_map_t * map)150*2d543d20SAndroid Build Coastguard Worker add_to_hashtable(context_map_node_t **table, char *key, context_map_t *map) {
151*2d543d20SAndroid Build Coastguard Worker 	unsigned int bucket = hash(key) % N_BUCKETS;
152*2d543d20SAndroid Build Coastguard Worker 	context_map_node_t **n;
153*2d543d20SAndroid Build Coastguard Worker 	for (n = &table[bucket]; *n; n = &(*n)->next)
154*2d543d20SAndroid Build Coastguard Worker 		;
155*2d543d20SAndroid Build Coastguard Worker 	*n = malloc(sizeof(context_map_node_t));
156*2d543d20SAndroid Build Coastguard Worker 	if (! *n)
157*2d543d20SAndroid Build Coastguard Worker 		goto err;
158*2d543d20SAndroid Build Coastguard Worker 	(*n)->key = key;
159*2d543d20SAndroid Build Coastguard Worker 	(*n)->map = map;
160*2d543d20SAndroid Build Coastguard Worker 	(*n)->next = NULL;
161*2d543d20SAndroid Build Coastguard Worker 	return 0;
162*2d543d20SAndroid Build Coastguard Worker err:
163*2d543d20SAndroid Build Coastguard Worker 	syslog(LOG_ERR, "add_to_hashtable: allocation error");
164*2d543d20SAndroid Build Coastguard Worker 	return -1;
165*2d543d20SAndroid Build Coastguard Worker }
166*2d543d20SAndroid Build Coastguard Worker 
167*2d543d20SAndroid Build Coastguard Worker static int
numdigits(unsigned int n)168*2d543d20SAndroid Build Coastguard Worker numdigits(unsigned int n)
169*2d543d20SAndroid Build Coastguard Worker {
170*2d543d20SAndroid Build Coastguard Worker 	int count = 1;
171*2d543d20SAndroid Build Coastguard Worker 	while ((n = n / 10))
172*2d543d20SAndroid Build Coastguard Worker 		count++;
173*2d543d20SAndroid Build Coastguard Worker 	return count;
174*2d543d20SAndroid Build Coastguard Worker }
175*2d543d20SAndroid Build Coastguard Worker 
176*2d543d20SAndroid Build Coastguard Worker static int
parse_category(ebitmap_t * e,const char * raw,int allowinverse)177*2d543d20SAndroid Build Coastguard Worker parse_category(ebitmap_t *e, const char *raw, int allowinverse)
178*2d543d20SAndroid Build Coastguard Worker {
179*2d543d20SAndroid Build Coastguard Worker 	int inverse = 0;
180*2d543d20SAndroid Build Coastguard Worker 	unsigned int low, high;
181*2d543d20SAndroid Build Coastguard Worker 	while (*raw) {
182*2d543d20SAndroid Build Coastguard Worker 		if (allowinverse && *raw == '~') {
183*2d543d20SAndroid Build Coastguard Worker 			inverse = !inverse;
184*2d543d20SAndroid Build Coastguard Worker 			raw++;
185*2d543d20SAndroid Build Coastguard Worker 			continue;
186*2d543d20SAndroid Build Coastguard Worker 		}
187*2d543d20SAndroid Build Coastguard Worker 		if (sscanf(raw,"c%u", &low) != 1)
188*2d543d20SAndroid Build Coastguard Worker 			return -1;
189*2d543d20SAndroid Build Coastguard Worker 		raw += numdigits(low) + 1;
190*2d543d20SAndroid Build Coastguard Worker 		if (*raw == '.') {
191*2d543d20SAndroid Build Coastguard Worker 			raw++;
192*2d543d20SAndroid Build Coastguard Worker 			if (sscanf(raw,"c%u", &high) != 1)
193*2d543d20SAndroid Build Coastguard Worker 				return -1;
194*2d543d20SAndroid Build Coastguard Worker 			raw += numdigits(high) + 1;
195*2d543d20SAndroid Build Coastguard Worker 		} else {
196*2d543d20SAndroid Build Coastguard Worker 			high = low;
197*2d543d20SAndroid Build Coastguard Worker 		}
198*2d543d20SAndroid Build Coastguard Worker 		while (low <= high) {
199*2d543d20SAndroid Build Coastguard Worker 			if (low >= maxbit)
200*2d543d20SAndroid Build Coastguard Worker 				maxbit = low + 1;
201*2d543d20SAndroid Build Coastguard Worker 			if (ebitmap_set_bit(e, low, inverse ? 0 : 1) < 0)
202*2d543d20SAndroid Build Coastguard Worker 				return -1;
203*2d543d20SAndroid Build Coastguard Worker 			low++;
204*2d543d20SAndroid Build Coastguard Worker 		}
205*2d543d20SAndroid Build Coastguard Worker 		if (*raw == ',') {
206*2d543d20SAndroid Build Coastguard Worker 			raw++;
207*2d543d20SAndroid Build Coastguard Worker 			inverse = 0;
208*2d543d20SAndroid Build Coastguard Worker 		} else if (*raw != '\0') {
209*2d543d20SAndroid Build Coastguard Worker 			return -1;
210*2d543d20SAndroid Build Coastguard Worker 		}
211*2d543d20SAndroid Build Coastguard Worker 	}
212*2d543d20SAndroid Build Coastguard Worker 	return 0;
213*2d543d20SAndroid Build Coastguard Worker }
214*2d543d20SAndroid Build Coastguard Worker 
215*2d543d20SAndroid Build Coastguard Worker static int
parse_ebitmap(ebitmap_t * e,ebitmap_t * def,const char * raw)216*2d543d20SAndroid Build Coastguard Worker parse_ebitmap(ebitmap_t *e, ebitmap_t *def, const char *raw) {
217*2d543d20SAndroid Build Coastguard Worker 	int rc = ebitmap_cpy(e, def);
218*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
219*2d543d20SAndroid Build Coastguard Worker 		return rc;
220*2d543d20SAndroid Build Coastguard Worker 	rc = parse_category(e, raw, 1);
221*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0)
222*2d543d20SAndroid Build Coastguard Worker 		return rc;
223*2d543d20SAndroid Build Coastguard Worker 	return 0;
224*2d543d20SAndroid Build Coastguard Worker }
225*2d543d20SAndroid Build Coastguard Worker 
226*2d543d20SAndroid Build Coastguard Worker static mls_level_t *
parse_raw(const char * raw)227*2d543d20SAndroid Build Coastguard Worker parse_raw(const char *raw) {
228*2d543d20SAndroid Build Coastguard Worker 	mls_level_t *mls = calloc(1, sizeof(mls_level_t));
229*2d543d20SAndroid Build Coastguard Worker 	if (!mls)
230*2d543d20SAndroid Build Coastguard Worker 		goto err;
231*2d543d20SAndroid Build Coastguard Worker 	if (sscanf(raw,"s%u", &mls->sens) != 1)
232*2d543d20SAndroid Build Coastguard Worker 		goto err;
233*2d543d20SAndroid Build Coastguard Worker 	raw += numdigits(mls->sens) + 1;
234*2d543d20SAndroid Build Coastguard Worker 	if (*raw == ':') {
235*2d543d20SAndroid Build Coastguard Worker 		raw++;
236*2d543d20SAndroid Build Coastguard Worker 		if (parse_category(&mls->cat, raw, 0) < 0)
237*2d543d20SAndroid Build Coastguard Worker 			goto err;
238*2d543d20SAndroid Build Coastguard Worker 	} else if (*raw != '\0') {
239*2d543d20SAndroid Build Coastguard Worker 		goto err;
240*2d543d20SAndroid Build Coastguard Worker 	}
241*2d543d20SAndroid Build Coastguard Worker 
242*2d543d20SAndroid Build Coastguard Worker 	return mls;
243*2d543d20SAndroid Build Coastguard Worker 
244*2d543d20SAndroid Build Coastguard Worker err:
245*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&mls->cat);
246*2d543d20SAndroid Build Coastguard Worker 	free(mls);
247*2d543d20SAndroid Build Coastguard Worker 	return NULL;
248*2d543d20SAndroid Build Coastguard Worker }
249*2d543d20SAndroid Build Coastguard Worker 
250*2d543d20SAndroid Build Coastguard Worker static void
destroy_word(word_t ** list,word_t * word)251*2d543d20SAndroid Build Coastguard Worker destroy_word(word_t **list, word_t *word) {
252*2d543d20SAndroid Build Coastguard Worker 	if (!word) {
253*2d543d20SAndroid Build Coastguard Worker 		return;
254*2d543d20SAndroid Build Coastguard Worker 	}
255*2d543d20SAndroid Build Coastguard Worker 	for (; list && *list; list = &(*list)->next) {
256*2d543d20SAndroid Build Coastguard Worker 		if (*list == word) {
257*2d543d20SAndroid Build Coastguard Worker 			*list = word->next;
258*2d543d20SAndroid Build Coastguard Worker 			break;
259*2d543d20SAndroid Build Coastguard Worker 		}
260*2d543d20SAndroid Build Coastguard Worker 	}
261*2d543d20SAndroid Build Coastguard Worker 	free(word->text);
262*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&word->cat);
263*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&word->normal);
264*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&word->inverse);
265*2d543d20SAndroid Build Coastguard Worker 	memset(word, 0, sizeof(word_t));
266*2d543d20SAndroid Build Coastguard Worker 	free(word);
267*2d543d20SAndroid Build Coastguard Worker }
268*2d543d20SAndroid Build Coastguard Worker 
269*2d543d20SAndroid Build Coastguard Worker static word_t *
create_word(word_t ** list,const char * text)270*2d543d20SAndroid Build Coastguard Worker create_word(word_t **list, const char *text) {
271*2d543d20SAndroid Build Coastguard Worker 	word_t *w = calloc(1, sizeof(word_t));
272*2d543d20SAndroid Build Coastguard Worker 	if (!w) {
273*2d543d20SAndroid Build Coastguard Worker 		goto err;
274*2d543d20SAndroid Build Coastguard Worker 	}
275*2d543d20SAndroid Build Coastguard Worker 	w->text = strdup(text);
276*2d543d20SAndroid Build Coastguard Worker 	if (!w->text) {
277*2d543d20SAndroid Build Coastguard Worker 		goto err;
278*2d543d20SAndroid Build Coastguard Worker 	}
279*2d543d20SAndroid Build Coastguard Worker 	if (list) {
280*2d543d20SAndroid Build Coastguard Worker 		for (; *list; list = &(*list)->next)
281*2d543d20SAndroid Build Coastguard Worker 			;
282*2d543d20SAndroid Build Coastguard Worker 		*list = w;
283*2d543d20SAndroid Build Coastguard Worker 	}
284*2d543d20SAndroid Build Coastguard Worker 
285*2d543d20SAndroid Build Coastguard Worker 	return w;
286*2d543d20SAndroid Build Coastguard Worker 
287*2d543d20SAndroid Build Coastguard Worker err:
288*2d543d20SAndroid Build Coastguard Worker 	log_error("create_word: allocation error %s", strerror(errno));
289*2d543d20SAndroid Build Coastguard Worker 	destroy_word(NULL, w);
290*2d543d20SAndroid Build Coastguard Worker 	return NULL;
291*2d543d20SAndroid Build Coastguard Worker }
292*2d543d20SAndroid Build Coastguard Worker 
293*2d543d20SAndroid Build Coastguard Worker static void
destroy_group(word_group_t ** list,word_group_t * group)294*2d543d20SAndroid Build Coastguard Worker destroy_group(word_group_t **list, word_group_t *group) {
295*2d543d20SAndroid Build Coastguard Worker 	for (; list && *list; list = &(*list)->next) {
296*2d543d20SAndroid Build Coastguard Worker 		if (*list == group) {
297*2d543d20SAndroid Build Coastguard Worker 			*list = group->next;
298*2d543d20SAndroid Build Coastguard Worker 			break;
299*2d543d20SAndroid Build Coastguard Worker 		}
300*2d543d20SAndroid Build Coastguard Worker 	}
301*2d543d20SAndroid Build Coastguard Worker 	while(group->prefixes) {
302*2d543d20SAndroid Build Coastguard Worker 		affix_t *next = group->prefixes->next;
303*2d543d20SAndroid Build Coastguard Worker 		free(group->prefixes->text);
304*2d543d20SAndroid Build Coastguard Worker 		free(group->prefixes);
305*2d543d20SAndroid Build Coastguard Worker 		group->prefixes=next;
306*2d543d20SAndroid Build Coastguard Worker 	}
307*2d543d20SAndroid Build Coastguard Worker 	while(group->suffixes) {
308*2d543d20SAndroid Build Coastguard Worker 		affix_t *next = group->suffixes->next;
309*2d543d20SAndroid Build Coastguard Worker 		free(group->suffixes->text);
310*2d543d20SAndroid Build Coastguard Worker 		free(group->suffixes);
311*2d543d20SAndroid Build Coastguard Worker 		group->suffixes=next;
312*2d543d20SAndroid Build Coastguard Worker 	}
313*2d543d20SAndroid Build Coastguard Worker 	while(group->words)
314*2d543d20SAndroid Build Coastguard Worker 		destroy_word(&group->words, group->words);
315*2d543d20SAndroid Build Coastguard Worker 	free(group->whitespace);
316*2d543d20SAndroid Build Coastguard Worker 	free(group->name);
317*2d543d20SAndroid Build Coastguard Worker 	free(group->sword);
318*2d543d20SAndroid Build Coastguard Worker 	free(group->join);
319*2d543d20SAndroid Build Coastguard Worker 	pcre2_code_free(group->prefix_regexp);
320*2d543d20SAndroid Build Coastguard Worker 	pcre2_code_free(group->word_regexp);
321*2d543d20SAndroid Build Coastguard Worker 	pcre2_code_free(group->suffix_regexp);
322*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&group->def);
323*2d543d20SAndroid Build Coastguard Worker 	free(group);
324*2d543d20SAndroid Build Coastguard Worker }
325*2d543d20SAndroid Build Coastguard Worker 
326*2d543d20SAndroid Build Coastguard Worker static word_group_t *
create_group(word_group_t ** list,const char * name)327*2d543d20SAndroid Build Coastguard Worker create_group(word_group_t **list, const char *name) {
328*2d543d20SAndroid Build Coastguard Worker 	word_group_t *group = calloc(1, sizeof(word_group_t));
329*2d543d20SAndroid Build Coastguard Worker 	if (!group)
330*2d543d20SAndroid Build Coastguard Worker 		return NULL;
331*2d543d20SAndroid Build Coastguard Worker 	group->name = strdup(name);
332*2d543d20SAndroid Build Coastguard Worker 	if (!group->name) {
333*2d543d20SAndroid Build Coastguard Worker 		goto err;
334*2d543d20SAndroid Build Coastguard Worker 	}
335*2d543d20SAndroid Build Coastguard Worker 	group->join = strdup(" ");
336*2d543d20SAndroid Build Coastguard Worker 	if (!group->join) {
337*2d543d20SAndroid Build Coastguard Worker 		goto err;
338*2d543d20SAndroid Build Coastguard Worker 	}
339*2d543d20SAndroid Build Coastguard Worker 	group->whitespace = strdup(" ");
340*2d543d20SAndroid Build Coastguard Worker 	if (!group->whitespace) {
341*2d543d20SAndroid Build Coastguard Worker 		goto err;
342*2d543d20SAndroid Build Coastguard Worker 	}
343*2d543d20SAndroid Build Coastguard Worker 	group->sword = NULL;
344*2d543d20SAndroid Build Coastguard Worker 
345*2d543d20SAndroid Build Coastguard Worker 	if (list) {
346*2d543d20SAndroid Build Coastguard Worker 		for (; *list; list = &(*list)->next)
347*2d543d20SAndroid Build Coastguard Worker 			;
348*2d543d20SAndroid Build Coastguard Worker 		*list = group;
349*2d543d20SAndroid Build Coastguard Worker 	}
350*2d543d20SAndroid Build Coastguard Worker 
351*2d543d20SAndroid Build Coastguard Worker 	return group;
352*2d543d20SAndroid Build Coastguard Worker 
353*2d543d20SAndroid Build Coastguard Worker err:
354*2d543d20SAndroid Build Coastguard Worker 	log_error("allocation error %s", strerror(errno));
355*2d543d20SAndroid Build Coastguard Worker 	destroy_group(NULL, group);
356*2d543d20SAndroid Build Coastguard Worker 	return NULL;
357*2d543d20SAndroid Build Coastguard Worker }
358*2d543d20SAndroid Build Coastguard Worker 
359*2d543d20SAndroid Build Coastguard Worker static void
destroy_domain(domain_t * domain)360*2d543d20SAndroid Build Coastguard Worker destroy_domain(domain_t *domain) {
361*2d543d20SAndroid Build Coastguard Worker 	int i;
362*2d543d20SAndroid Build Coastguard Worker         unsigned int rt = 0, tr = 0;
363*2d543d20SAndroid Build Coastguard Worker 	for (i=0; i < N_BUCKETS; i++) {
364*2d543d20SAndroid Build Coastguard Worker 		context_map_node_t *ptr;
365*2d543d20SAndroid Build Coastguard Worker 		for (ptr = domain->trans_to_raw[i]; ptr;)  {
366*2d543d20SAndroid Build Coastguard Worker 			context_map_node_t *t = ptr->next;
367*2d543d20SAndroid Build Coastguard Worker 			free(ptr);
368*2d543d20SAndroid Build Coastguard Worker 			ptr = t;
369*2d543d20SAndroid Build Coastguard Worker 			tr++;
370*2d543d20SAndroid Build Coastguard Worker 		}
371*2d543d20SAndroid Build Coastguard Worker 		domain->trans_to_raw[i] = NULL;
372*2d543d20SAndroid Build Coastguard Worker 	}
373*2d543d20SAndroid Build Coastguard Worker 	for (i=0; i < N_BUCKETS; i++) {
374*2d543d20SAndroid Build Coastguard Worker 		context_map_node_t *ptr;
375*2d543d20SAndroid Build Coastguard Worker 		for (ptr = domain->raw_to_trans[i]; ptr;)  {
376*2d543d20SAndroid Build Coastguard Worker 			context_map_node_t *t = ptr->next;
377*2d543d20SAndroid Build Coastguard Worker 			free(ptr->map->raw);
378*2d543d20SAndroid Build Coastguard Worker 			free(ptr->map->trans);
379*2d543d20SAndroid Build Coastguard Worker 			free(ptr->map);
380*2d543d20SAndroid Build Coastguard Worker 			free(ptr);
381*2d543d20SAndroid Build Coastguard Worker 			ptr = t;
382*2d543d20SAndroid Build Coastguard Worker 			rt++;
383*2d543d20SAndroid Build Coastguard Worker 		}
384*2d543d20SAndroid Build Coastguard Worker 		domain->raw_to_trans[i] = NULL;
385*2d543d20SAndroid Build Coastguard Worker 	}
386*2d543d20SAndroid Build Coastguard Worker 	while (domain->base_classifications)  {
387*2d543d20SAndroid Build Coastguard Worker 		base_classification_t *next = domain->base_classifications->next;
388*2d543d20SAndroid Build Coastguard Worker 		free(domain->base_classifications->trans);
389*2d543d20SAndroid Build Coastguard Worker 		ebitmap_destroy(&domain->base_classifications->level->cat);
390*2d543d20SAndroid Build Coastguard Worker 		free(domain->base_classifications->level);
391*2d543d20SAndroid Build Coastguard Worker 		free(domain->base_classifications);
392*2d543d20SAndroid Build Coastguard Worker 		domain->base_classifications = next;
393*2d543d20SAndroid Build Coastguard Worker 	}
394*2d543d20SAndroid Build Coastguard Worker 	pcre2_code_free(domain->base_classification_regexp);
395*2d543d20SAndroid Build Coastguard Worker 	while (domain->groups)
396*2d543d20SAndroid Build Coastguard Worker 		destroy_group(&domain->groups, domain->groups);
397*2d543d20SAndroid Build Coastguard Worker 	free(domain->name);
398*2d543d20SAndroid Build Coastguard Worker 	free(domain);
399*2d543d20SAndroid Build Coastguard Worker 
400*2d543d20SAndroid Build Coastguard Worker 	syslog(LOG_INFO, "cache sizes: tr = %u, rt = %u", tr, rt);
401*2d543d20SAndroid Build Coastguard Worker }
402*2d543d20SAndroid Build Coastguard Worker 
403*2d543d20SAndroid Build Coastguard Worker static domain_t *
create_domain(const char * name)404*2d543d20SAndroid Build Coastguard Worker create_domain(const char *name) {
405*2d543d20SAndroid Build Coastguard Worker 	domain_t *domain = calloc(1, sizeof(domain_t));
406*2d543d20SAndroid Build Coastguard Worker 	if (!domain) {
407*2d543d20SAndroid Build Coastguard Worker 		goto err;
408*2d543d20SAndroid Build Coastguard Worker 	}
409*2d543d20SAndroid Build Coastguard Worker 	domain->name = strdup(name);
410*2d543d20SAndroid Build Coastguard Worker 	if (!domain->name) {
411*2d543d20SAndroid Build Coastguard Worker 		goto err;
412*2d543d20SAndroid Build Coastguard Worker 	}
413*2d543d20SAndroid Build Coastguard Worker 
414*2d543d20SAndroid Build Coastguard Worker 	domain_t **d = &domains;
415*2d543d20SAndroid Build Coastguard Worker 	for (; *d; d = &(*d)->next)
416*2d543d20SAndroid Build Coastguard Worker 		;
417*2d543d20SAndroid Build Coastguard Worker 	*d = domain;
418*2d543d20SAndroid Build Coastguard Worker 
419*2d543d20SAndroid Build Coastguard Worker 	return domain;
420*2d543d20SAndroid Build Coastguard Worker 
421*2d543d20SAndroid Build Coastguard Worker err:
422*2d543d20SAndroid Build Coastguard Worker 	log_error("allocation error %s", strerror(errno));
423*2d543d20SAndroid Build Coastguard Worker 	destroy_domain(domain);
424*2d543d20SAndroid Build Coastguard Worker 	return NULL;
425*2d543d20SAndroid Build Coastguard Worker }
426*2d543d20SAndroid Build Coastguard Worker 
427*2d543d20SAndroid Build Coastguard Worker static int
add_word(word_group_t * group,char * raw,char * trans)428*2d543d20SAndroid Build Coastguard Worker add_word(word_group_t *group, char *raw, char *trans) {
429*2d543d20SAndroid Build Coastguard Worker 	if (strchr(trans,'-')) {
430*2d543d20SAndroid Build Coastguard Worker 		log_error("'%s'is invalid because '-' is illegal in modifiers.\n", trans);
431*2d543d20SAndroid Build Coastguard Worker 		return -1;
432*2d543d20SAndroid Build Coastguard Worker 	}
433*2d543d20SAndroid Build Coastguard Worker 	word_t *word = create_word(&group->words, trans);
434*2d543d20SAndroid Build Coastguard Worker 	int rc = parse_ebitmap(&word->cat, &group->def, raw);
435*2d543d20SAndroid Build Coastguard Worker 	if (rc < 0) {
436*2d543d20SAndroid Build Coastguard Worker 		log_error(" syntax error in %s\n", raw);
437*2d543d20SAndroid Build Coastguard Worker 		destroy_word(&group->words, word);
438*2d543d20SAndroid Build Coastguard Worker 		return -1;
439*2d543d20SAndroid Build Coastguard Worker 	}
440*2d543d20SAndroid Build Coastguard Worker 	if (ebitmap_andnot(&word->normal, &word->cat, &group->def, maxbit) < 0)
441*2d543d20SAndroid Build Coastguard Worker 		return -1;
442*2d543d20SAndroid Build Coastguard Worker 
443*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t temp;
444*2d543d20SAndroid Build Coastguard Worker 	if (ebitmap_xor(&temp, &word->cat, &group->def) < 0)
445*2d543d20SAndroid Build Coastguard Worker 		return -1;
446*2d543d20SAndroid Build Coastguard Worker 	if (ebitmap_and(&word->inverse, &temp, &group->def) < 0)
447*2d543d20SAndroid Build Coastguard Worker 		return -1;
448*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&temp);
449*2d543d20SAndroid Build Coastguard Worker 
450*2d543d20SAndroid Build Coastguard Worker 	return 0;
451*2d543d20SAndroid Build Coastguard Worker }
452*2d543d20SAndroid Build Coastguard Worker 
453*2d543d20SAndroid Build Coastguard Worker static int
add_constraint(char op,char * raw,char * tok)454*2d543d20SAndroid Build Coastguard Worker add_constraint(char op, char *raw, char *tok) {
455*2d543d20SAndroid Build Coastguard Worker 	log_debug("%s\n", "add_constraint");
456*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t empty;
457*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&empty);
458*2d543d20SAndroid Build Coastguard Worker 	if (!raw || !*raw) {
459*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_ERR, "unable to parse line");
460*2d543d20SAndroid Build Coastguard Worker 		return -1;
461*2d543d20SAndroid Build Coastguard Worker 	}
462*2d543d20SAndroid Build Coastguard Worker 	if (*raw == 's') {
463*2d543d20SAndroid Build Coastguard Worker 		sens_constraint_t *constraint = calloc(1, sizeof(sens_constraint_t));
464*2d543d20SAndroid Build Coastguard Worker 		if (!constraint) {
465*2d543d20SAndroid Build Coastguard Worker 			log_error("allocation error %s", strerror(errno));
466*2d543d20SAndroid Build Coastguard Worker 			return -1;
467*2d543d20SAndroid Build Coastguard Worker 		}
468*2d543d20SAndroid Build Coastguard Worker 		if (sscanf(raw,"s%u", &constraint->sens) != 1) {
469*2d543d20SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "unable to parse level");
470*2d543d20SAndroid Build Coastguard Worker 			free(constraint);
471*2d543d20SAndroid Build Coastguard Worker 			return -1;
472*2d543d20SAndroid Build Coastguard Worker 		}
473*2d543d20SAndroid Build Coastguard Worker 		if (parse_ebitmap(&constraint->cat, &empty, tok) < 0) {
474*2d543d20SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "unable to parse cat");
475*2d543d20SAndroid Build Coastguard Worker 			free(constraint);
476*2d543d20SAndroid Build Coastguard Worker 			return -1;
477*2d543d20SAndroid Build Coastguard Worker 		}
478*2d543d20SAndroid Build Coastguard Worker 		if (asprintf(&constraint->text, "%s%c%s", raw, op, tok) < 0) {
479*2d543d20SAndroid Build Coastguard Worker 			log_error("asprintf failed %s", strerror(errno));
480*2d543d20SAndroid Build Coastguard Worker 			free(constraint);
481*2d543d20SAndroid Build Coastguard Worker 			return -1;
482*2d543d20SAndroid Build Coastguard Worker 		}
483*2d543d20SAndroid Build Coastguard Worker 		constraint->op = op;
484*2d543d20SAndroid Build Coastguard Worker 		sens_constraint_t **p;
485*2d543d20SAndroid Build Coastguard Worker 		for (p= &sens_constraints; *p; p = &(*p)->next)
486*2d543d20SAndroid Build Coastguard Worker                         ;
487*2d543d20SAndroid Build Coastguard Worker                 *p = constraint;
488*2d543d20SAndroid Build Coastguard Worker 		return 0;
489*2d543d20SAndroid Build Coastguard Worker 	} else if (*raw == 'c' ) {
490*2d543d20SAndroid Build Coastguard Worker 		cat_constraint_t *constraint = calloc(1, sizeof(cat_constraint_t));
491*2d543d20SAndroid Build Coastguard Worker 		if (!constraint) {
492*2d543d20SAndroid Build Coastguard Worker 			log_error("allocation error %s", strerror(errno));
493*2d543d20SAndroid Build Coastguard Worker 			return -1;
494*2d543d20SAndroid Build Coastguard Worker 		}
495*2d543d20SAndroid Build Coastguard Worker 		if (parse_ebitmap(&constraint->mask, &empty, raw) < 0) {
496*2d543d20SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "unable to parse mask");
497*2d543d20SAndroid Build Coastguard Worker 			free(constraint);
498*2d543d20SAndroid Build Coastguard Worker 			return -1;
499*2d543d20SAndroid Build Coastguard Worker 		}
500*2d543d20SAndroid Build Coastguard Worker 		if (parse_ebitmap(&constraint->cat, &empty, tok) < 0) {
501*2d543d20SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "unable to parse cat");
502*2d543d20SAndroid Build Coastguard Worker 			ebitmap_destroy(&constraint->mask);
503*2d543d20SAndroid Build Coastguard Worker 			free(constraint);
504*2d543d20SAndroid Build Coastguard Worker 			return -1;
505*2d543d20SAndroid Build Coastguard Worker 		}
506*2d543d20SAndroid Build Coastguard Worker 		if (asprintf(&constraint->text, "%s%c%s", raw, op, tok) < 0) {
507*2d543d20SAndroid Build Coastguard Worker 			log_error("asprintf failed %s", strerror(errno));
508*2d543d20SAndroid Build Coastguard Worker 			return -1;
509*2d543d20SAndroid Build Coastguard Worker 		}
510*2d543d20SAndroid Build Coastguard Worker 		constraint->nbits = ebitmap_cardinality(&constraint->cat);
511*2d543d20SAndroid Build Coastguard Worker 		constraint->op = op;
512*2d543d20SAndroid Build Coastguard Worker 		cat_constraint_t **p;
513*2d543d20SAndroid Build Coastguard Worker 		for (p= &cat_constraints; *p; p = &(*p)->next)
514*2d543d20SAndroid Build Coastguard Worker                         ;
515*2d543d20SAndroid Build Coastguard Worker                 *p = constraint;
516*2d543d20SAndroid Build Coastguard Worker 		return 0;
517*2d543d20SAndroid Build Coastguard Worker 	} else {
518*2d543d20SAndroid Build Coastguard Worker 		return -1;
519*2d543d20SAndroid Build Coastguard Worker 	}
520*2d543d20SAndroid Build Coastguard Worker 
521*2d543d20SAndroid Build Coastguard Worker 	return 0;
522*2d543d20SAndroid Build Coastguard Worker }
523*2d543d20SAndroid Build Coastguard Worker 
524*2d543d20SAndroid Build Coastguard Worker static int
violates_constraints(mls_level_t * l)525*2d543d20SAndroid Build Coastguard Worker violates_constraints(mls_level_t *l) {
526*2d543d20SAndroid Build Coastguard Worker 	int nbits;
527*2d543d20SAndroid Build Coastguard Worker 	sens_constraint_t *s;
528*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t common;
529*2d543d20SAndroid Build Coastguard Worker 	for (s=sens_constraints; s; s=s->next) {
530*2d543d20SAndroid Build Coastguard Worker 		if (s->sens == l->sens) {
531*2d543d20SAndroid Build Coastguard Worker 			if (ebitmap_and(&common, &s->cat, &l->cat) < 0)
532*2d543d20SAndroid Build Coastguard Worker 				return 1;
533*2d543d20SAndroid Build Coastguard Worker 			nbits = ebitmap_cardinality(&common);
534*2d543d20SAndroid Build Coastguard Worker 			ebitmap_destroy(&common);
535*2d543d20SAndroid Build Coastguard Worker 			if (nbits) {
536*2d543d20SAndroid Build Coastguard Worker 				char *text = mls_level_to_string(l);
537*2d543d20SAndroid Build Coastguard Worker 				syslog(LOG_WARNING, "%s violates %s", text, s->text);
538*2d543d20SAndroid Build Coastguard Worker 				free(text);
539*2d543d20SAndroid Build Coastguard Worker 				return 1;
540*2d543d20SAndroid Build Coastguard Worker 			}
541*2d543d20SAndroid Build Coastguard Worker 		}
542*2d543d20SAndroid Build Coastguard Worker 	}
543*2d543d20SAndroid Build Coastguard Worker 	cat_constraint_t *c;
544*2d543d20SAndroid Build Coastguard Worker 	for (c=cat_constraints; c; c=c->next) {
545*2d543d20SAndroid Build Coastguard Worker 		if (ebitmap_and(&common, &c->mask, &l->cat) < 0)
546*2d543d20SAndroid Build Coastguard Worker 			return 1;
547*2d543d20SAndroid Build Coastguard Worker 		nbits = ebitmap_cardinality(&common);
548*2d543d20SAndroid Build Coastguard Worker 		ebitmap_destroy(&common);
549*2d543d20SAndroid Build Coastguard Worker 		if (nbits > 0) {
550*2d543d20SAndroid Build Coastguard Worker 			if (ebitmap_and(&common, &c->cat, &l->cat) < 0)
551*2d543d20SAndroid Build Coastguard Worker 				return 1;
552*2d543d20SAndroid Build Coastguard Worker 			nbits = ebitmap_cardinality(&common);
553*2d543d20SAndroid Build Coastguard Worker 			ebitmap_destroy(&common);
554*2d543d20SAndroid Build Coastguard Worker 			if ((c->op == '!' && nbits) ||
555*2d543d20SAndroid Build Coastguard Worker 			    (c->op == '>' && nbits != c->nbits)) {
556*2d543d20SAndroid Build Coastguard Worker 				char *text = mls_level_to_string(l);
557*2d543d20SAndroid Build Coastguard Worker 				syslog(LOG_WARNING, "%s violates %s (%d,%d)", text, c->text, nbits, c->nbits);
558*2d543d20SAndroid Build Coastguard Worker 				free(text);
559*2d543d20SAndroid Build Coastguard Worker 				return 1;
560*2d543d20SAndroid Build Coastguard Worker 			}
561*2d543d20SAndroid Build Coastguard Worker 		}
562*2d543d20SAndroid Build Coastguard Worker 	}
563*2d543d20SAndroid Build Coastguard Worker 	return 0;
564*2d543d20SAndroid Build Coastguard Worker }
565*2d543d20SAndroid Build Coastguard Worker 
566*2d543d20SAndroid Build Coastguard Worker static void
destroy_sens_constraint(sens_constraint_t ** list,sens_constraint_t * constraint)567*2d543d20SAndroid Build Coastguard Worker destroy_sens_constraint(sens_constraint_t **list, sens_constraint_t *constraint) {
568*2d543d20SAndroid Build Coastguard Worker 	if (!constraint) {
569*2d543d20SAndroid Build Coastguard Worker 		return;
570*2d543d20SAndroid Build Coastguard Worker 	}
571*2d543d20SAndroid Build Coastguard Worker 	for (; list && *list; list = &(*list)->next) {
572*2d543d20SAndroid Build Coastguard Worker 		if (*list == constraint) {
573*2d543d20SAndroid Build Coastguard Worker 			*list = constraint->next;
574*2d543d20SAndroid Build Coastguard Worker 			break;
575*2d543d20SAndroid Build Coastguard Worker 		}
576*2d543d20SAndroid Build Coastguard Worker 	}
577*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&constraint->cat);
578*2d543d20SAndroid Build Coastguard Worker 	free(constraint->text);
579*2d543d20SAndroid Build Coastguard Worker 	memset(constraint, 0, sizeof(sens_constraint_t));
580*2d543d20SAndroid Build Coastguard Worker 	free(constraint);
581*2d543d20SAndroid Build Coastguard Worker }
582*2d543d20SAndroid Build Coastguard Worker 
583*2d543d20SAndroid Build Coastguard Worker static void
destroy_cat_constraint(cat_constraint_t ** list,cat_constraint_t * constraint)584*2d543d20SAndroid Build Coastguard Worker destroy_cat_constraint(cat_constraint_t **list, cat_constraint_t *constraint) {
585*2d543d20SAndroid Build Coastguard Worker 	if (!constraint) {
586*2d543d20SAndroid Build Coastguard Worker 		return;
587*2d543d20SAndroid Build Coastguard Worker 	}
588*2d543d20SAndroid Build Coastguard Worker 	for (; list && *list; list = &(*list)->next) {
589*2d543d20SAndroid Build Coastguard Worker 		if (*list == constraint) {
590*2d543d20SAndroid Build Coastguard Worker 			*list = constraint->next;
591*2d543d20SAndroid Build Coastguard Worker 			break;
592*2d543d20SAndroid Build Coastguard Worker 		}
593*2d543d20SAndroid Build Coastguard Worker 	}
594*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&constraint->mask);
595*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&constraint->cat);
596*2d543d20SAndroid Build Coastguard Worker 	free(constraint->text);
597*2d543d20SAndroid Build Coastguard Worker 	memset(constraint, 0, sizeof(cat_constraint_t));
598*2d543d20SAndroid Build Coastguard Worker 	free(constraint);
599*2d543d20SAndroid Build Coastguard Worker }
600*2d543d20SAndroid Build Coastguard Worker 
601*2d543d20SAndroid Build Coastguard Worker 
602*2d543d20SAndroid Build Coastguard Worker static int
add_base_classification(domain_t * domain,char * raw,char * trans)603*2d543d20SAndroid Build Coastguard Worker add_base_classification(domain_t *domain, char *raw, char *trans) {
604*2d543d20SAndroid Build Coastguard Worker 	mls_level_t *level = parse_raw(raw);
605*2d543d20SAndroid Build Coastguard Worker 	if (level) {
606*2d543d20SAndroid Build Coastguard Worker 		base_classification_t **i;
607*2d543d20SAndroid Build Coastguard Worker 		base_classification_t *base_classification = calloc(1, sizeof(base_classification_t));
608*2d543d20SAndroid Build Coastguard Worker 		if (!base_classification) {
609*2d543d20SAndroid Build Coastguard Worker 			log_error("allocation error %s", strerror(errno));
610*2d543d20SAndroid Build Coastguard Worker 			return -1;
611*2d543d20SAndroid Build Coastguard Worker 		}
612*2d543d20SAndroid Build Coastguard Worker 		base_classification->trans=strdup(trans);
613*2d543d20SAndroid Build Coastguard Worker 		if (!base_classification->trans) {
614*2d543d20SAndroid Build Coastguard Worker 			log_error("allocation error %s", strerror(errno));
615*2d543d20SAndroid Build Coastguard Worker 			free(base_classification);
616*2d543d20SAndroid Build Coastguard Worker 			return -1;
617*2d543d20SAndroid Build Coastguard Worker 		}
618*2d543d20SAndroid Build Coastguard Worker 		base_classification->level=level;
619*2d543d20SAndroid Build Coastguard Worker 
620*2d543d20SAndroid Build Coastguard Worker 		for (i=&domain->base_classifications; *i; i=&(*i)->next)
621*2d543d20SAndroid Build Coastguard Worker 		;
622*2d543d20SAndroid Build Coastguard Worker 		*i = base_classification;
623*2d543d20SAndroid Build Coastguard Worker 			return 0;
624*2d543d20SAndroid Build Coastguard Worker 		}
625*2d543d20SAndroid Build Coastguard Worker 	log_error(" add_base_classification error %s %s\n", raw, trans);
626*2d543d20SAndroid Build Coastguard Worker 	return -1;
627*2d543d20SAndroid Build Coastguard Worker }
628*2d543d20SAndroid Build Coastguard Worker 
629*2d543d20SAndroid Build Coastguard Worker static int
add_cache(domain_t * domain,char * raw,char * trans)630*2d543d20SAndroid Build Coastguard Worker add_cache(domain_t *domain, char *raw, char *trans) {
631*2d543d20SAndroid Build Coastguard Worker 	context_map_t *map = calloc(1, sizeof(context_map_t));
632*2d543d20SAndroid Build Coastguard Worker 	if (!map) goto err;
633*2d543d20SAndroid Build Coastguard Worker 
634*2d543d20SAndroid Build Coastguard Worker 	map->raw = strdup(raw);
635*2d543d20SAndroid Build Coastguard Worker 	if (!map->raw) {
636*2d543d20SAndroid Build Coastguard Worker 		free(map);
637*2d543d20SAndroid Build Coastguard Worker 		goto err;
638*2d543d20SAndroid Build Coastguard Worker 	}
639*2d543d20SAndroid Build Coastguard Worker 	map->trans = strdup(trans);
640*2d543d20SAndroid Build Coastguard Worker 	if (!map->trans) {
641*2d543d20SAndroid Build Coastguard Worker 		free(map->raw);
642*2d543d20SAndroid Build Coastguard Worker 		free(map);
643*2d543d20SAndroid Build Coastguard Worker 		goto err;
644*2d543d20SAndroid Build Coastguard Worker 	}
645*2d543d20SAndroid Build Coastguard Worker 
646*2d543d20SAndroid Build Coastguard Worker 	log_debug(" add_cache (%s,%s)\n", raw, trans);
647*2d543d20SAndroid Build Coastguard Worker 	if (add_to_hashtable(domain->raw_to_trans, map->raw, map) < 0) {
648*2d543d20SAndroid Build Coastguard Worker 		free(map->trans);
649*2d543d20SAndroid Build Coastguard Worker 		free(map->raw);
650*2d543d20SAndroid Build Coastguard Worker 		free(map);
651*2d543d20SAndroid Build Coastguard Worker 		goto err;
652*2d543d20SAndroid Build Coastguard Worker 	}
653*2d543d20SAndroid Build Coastguard Worker 
654*2d543d20SAndroid Build Coastguard Worker 	if (add_to_hashtable(domain->trans_to_raw, map->trans, map) < 0)
655*2d543d20SAndroid Build Coastguard Worker 		goto err;
656*2d543d20SAndroid Build Coastguard Worker 
657*2d543d20SAndroid Build Coastguard Worker 	return 0;
658*2d543d20SAndroid Build Coastguard Worker err:
659*2d543d20SAndroid Build Coastguard Worker 	log_error("%s: allocation error", "add_cache");
660*2d543d20SAndroid Build Coastguard Worker 	return -1;
661*2d543d20SAndroid Build Coastguard Worker }
662*2d543d20SAndroid Build Coastguard Worker 
663*2d543d20SAndroid Build Coastguard Worker static context_map_t *
find_in_table(context_map_node_t ** table,const char * key)664*2d543d20SAndroid Build Coastguard Worker find_in_table(context_map_node_t **table, const char *key) {
665*2d543d20SAndroid Build Coastguard Worker 	unsigned int bucket = hash(key) % N_BUCKETS;
666*2d543d20SAndroid Build Coastguard Worker 	context_map_node_t **n;
667*2d543d20SAndroid Build Coastguard Worker 	for (n = &table[bucket]; *n; n = &(*n)->next)
668*2d543d20SAndroid Build Coastguard Worker 		if (!strcmp((*n)->key, key))
669*2d543d20SAndroid Build Coastguard Worker 			return (*n)->map;
670*2d543d20SAndroid Build Coastguard Worker 	return NULL;
671*2d543d20SAndroid Build Coastguard Worker }
672*2d543d20SAndroid Build Coastguard Worker 
673*2d543d20SAndroid Build Coastguard Worker static char *
trim(char * str,const char * whitespace)674*2d543d20SAndroid Build Coastguard Worker trim(char *str, const char *whitespace) {
675*2d543d20SAndroid Build Coastguard Worker 	char *p = str + strlen(str);
676*2d543d20SAndroid Build Coastguard Worker 
677*2d543d20SAndroid Build Coastguard Worker 	while (p > str && strchr(whitespace, *(p-1)) != NULL)
678*2d543d20SAndroid Build Coastguard Worker 		*--p = 0;
679*2d543d20SAndroid Build Coastguard Worker 	return str;
680*2d543d20SAndroid Build Coastguard Worker }
681*2d543d20SAndroid Build Coastguard Worker 
682*2d543d20SAndroid Build Coastguard Worker static char *
triml(char * str,const char * whitespace)683*2d543d20SAndroid Build Coastguard Worker triml(char *str, const char *whitespace) {
684*2d543d20SAndroid Build Coastguard Worker 	char *p = str;
685*2d543d20SAndroid Build Coastguard Worker 
686*2d543d20SAndroid Build Coastguard Worker 	while (*p && (strchr(whitespace, *p) != NULL))
687*2d543d20SAndroid Build Coastguard Worker 		p++;
688*2d543d20SAndroid Build Coastguard Worker 	return p;
689*2d543d20SAndroid Build Coastguard Worker }
690*2d543d20SAndroid Build Coastguard Worker 
691*2d543d20SAndroid Build Coastguard Worker static int
update(char ** p,char * const val)692*2d543d20SAndroid Build Coastguard Worker update(char **p, char *const val) {
693*2d543d20SAndroid Build Coastguard Worker 	free (*p);
694*2d543d20SAndroid Build Coastguard Worker 	*p = strdup(val);
695*2d543d20SAndroid Build Coastguard Worker 	if (!*p) {
696*2d543d20SAndroid Build Coastguard Worker 		log_error("allocation error %s", strerror(errno));
697*2d543d20SAndroid Build Coastguard Worker 		return -1;
698*2d543d20SAndroid Build Coastguard Worker 	}
699*2d543d20SAndroid Build Coastguard Worker 	return 0;
700*2d543d20SAndroid Build Coastguard Worker }
701*2d543d20SAndroid Build Coastguard Worker 
702*2d543d20SAndroid Build Coastguard Worker static int
append(affix_t ** affixes,const char * val)703*2d543d20SAndroid Build Coastguard Worker append(affix_t **affixes, const char *val) {
704*2d543d20SAndroid Build Coastguard Worker 	affix_t *affix = calloc(1, sizeof(affix_t));
705*2d543d20SAndroid Build Coastguard Worker 	if (!affix) {
706*2d543d20SAndroid Build Coastguard Worker 		goto err;
707*2d543d20SAndroid Build Coastguard Worker 	}
708*2d543d20SAndroid Build Coastguard Worker 	affix->text = strdup(val);
709*2d543d20SAndroid Build Coastguard Worker 	if (!affix->text)
710*2d543d20SAndroid Build Coastguard Worker 		goto err;
711*2d543d20SAndroid Build Coastguard Worker 	for (;*affixes; affixes = &(*affixes)->next)
712*2d543d20SAndroid Build Coastguard Worker 		;
713*2d543d20SAndroid Build Coastguard Worker 	*affixes = affix;
714*2d543d20SAndroid Build Coastguard Worker 	return 0;
715*2d543d20SAndroid Build Coastguard Worker 
716*2d543d20SAndroid Build Coastguard Worker err:
717*2d543d20SAndroid Build Coastguard Worker 	log_error("allocation error %s", strerror(errno));
718*2d543d20SAndroid Build Coastguard Worker 	free(affix);
719*2d543d20SAndroid Build Coastguard Worker 	return -1;
720*2d543d20SAndroid Build Coastguard Worker }
721*2d543d20SAndroid Build Coastguard Worker 
722*2d543d20SAndroid Build Coastguard Worker static int read_translations(const char *filename);
723*2d543d20SAndroid Build Coastguard Worker 
724*2d543d20SAndroid Build Coastguard Worker /* Process line from translation file.
725*2d543d20SAndroid Build Coastguard Worker    Remove white space and set raw do data before the "=" and tok to data after it
726*2d543d20SAndroid Build Coastguard Worker    Modifies the data pointed to by the buffer parameter
727*2d543d20SAndroid Build Coastguard Worker  */
728*2d543d20SAndroid Build Coastguard Worker static int
process_trans(char * buffer)729*2d543d20SAndroid Build Coastguard Worker process_trans(char *buffer) {
730*2d543d20SAndroid Build Coastguard Worker 	static domain_t *domain;
731*2d543d20SAndroid Build Coastguard Worker 	static word_group_t *group;
732*2d543d20SAndroid Build Coastguard Worker 	static int base_classification;
733*2d543d20SAndroid Build Coastguard Worker 	static int lineno = 0;
734*2d543d20SAndroid Build Coastguard Worker 	char op='\0';
735*2d543d20SAndroid Build Coastguard Worker 
736*2d543d20SAndroid Build Coastguard Worker 	lineno++;
737*2d543d20SAndroid Build Coastguard Worker 	log_debug("%d: %s", lineno, buffer);
738*2d543d20SAndroid Build Coastguard Worker 
739*2d543d20SAndroid Build Coastguard Worker 	/* zap leading whitespace */
740*2d543d20SAndroid Build Coastguard Worker 	buffer = triml(buffer, "\t ");
741*2d543d20SAndroid Build Coastguard Worker 
742*2d543d20SAndroid Build Coastguard Worker 	/* Ignore comments */
743*2d543d20SAndroid Build Coastguard Worker 	if (*buffer == '#') return 0;
744*2d543d20SAndroid Build Coastguard Worker 	char *comment = strpbrk (buffer, "#");
745*2d543d20SAndroid Build Coastguard Worker 	if (comment) {
746*2d543d20SAndroid Build Coastguard Worker 		*comment = '\0';
747*2d543d20SAndroid Build Coastguard Worker 	}
748*2d543d20SAndroid Build Coastguard Worker 
749*2d543d20SAndroid Build Coastguard Worker 	/* zap trailing whitespace */
750*2d543d20SAndroid Build Coastguard Worker 	buffer = trim(buffer, "\t \r\n");
751*2d543d20SAndroid Build Coastguard Worker 
752*2d543d20SAndroid Build Coastguard Worker 	if (*buffer == 0) return 0;
753*2d543d20SAndroid Build Coastguard Worker 
754*2d543d20SAndroid Build Coastguard Worker 	char *delim = strpbrk (buffer, "=!>");
755*2d543d20SAndroid Build Coastguard Worker 	if (! delim) {
756*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_ERR, "invalid line (no !, = or >) %d", lineno);
757*2d543d20SAndroid Build Coastguard Worker 		return -1;
758*2d543d20SAndroid Build Coastguard Worker 	}
759*2d543d20SAndroid Build Coastguard Worker 
760*2d543d20SAndroid Build Coastguard Worker 	op = *delim;
761*2d543d20SAndroid Build Coastguard Worker 	*delim = '\0';
762*2d543d20SAndroid Build Coastguard Worker 	char *raw = buffer;
763*2d543d20SAndroid Build Coastguard Worker 	char *tok = delim+1;
764*2d543d20SAndroid Build Coastguard Worker 
765*2d543d20SAndroid Build Coastguard Worker 	/* remove trailing/leading whitespace from the split tokens */
766*2d543d20SAndroid Build Coastguard Worker 	trim(raw, "\t ");
767*2d543d20SAndroid Build Coastguard Worker 	tok = triml(tok, "\t ");
768*2d543d20SAndroid Build Coastguard Worker 
769*2d543d20SAndroid Build Coastguard Worker 	if (! *raw) {
770*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_ERR, "invalid line %d", lineno);
771*2d543d20SAndroid Build Coastguard Worker 		return -1;
772*2d543d20SAndroid Build Coastguard Worker 	}
773*2d543d20SAndroid Build Coastguard Worker 
774*2d543d20SAndroid Build Coastguard Worker 	if (! *tok) {
775*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_ERR, "invalid line %d", lineno);
776*2d543d20SAndroid Build Coastguard Worker 		return -1;
777*2d543d20SAndroid Build Coastguard Worker 	}
778*2d543d20SAndroid Build Coastguard Worker 
779*2d543d20SAndroid Build Coastguard Worker 	/* constraints have different syntax */
780*2d543d20SAndroid Build Coastguard Worker 	if (op == '!' || op == '>') {
781*2d543d20SAndroid Build Coastguard Worker 		return add_constraint(op, raw, tok);
782*2d543d20SAndroid Build Coastguard Worker 	}
783*2d543d20SAndroid Build Coastguard Worker 
784*2d543d20SAndroid Build Coastguard Worker 	if (!strcmp(raw, "Domain")) {
785*2d543d20SAndroid Build Coastguard Worker 		domain = create_domain(tok);
786*2d543d20SAndroid Build Coastguard Worker 		group = NULL;
787*2d543d20SAndroid Build Coastguard Worker 		return 0;
788*2d543d20SAndroid Build Coastguard Worker 	}
789*2d543d20SAndroid Build Coastguard Worker 
790*2d543d20SAndroid Build Coastguard Worker 	if (!domain) {
791*2d543d20SAndroid Build Coastguard Worker 		domain = create_domain("Default");
792*2d543d20SAndroid Build Coastguard Worker 		if (!domain)
793*2d543d20SAndroid Build Coastguard Worker 			return -1;
794*2d543d20SAndroid Build Coastguard Worker 		group = NULL;
795*2d543d20SAndroid Build Coastguard Worker 	}
796*2d543d20SAndroid Build Coastguard Worker 
797*2d543d20SAndroid Build Coastguard Worker 	if (!group &&
798*2d543d20SAndroid Build Coastguard Worker 	    (!strcmp(raw, "Whitespace") || !strcmp(raw, "Join") ||
799*2d543d20SAndroid Build Coastguard Worker 	     !strcmp(raw, "Prefix") || !strcmp(raw, "Suffix") ||
800*2d543d20SAndroid Build Coastguard Worker 		 !strcmp(raw, "Default"))) {
801*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_ERR, "expected  ModifierGroup declaration on line %d", lineno);
802*2d543d20SAndroid Build Coastguard Worker 		return -1;
803*2d543d20SAndroid Build Coastguard Worker 	}
804*2d543d20SAndroid Build Coastguard Worker 
805*2d543d20SAndroid Build Coastguard Worker 	if (!strcmp(raw, "Include")) {
806*2d543d20SAndroid Build Coastguard Worker 		unsigned int n;
807*2d543d20SAndroid Build Coastguard Worker 		glob_t g;
808*2d543d20SAndroid Build Coastguard Worker 		g.gl_offs = 0;
809*2d543d20SAndroid Build Coastguard Worker 		if (glob(tok, GLOB_ERR, NULL, &g) < 0) {
810*2d543d20SAndroid Build Coastguard Worker 			globfree(&g);
811*2d543d20SAndroid Build Coastguard Worker 			return -1;
812*2d543d20SAndroid Build Coastguard Worker 		}
813*2d543d20SAndroid Build Coastguard Worker 		for (n=0; n < g.gl_pathc; n++) {
814*2d543d20SAndroid Build Coastguard Worker 			if (read_translations(g.gl_pathv[n]) < 0) {
815*2d543d20SAndroid Build Coastguard Worker 				globfree(&g);
816*2d543d20SAndroid Build Coastguard Worker 				return -1;
817*2d543d20SAndroid Build Coastguard Worker 			}
818*2d543d20SAndroid Build Coastguard Worker 		}
819*2d543d20SAndroid Build Coastguard Worker 		globfree(&g);
820*2d543d20SAndroid Build Coastguard Worker 	} else if (!strcmp(raw, "Base")) {
821*2d543d20SAndroid Build Coastguard Worker 		base_classification = 1;
822*2d543d20SAndroid Build Coastguard Worker 	} else if (!strcmp(raw, "ModifierGroup")) {
823*2d543d20SAndroid Build Coastguard Worker 		group = create_group(&domain->groups, tok);
824*2d543d20SAndroid Build Coastguard Worker 		if (!group)
825*2d543d20SAndroid Build Coastguard Worker 			return -1;
826*2d543d20SAndroid Build Coastguard Worker 		base_classification = 0;
827*2d543d20SAndroid Build Coastguard Worker 	} else if (!strcmp(raw, "Whitespace")) {
828*2d543d20SAndroid Build Coastguard Worker 		if (update (&group->whitespace, tok) < 0)
829*2d543d20SAndroid Build Coastguard Worker 			return -1;
830*2d543d20SAndroid Build Coastguard Worker 	} else if (!strcmp(raw, "Join")) {
831*2d543d20SAndroid Build Coastguard Worker 		if (update (&group->join, tok) < 0)
832*2d543d20SAndroid Build Coastguard Worker 			return -1;
833*2d543d20SAndroid Build Coastguard Worker 	} else if (!strcmp(raw, "Prefix")) {
834*2d543d20SAndroid Build Coastguard Worker 		if (append (&group->prefixes, tok) < 0)
835*2d543d20SAndroid Build Coastguard Worker 			return -1;
836*2d543d20SAndroid Build Coastguard Worker 	} else if (!strcmp(raw, "Suffix")) {
837*2d543d20SAndroid Build Coastguard Worker 		if (append (&group->suffixes, tok) < 0)
838*2d543d20SAndroid Build Coastguard Worker 			return -1;
839*2d543d20SAndroid Build Coastguard Worker 	} else if (!strcmp(raw, "Default")) {
840*2d543d20SAndroid Build Coastguard Worker 		ebitmap_t empty;
841*2d543d20SAndroid Build Coastguard Worker 		ebitmap_init(&empty);
842*2d543d20SAndroid Build Coastguard Worker 		if (parse_ebitmap(&group->def, &empty, tok) < 0) {
843*2d543d20SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "unable to parse Default %d", lineno);
844*2d543d20SAndroid Build Coastguard Worker 			return -1;
845*2d543d20SAndroid Build Coastguard Worker 		}
846*2d543d20SAndroid Build Coastguard Worker 	} else if (group) {
847*2d543d20SAndroid Build Coastguard Worker 		if (add_word(group, raw, tok) < 0) {
848*2d543d20SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "unable to add base_classification on line %d", lineno);
849*2d543d20SAndroid Build Coastguard Worker 			return -1;
850*2d543d20SAndroid Build Coastguard Worker 		}
851*2d543d20SAndroid Build Coastguard Worker 	} else {
852*2d543d20SAndroid Build Coastguard Worker 		if (base_classification) {
853*2d543d20SAndroid Build Coastguard Worker 			if (add_base_classification(domain, raw, tok) < 0) {
854*2d543d20SAndroid Build Coastguard Worker 				syslog(LOG_ERR, "unable to add base_classification on line %d", lineno);
855*2d543d20SAndroid Build Coastguard Worker 				return -1;
856*2d543d20SAndroid Build Coastguard Worker 			}
857*2d543d20SAndroid Build Coastguard Worker 		}
858*2d543d20SAndroid Build Coastguard Worker 		if (add_cache(domain, raw, tok) < 0)
859*2d543d20SAndroid Build Coastguard Worker 			return -1;
860*2d543d20SAndroid Build Coastguard Worker 	}
861*2d543d20SAndroid Build Coastguard Worker 	return 0;
862*2d543d20SAndroid Build Coastguard Worker }
863*2d543d20SAndroid Build Coastguard Worker 
864*2d543d20SAndroid Build Coastguard Worker int
read_translations(const char * filename)865*2d543d20SAndroid Build Coastguard Worker read_translations(const char *filename) {
866*2d543d20SAndroid Build Coastguard Worker 	size_t size = 0;
867*2d543d20SAndroid Build Coastguard Worker 	char *buffer = NULL;
868*2d543d20SAndroid Build Coastguard Worker 	int rval = 0;
869*2d543d20SAndroid Build Coastguard Worker 
870*2d543d20SAndroid Build Coastguard Worker 	FILE *cfg = fopen(filename,"r");
871*2d543d20SAndroid Build Coastguard Worker 	if (!cfg) {
872*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_ERR, "%s file open failed", filename);
873*2d543d20SAndroid Build Coastguard Worker 		return -1;
874*2d543d20SAndroid Build Coastguard Worker 	}
875*2d543d20SAndroid Build Coastguard Worker 
876*2d543d20SAndroid Build Coastguard Worker 	__fsetlocking(cfg, FSETLOCKING_BYCALLER);
877*2d543d20SAndroid Build Coastguard Worker 	while (getline(&buffer, &size, cfg) > 0) {
878*2d543d20SAndroid Build Coastguard Worker 		if( process_trans(buffer) < 0 ) {
879*2d543d20SAndroid Build Coastguard Worker 			syslog(LOG_ERR, "%s file read failed", filename);
880*2d543d20SAndroid Build Coastguard Worker 			rval = -1;
881*2d543d20SAndroid Build Coastguard Worker 			break;
882*2d543d20SAndroid Build Coastguard Worker 		}
883*2d543d20SAndroid Build Coastguard Worker 	}
884*2d543d20SAndroid Build Coastguard Worker 	free(buffer);
885*2d543d20SAndroid Build Coastguard Worker 	fclose(cfg);
886*2d543d20SAndroid Build Coastguard Worker 	return rval;
887*2d543d20SAndroid Build Coastguard Worker }
888*2d543d20SAndroid Build Coastguard Worker 
889*2d543d20SAndroid Build Coastguard Worker int
init_translations(void)890*2d543d20SAndroid Build Coastguard Worker init_translations(void) {
891*2d543d20SAndroid Build Coastguard Worker 	if (is_selinux_mls_enabled() <= 0)
892*2d543d20SAndroid Build Coastguard Worker 		return -1;
893*2d543d20SAndroid Build Coastguard Worker 
894*2d543d20SAndroid Build Coastguard Worker 	return(read_translations(selinux_translations_path()));
895*2d543d20SAndroid Build Coastguard Worker }
896*2d543d20SAndroid Build Coastguard Worker 
897*2d543d20SAndroid Build Coastguard Worker static char *
extract_range(const char * incon)898*2d543d20SAndroid Build Coastguard Worker extract_range(const char *incon) {
899*2d543d20SAndroid Build Coastguard Worker 	context_t con = context_new(incon);
900*2d543d20SAndroid Build Coastguard Worker 	if (!con) {
901*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_ERR, "extract_range context_new(%s) failed: %s", incon, strerror(errno));
902*2d543d20SAndroid Build Coastguard Worker 		return NULL;
903*2d543d20SAndroid Build Coastguard Worker 	}
904*2d543d20SAndroid Build Coastguard Worker 
905*2d543d20SAndroid Build Coastguard Worker 	const char *range = context_range_get(con);
906*2d543d20SAndroid Build Coastguard Worker 	if (!range) {
907*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_ERR, "extract_range: context_range_get(%s) failed: %m", incon);
908*2d543d20SAndroid Build Coastguard Worker 		context_free(con);
909*2d543d20SAndroid Build Coastguard Worker 		return NULL;
910*2d543d20SAndroid Build Coastguard Worker 	}
911*2d543d20SAndroid Build Coastguard Worker 	char *r = strdup(range);
912*2d543d20SAndroid Build Coastguard Worker 	if (!r) {
913*2d543d20SAndroid Build Coastguard Worker 		log_error("extract_range: allocation error %s", strerror(errno));
914*2d543d20SAndroid Build Coastguard Worker 		return NULL;
915*2d543d20SAndroid Build Coastguard Worker 	}
916*2d543d20SAndroid Build Coastguard Worker 	context_free(con);
917*2d543d20SAndroid Build Coastguard Worker 	return r;
918*2d543d20SAndroid Build Coastguard Worker }
919*2d543d20SAndroid Build Coastguard Worker 
920*2d543d20SAndroid Build Coastguard Worker static char *
new_context_str(const char * incon,const char * range)921*2d543d20SAndroid Build Coastguard Worker new_context_str(const char *incon, const char *range) {
922*2d543d20SAndroid Build Coastguard Worker 	char *rcon = NULL;
923*2d543d20SAndroid Build Coastguard Worker 	context_t con = context_new(incon);
924*2d543d20SAndroid Build Coastguard Worker 	if (!con) {
925*2d543d20SAndroid Build Coastguard Worker 		goto exit;
926*2d543d20SAndroid Build Coastguard Worker 	}
927*2d543d20SAndroid Build Coastguard Worker 	context_range_set(con, range);
928*2d543d20SAndroid Build Coastguard Worker 	rcon = strdup(context_str(con));
929*2d543d20SAndroid Build Coastguard Worker 	context_free(con);
930*2d543d20SAndroid Build Coastguard Worker 	if (!rcon) {
931*2d543d20SAndroid Build Coastguard Worker 		goto exit;
932*2d543d20SAndroid Build Coastguard Worker 	}
933*2d543d20SAndroid Build Coastguard Worker 
934*2d543d20SAndroid Build Coastguard Worker 	return rcon;
935*2d543d20SAndroid Build Coastguard Worker 
936*2d543d20SAndroid Build Coastguard Worker exit:
937*2d543d20SAndroid Build Coastguard Worker 	log_error("new_context_str: %s %s", incon, strerror(errno));
938*2d543d20SAndroid Build Coastguard Worker 	return NULL;
939*2d543d20SAndroid Build Coastguard Worker }
940*2d543d20SAndroid Build Coastguard Worker 
941*2d543d20SAndroid Build Coastguard Worker static char *
find_in_hashtable(const char * range,domain_t * domain,context_map_node_t ** table)942*2d543d20SAndroid Build Coastguard Worker find_in_hashtable(const char *range, domain_t *domain, context_map_node_t **table) {
943*2d543d20SAndroid Build Coastguard Worker 	char *trans = NULL;
944*2d543d20SAndroid Build Coastguard Worker 	context_map_t *map = find_in_table(table, range);
945*2d543d20SAndroid Build Coastguard Worker 	if (map) {
946*2d543d20SAndroid Build Coastguard Worker 		trans = strdup((table == domain->raw_to_trans) ? map->trans: map->raw);
947*2d543d20SAndroid Build Coastguard Worker 		if (!trans) {
948*2d543d20SAndroid Build Coastguard Worker 			log_error("find_in_hashtable: allocation error %s", strerror(errno));
949*2d543d20SAndroid Build Coastguard Worker 			return NULL;
950*2d543d20SAndroid Build Coastguard Worker 		}
951*2d543d20SAndroid Build Coastguard Worker 		log_debug(" found %s in hashtable returning %s\n", range, trans);
952*2d543d20SAndroid Build Coastguard Worker 	}
953*2d543d20SAndroid Build Coastguard Worker 	return trans;
954*2d543d20SAndroid Build Coastguard Worker }
955*2d543d20SAndroid Build Coastguard Worker 
956*2d543d20SAndroid Build Coastguard Worker #define spaceship_cmp(a, b) (((a) > (b)) - ((a) < (b)))
957*2d543d20SAndroid Build Coastguard Worker 
958*2d543d20SAndroid Build Coastguard Worker static int
string_size(const void * p1,const void * p2)959*2d543d20SAndroid Build Coastguard Worker string_size(const void *p1, const void *p2) {
960*2d543d20SAndroid Build Coastguard Worker 	size_t len1 = strlen(*(const char *const *)p2);
961*2d543d20SAndroid Build Coastguard Worker 	size_t len2 = strlen(*(const char *const *)p1);
962*2d543d20SAndroid Build Coastguard Worker 	return spaceship_cmp(len1, len2);
963*2d543d20SAndroid Build Coastguard Worker }
964*2d543d20SAndroid Build Coastguard Worker 
965*2d543d20SAndroid Build Coastguard Worker static int
word_size(const void * p1,const void * p2)966*2d543d20SAndroid Build Coastguard Worker word_size(const void *p1, const void *p2) {
967*2d543d20SAndroid Build Coastguard Worker 	word_t *w1 = *(word_t **)p1;
968*2d543d20SAndroid Build Coastguard Worker 	word_t *w2 = *(word_t **)p2;
969*2d543d20SAndroid Build Coastguard Worker 	int w1_len=strlen(w1->text);
970*2d543d20SAndroid Build Coastguard Worker 	int w2_len=strlen(w2->text);
971*2d543d20SAndroid Build Coastguard Worker 	if (w1_len == w2_len)
972*2d543d20SAndroid Build Coastguard Worker 		return strcmp(w1->text, w2->text);
973*2d543d20SAndroid Build Coastguard Worker 	return spaceship_cmp(w2_len, w1_len);
974*2d543d20SAndroid Build Coastguard Worker }
975*2d543d20SAndroid Build Coastguard Worker 
976*2d543d20SAndroid Build Coastguard Worker static void
build_regexp(pcre2_code ** r,char * buffer)977*2d543d20SAndroid Build Coastguard Worker build_regexp(pcre2_code **r, char *buffer) {
978*2d543d20SAndroid Build Coastguard Worker 	int error;
979*2d543d20SAndroid Build Coastguard Worker 	PCRE2_SIZE error_offset;
980*2d543d20SAndroid Build Coastguard Worker 	if (*r)
981*2d543d20SAndroid Build Coastguard Worker 		pcre2_code_free(*r);
982*2d543d20SAndroid Build Coastguard Worker 	*r = pcre2_compile((PCRE2_SPTR8) buffer, PCRE2_ZERO_TERMINATED, PCRE2_CASELESS, &error, &error_offset, NULL);
983*2d543d20SAndroid Build Coastguard Worker 	if (!*r) {
984*2d543d20SAndroid Build Coastguard Worker 		PCRE2_UCHAR errbuf[256];
985*2d543d20SAndroid Build Coastguard Worker 		pcre2_get_error_message(error, errbuf, sizeof(errbuf));
986*2d543d20SAndroid Build Coastguard Worker 		log_error("pcre compilation of '%s' failed at offset %zu: %s\n", buffer, error_offset, errbuf);
987*2d543d20SAndroid Build Coastguard Worker 	}
988*2d543d20SAndroid Build Coastguard Worker 	buffer[0] = '\0';
989*2d543d20SAndroid Build Coastguard Worker }
990*2d543d20SAndroid Build Coastguard Worker 
991*2d543d20SAndroid Build Coastguard Worker static int
build_regexps(domain_t * domain)992*2d543d20SAndroid Build Coastguard Worker build_regexps(domain_t *domain) {
993*2d543d20SAndroid Build Coastguard Worker 	char buffer[1024 * 128];
994*2d543d20SAndroid Build Coastguard Worker 	buffer[0] = '\0';
995*2d543d20SAndroid Build Coastguard Worker 	base_classification_t *bc;
996*2d543d20SAndroid Build Coastguard Worker 	word_group_t *g;
997*2d543d20SAndroid Build Coastguard Worker 	affix_t *a;
998*2d543d20SAndroid Build Coastguard Worker 	word_t *w;
999*2d543d20SAndroid Build Coastguard Worker 	size_t n_el, i;
1000*2d543d20SAndroid Build Coastguard Worker 
1001*2d543d20SAndroid Build Coastguard Worker 	for (n_el = 0, bc = domain->base_classifications; bc; bc = bc->next) {
1002*2d543d20SAndroid Build Coastguard Worker 		n_el++;
1003*2d543d20SAndroid Build Coastguard Worker 	}
1004*2d543d20SAndroid Build Coastguard Worker 
1005*2d543d20SAndroid Build Coastguard Worker 	char **sortable = calloc(n_el, sizeof(char *));
1006*2d543d20SAndroid Build Coastguard Worker 	if (!sortable) {
1007*2d543d20SAndroid Build Coastguard Worker 		log_error("allocation error %s", strerror(errno));
1008*2d543d20SAndroid Build Coastguard Worker 		return -1;
1009*2d543d20SAndroid Build Coastguard Worker 	}
1010*2d543d20SAndroid Build Coastguard Worker 
1011*2d543d20SAndroid Build Coastguard Worker 	for (i=0, bc = domain->base_classifications; bc; bc = bc->next) {
1012*2d543d20SAndroid Build Coastguard Worker 		sortable[i++] = bc->trans;
1013*2d543d20SAndroid Build Coastguard Worker 	}
1014*2d543d20SAndroid Build Coastguard Worker 
1015*2d543d20SAndroid Build Coastguard Worker 	qsort(sortable, n_el, sizeof(char *), string_size);
1016*2d543d20SAndroid Build Coastguard Worker 
1017*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < n_el; i++) {
1018*2d543d20SAndroid Build Coastguard Worker 		strcat(buffer, sortable[i]);
1019*2d543d20SAndroid Build Coastguard Worker 		if (i < n_el) strcat(buffer,"|");
1020*2d543d20SAndroid Build Coastguard Worker 	}
1021*2d543d20SAndroid Build Coastguard Worker 
1022*2d543d20SAndroid Build Coastguard Worker 	free(sortable);
1023*2d543d20SAndroid Build Coastguard Worker 
1024*2d543d20SAndroid Build Coastguard Worker 	log_debug(">>> %s classification regexp=%s\n", domain->name, buffer);
1025*2d543d20SAndroid Build Coastguard Worker 	build_regexp(&domain->base_classification_regexp, buffer);
1026*2d543d20SAndroid Build Coastguard Worker 
1027*2d543d20SAndroid Build Coastguard Worker 	for (g = domain->groups; g; g = g->next) {
1028*2d543d20SAndroid Build Coastguard Worker 		if (g->prefixes) {
1029*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer,"(?:");
1030*2d543d20SAndroid Build Coastguard Worker 			for (a = g->prefixes; a; a = a->next) {
1031*2d543d20SAndroid Build Coastguard Worker 				strcat(buffer, a->text);
1032*2d543d20SAndroid Build Coastguard Worker 				if (a->next) strcat(buffer,"|");
1033*2d543d20SAndroid Build Coastguard Worker 			}
1034*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer,")");
1035*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer,"[ 	]+");
1036*2d543d20SAndroid Build Coastguard Worker 			log_debug(">>> %s %s prefix regexp=%s\n", domain->name, g->name, buffer);
1037*2d543d20SAndroid Build Coastguard Worker 			build_regexp(&g->prefix_regexp, buffer);
1038*2d543d20SAndroid Build Coastguard Worker 		}
1039*2d543d20SAndroid Build Coastguard Worker 
1040*2d543d20SAndroid Build Coastguard Worker 		if (g->prefixes)
1041*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer, "^");
1042*2d543d20SAndroid Build Coastguard Worker 		strcat(buffer, "(?:");
1043*2d543d20SAndroid Build Coastguard Worker 
1044*2d543d20SAndroid Build Coastguard Worker 		g->sword_len=0;
1045*2d543d20SAndroid Build Coastguard Worker 		for (w = g->words; w; w = w->next)
1046*2d543d20SAndroid Build Coastguard Worker 			g->sword_len++;
1047*2d543d20SAndroid Build Coastguard Worker 
1048*2d543d20SAndroid Build Coastguard Worker 		g->sword = calloc(g->sword_len, sizeof(word_t *));
1049*2d543d20SAndroid Build Coastguard Worker 		if (!g->sword) {
1050*2d543d20SAndroid Build Coastguard Worker 			log_error("allocation error %s", strerror(errno));
1051*2d543d20SAndroid Build Coastguard Worker 			return -1;
1052*2d543d20SAndroid Build Coastguard Worker 		}
1053*2d543d20SAndroid Build Coastguard Worker 
1054*2d543d20SAndroid Build Coastguard Worker 		i=0;
1055*2d543d20SAndroid Build Coastguard Worker 		for (w = g->words; w; w = w->next)
1056*2d543d20SAndroid Build Coastguard Worker 			g->sword[i++]=w;
1057*2d543d20SAndroid Build Coastguard Worker 
1058*2d543d20SAndroid Build Coastguard Worker 		qsort(g->sword, g->sword_len, sizeof(word_t *), word_size);
1059*2d543d20SAndroid Build Coastguard Worker 
1060*2d543d20SAndroid Build Coastguard Worker 		for (i=0; i < g->sword_len; i++) {
1061*2d543d20SAndroid Build Coastguard Worker 			if (i) strcat(buffer,"|");
1062*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer,"\\b");
1063*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer, g->sword[i]->text);
1064*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer,"\\b");
1065*2d543d20SAndroid Build Coastguard Worker 		}
1066*2d543d20SAndroid Build Coastguard Worker 
1067*2d543d20SAndroid Build Coastguard Worker 		if (g->whitespace) {
1068*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer,"|[");
1069*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer, g->whitespace);
1070*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer, "]+");
1071*2d543d20SAndroid Build Coastguard Worker 		}
1072*2d543d20SAndroid Build Coastguard Worker 
1073*2d543d20SAndroid Build Coastguard Worker 		strcat(buffer, ")+");
1074*2d543d20SAndroid Build Coastguard Worker 		if (g->suffixes)
1075*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer, "$");
1076*2d543d20SAndroid Build Coastguard Worker 
1077*2d543d20SAndroid Build Coastguard Worker 		log_debug(">>> %s %s modifier regexp=%s\n", domain->name, g->name, buffer);
1078*2d543d20SAndroid Build Coastguard Worker 		build_regexp(&g->word_regexp, buffer);
1079*2d543d20SAndroid Build Coastguard Worker 		if (g->suffixes) {
1080*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer,"[ 	]+");
1081*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer,"(?:");
1082*2d543d20SAndroid Build Coastguard Worker 			for (a = g->suffixes; a; a = a->next) {
1083*2d543d20SAndroid Build Coastguard Worker 				strcat(buffer, a->text);
1084*2d543d20SAndroid Build Coastguard Worker 				if (a->next) strcat(buffer,"|");
1085*2d543d20SAndroid Build Coastguard Worker 			}
1086*2d543d20SAndroid Build Coastguard Worker 			strcat(buffer,")");
1087*2d543d20SAndroid Build Coastguard Worker 			log_debug(">>> %s %s suffix regexp=%s\n", domain->name, g->name, buffer);
1088*2d543d20SAndroid Build Coastguard Worker 			build_regexp(&g->suffix_regexp, buffer);
1089*2d543d20SAndroid Build Coastguard Worker 		}
1090*2d543d20SAndroid Build Coastguard Worker 	}
1091*2d543d20SAndroid Build Coastguard Worker 
1092*2d543d20SAndroid Build Coastguard Worker 	return 0;
1093*2d543d20SAndroid Build Coastguard Worker }
1094*2d543d20SAndroid Build Coastguard Worker 
1095*2d543d20SAndroid Build Coastguard Worker static char *
compute_raw_from_trans(const char * level,domain_t * domain)1096*2d543d20SAndroid Build Coastguard Worker compute_raw_from_trans(const char *level, domain_t *domain) {
1097*2d543d20SAndroid Build Coastguard Worker 
1098*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
1099*2d543d20SAndroid Build Coastguard Worker 	struct timeval startTime;
1100*2d543d20SAndroid Build Coastguard Worker 	gettimeofday(&startTime, 0);
1101*2d543d20SAndroid Build Coastguard Worker #endif
1102*2d543d20SAndroid Build Coastguard Worker 
1103*2d543d20SAndroid Build Coastguard Worker 	int rc = 0;
1104*2d543d20SAndroid Build Coastguard Worker 	pcre2_match_data *match_data = NULL;
1105*2d543d20SAndroid Build Coastguard Worker 	word_group_t *g = NULL;
1106*2d543d20SAndroid Build Coastguard Worker 	char *work = NULL;
1107*2d543d20SAndroid Build Coastguard Worker 	char *r = NULL;
1108*2d543d20SAndroid Build Coastguard Worker 	char *match = NULL;
1109*2d543d20SAndroid Build Coastguard Worker 	size_t work_len;
1110*2d543d20SAndroid Build Coastguard Worker 	mls_level_t *mraw = NULL;
1111*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t set, clear, tmp;
1112*2d543d20SAndroid Build Coastguard Worker 
1113*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&set);
1114*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&clear);
1115*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&tmp);
1116*2d543d20SAndroid Build Coastguard Worker 
1117*2d543d20SAndroid Build Coastguard Worker 	work = strdup(level);
1118*2d543d20SAndroid Build Coastguard Worker 	if (!work) {
1119*2d543d20SAndroid Build Coastguard Worker 		log_error("compute_raw_from_trans: allocation error %s", strerror(errno));
1120*2d543d20SAndroid Build Coastguard Worker 		goto err;
1121*2d543d20SAndroid Build Coastguard Worker 	}
1122*2d543d20SAndroid Build Coastguard Worker 	work_len = strlen(work);
1123*2d543d20SAndroid Build Coastguard Worker 
1124*2d543d20SAndroid Build Coastguard Worker 	if (!domain->base_classification_regexp)
1125*2d543d20SAndroid Build Coastguard Worker 		if (build_regexps(domain) < 0)
1126*2d543d20SAndroid Build Coastguard Worker 			goto err;
1127*2d543d20SAndroid Build Coastguard Worker 	if (!domain->base_classification_regexp)
1128*2d543d20SAndroid Build Coastguard Worker 		goto err;
1129*2d543d20SAndroid Build Coastguard Worker 	log_debug(" compute_raw_from_trans work = %s\n", work);
1130*2d543d20SAndroid Build Coastguard Worker 	match_data = pcre2_match_data_create_from_pattern(domain->base_classification_regexp, NULL);
1131*2d543d20SAndroid Build Coastguard Worker 	if (!match_data) {
1132*2d543d20SAndroid Build Coastguard Worker 		log_error("allocation error %s", strerror(errno));
1133*2d543d20SAndroid Build Coastguard Worker 		goto err;
1134*2d543d20SAndroid Build Coastguard Worker 	}
1135*2d543d20SAndroid Build Coastguard Worker 	rc = pcre2_match(domain->base_classification_regexp, (PCRE2_SPTR8)work, work_len, 0, PCRE2_ANCHORED, match_data, NULL);
1136*2d543d20SAndroid Build Coastguard Worker 	if (rc > 0) {
1137*2d543d20SAndroid Build Coastguard Worker 		const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
1138*2d543d20SAndroid Build Coastguard Worker 		match = strndup(work + ovector[0], ovector[1] - ovector[0]);
1139*2d543d20SAndroid Build Coastguard Worker 		if (!match) {
1140*2d543d20SAndroid Build Coastguard Worker 			log_error("allocation error %s", strerror(errno));
1141*2d543d20SAndroid Build Coastguard Worker 			goto err;
1142*2d543d20SAndroid Build Coastguard Worker 		}
1143*2d543d20SAndroid Build Coastguard Worker 		log_debug(" compute_raw_from_trans match = %s len = %zu\n", match, strlen(match));
1144*2d543d20SAndroid Build Coastguard Worker 		base_classification_t *bc;
1145*2d543d20SAndroid Build Coastguard Worker 		for (bc = domain->base_classifications; bc; bc = bc->next) {
1146*2d543d20SAndroid Build Coastguard Worker 			if (!strcmp(bc->trans, match)) {
1147*2d543d20SAndroid Build Coastguard Worker 				log_debug(" compute_raw_from_trans base classification %s matched %s\n", level, bc->trans);
1148*2d543d20SAndroid Build Coastguard Worker 				mraw = malloc(sizeof(mls_level_t));
1149*2d543d20SAndroid Build Coastguard Worker 				if (!mraw) {
1150*2d543d20SAndroid Build Coastguard Worker 					log_error("allocation error %s", strerror(errno));
1151*2d543d20SAndroid Build Coastguard Worker 					goto err;
1152*2d543d20SAndroid Build Coastguard Worker 				}
1153*2d543d20SAndroid Build Coastguard Worker 				if (mls_level_cpy(mraw, bc->level) < 0)
1154*2d543d20SAndroid Build Coastguard Worker 					goto err;
1155*2d543d20SAndroid Build Coastguard Worker 				break;
1156*2d543d20SAndroid Build Coastguard Worker 			}
1157*2d543d20SAndroid Build Coastguard Worker 		}
1158*2d543d20SAndroid Build Coastguard Worker 
1159*2d543d20SAndroid Build Coastguard Worker 		memset(work + ovector[0], '#', ovector[1] - ovector[0]);
1160*2d543d20SAndroid Build Coastguard Worker 		char *p=work + ovector[0] + ovector[1];
1161*2d543d20SAndroid Build Coastguard Worker 		while (*p && (strchr(" 	", *p) != NULL))
1162*2d543d20SAndroid Build Coastguard Worker 			*p++ = '#';
1163*2d543d20SAndroid Build Coastguard Worker 
1164*2d543d20SAndroid Build Coastguard Worker 		free(match);
1165*2d543d20SAndroid Build Coastguard Worker 		match = NULL;
1166*2d543d20SAndroid Build Coastguard Worker 	} else {
1167*2d543d20SAndroid Build Coastguard Worker 		switch (rc) {
1168*2d543d20SAndroid Build Coastguard Worker 		case PCRE2_ERROR_NOMATCH:
1169*2d543d20SAndroid Build Coastguard Worker 			log_debug(" compute_raw_from_trans no base classification matched %s\n", level);
1170*2d543d20SAndroid Build Coastguard Worker 			break;
1171*2d543d20SAndroid Build Coastguard Worker 		default:
1172*2d543d20SAndroid Build Coastguard Worker 			log_error("compute_raw_from_trans: base matching error for input '%s': %d\n", level, rc);
1173*2d543d20SAndroid Build Coastguard Worker 			break;
1174*2d543d20SAndroid Build Coastguard Worker 		}
1175*2d543d20SAndroid Build Coastguard Worker 	}
1176*2d543d20SAndroid Build Coastguard Worker 
1177*2d543d20SAndroid Build Coastguard Worker 	pcre2_match_data_free(match_data);
1178*2d543d20SAndroid Build Coastguard Worker 	match_data = NULL;
1179*2d543d20SAndroid Build Coastguard Worker 
1180*2d543d20SAndroid Build Coastguard Worker 	if (mraw == NULL) {
1181*2d543d20SAndroid Build Coastguard Worker 		goto err;
1182*2d543d20SAndroid Build Coastguard Worker 	}
1183*2d543d20SAndroid Build Coastguard Worker 
1184*2d543d20SAndroid Build Coastguard Worker 	int complete = 0;
1185*2d543d20SAndroid Build Coastguard Worker 	int change = 1;
1186*2d543d20SAndroid Build Coastguard Worker 	while(change && !complete) {
1187*2d543d20SAndroid Build Coastguard Worker 		change = 0;
1188*2d543d20SAndroid Build Coastguard Worker 		for (g = domain->groups; g && !change && !complete; g = g->next) {
1189*2d543d20SAndroid Build Coastguard Worker 			int prefix = 0, suffix = 0;
1190*2d543d20SAndroid Build Coastguard Worker 			PCRE2_SIZE prefix_offset = 0, prefix_len = 0;
1191*2d543d20SAndroid Build Coastguard Worker 			PCRE2_SIZE suffix_offset = 0, suffix_len = 0;
1192*2d543d20SAndroid Build Coastguard Worker 			if (g->prefix_regexp) {
1193*2d543d20SAndroid Build Coastguard Worker 				match_data = pcre2_match_data_create_from_pattern(g->prefix_regexp, NULL);
1194*2d543d20SAndroid Build Coastguard Worker 				if (!match_data) {
1195*2d543d20SAndroid Build Coastguard Worker 					log_error("allocation error %s", strerror(errno));
1196*2d543d20SAndroid Build Coastguard Worker 					goto err;
1197*2d543d20SAndroid Build Coastguard Worker 				}
1198*2d543d20SAndroid Build Coastguard Worker 				rc = pcre2_match(g->prefix_regexp, (PCRE2_SPTR8)work, work_len, 0, 0, match_data, NULL);
1199*2d543d20SAndroid Build Coastguard Worker 				if (rc > 0) {
1200*2d543d20SAndroid Build Coastguard Worker 					const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
1201*2d543d20SAndroid Build Coastguard Worker 					prefix = 1;
1202*2d543d20SAndroid Build Coastguard Worker 					prefix_offset = ovector[0];
1203*2d543d20SAndroid Build Coastguard Worker 					prefix_len = ovector[1] - ovector[0];
1204*2d543d20SAndroid Build Coastguard Worker 				} else if (rc != PCRE2_ERROR_NOMATCH) {
1205*2d543d20SAndroid Build Coastguard Worker 					log_error("compute_raw_from_trans: prefix matching error for input '%s': %d\n", level, rc);
1206*2d543d20SAndroid Build Coastguard Worker 				}
1207*2d543d20SAndroid Build Coastguard Worker 				pcre2_match_data_free(match_data);
1208*2d543d20SAndroid Build Coastguard Worker 				match_data = NULL;
1209*2d543d20SAndroid Build Coastguard Worker 			}
1210*2d543d20SAndroid Build Coastguard Worker 			if (g->suffix_regexp) {
1211*2d543d20SAndroid Build Coastguard Worker 				match_data = pcre2_match_data_create_from_pattern(g->suffix_regexp, NULL);
1212*2d543d20SAndroid Build Coastguard Worker 				if (!match_data) {
1213*2d543d20SAndroid Build Coastguard Worker 					log_error("allocation error %s", strerror(errno));
1214*2d543d20SAndroid Build Coastguard Worker 					goto err;
1215*2d543d20SAndroid Build Coastguard Worker 				}
1216*2d543d20SAndroid Build Coastguard Worker 				rc = pcre2_match(g->suffix_regexp, (PCRE2_SPTR8)work, work_len, 0, 0, match_data, NULL);
1217*2d543d20SAndroid Build Coastguard Worker 				if (rc > 0) {
1218*2d543d20SAndroid Build Coastguard Worker 					const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
1219*2d543d20SAndroid Build Coastguard Worker 					suffix = 1;
1220*2d543d20SAndroid Build Coastguard Worker 					suffix_offset = ovector[0];
1221*2d543d20SAndroid Build Coastguard Worker 					suffix_len = ovector[1] - ovector[0];
1222*2d543d20SAndroid Build Coastguard Worker 				} else if (rc != PCRE2_ERROR_NOMATCH) {
1223*2d543d20SAndroid Build Coastguard Worker 					log_error("compute_raw_from_trans: suffix matching error for input '%s': %d\n", level, rc);
1224*2d543d20SAndroid Build Coastguard Worker 				}
1225*2d543d20SAndroid Build Coastguard Worker 				pcre2_match_data_free(match_data);
1226*2d543d20SAndroid Build Coastguard Worker 				match_data = NULL;
1227*2d543d20SAndroid Build Coastguard Worker 			}
1228*2d543d20SAndroid Build Coastguard Worker 
1229*2d543d20SAndroid Build Coastguard Worker /* anchors prefix ^, suffix $ */
1230*2d543d20SAndroid Build Coastguard Worker 			if (((!g->prefixes && !g->suffixes) ||
1231*2d543d20SAndroid Build Coastguard Worker 			     (g->prefixes && prefix) ||
1232*2d543d20SAndroid Build Coastguard Worker 			     (g->suffixes && suffix)) &&
1233*2d543d20SAndroid Build Coastguard Worker 			     g->word_regexp) {
1234*2d543d20SAndroid Build Coastguard Worker 				char *s = work + prefix_offset + prefix_len;
1235*2d543d20SAndroid Build Coastguard Worker 				PCRE2_SIZE len = (suffix_len ? suffix_offset : work_len) - prefix_len - prefix_offset;
1236*2d543d20SAndroid Build Coastguard Worker 				match_data = pcre2_match_data_create_from_pattern(g->word_regexp, NULL);
1237*2d543d20SAndroid Build Coastguard Worker 				if (!match_data) {
1238*2d543d20SAndroid Build Coastguard Worker 					log_error("allocation error %s", strerror(errno));
1239*2d543d20SAndroid Build Coastguard Worker 					goto err;
1240*2d543d20SAndroid Build Coastguard Worker 				}
1241*2d543d20SAndroid Build Coastguard Worker 				rc = pcre2_match(g->word_regexp, (PCRE2_SPTR8)s, len, 0, 0, match_data, NULL);
1242*2d543d20SAndroid Build Coastguard Worker 				if (rc > 0) {
1243*2d543d20SAndroid Build Coastguard Worker 					const PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(match_data);
1244*2d543d20SAndroid Build Coastguard Worker 					match = strndup(s + ovector[0], ovector[1] - ovector[0]);
1245*2d543d20SAndroid Build Coastguard Worker 					if (!match) {
1246*2d543d20SAndroid Build Coastguard Worker 						log_error("allocation error %s", strerror(errno));
1247*2d543d20SAndroid Build Coastguard Worker 						goto err;
1248*2d543d20SAndroid Build Coastguard Worker 					}
1249*2d543d20SAndroid Build Coastguard Worker 					trim(match, g->whitespace);
1250*2d543d20SAndroid Build Coastguard Worker 					if (*match) {
1251*2d543d20SAndroid Build Coastguard Worker 						char *p = triml(match, g->whitespace);
1252*2d543d20SAndroid Build Coastguard Worker 						while (p && *p) {
1253*2d543d20SAndroid Build Coastguard Worker 							int plen = strlen(p);
1254*2d543d20SAndroid Build Coastguard Worker 							unsigned int i;
1255*2d543d20SAndroid Build Coastguard Worker 							for (i = 0; i < g->sword_len; i++) {
1256*2d543d20SAndroid Build Coastguard Worker 								word_t *w = g->sword[i];
1257*2d543d20SAndroid Build Coastguard Worker 								int wlen = strlen(w->text);
1258*2d543d20SAndroid Build Coastguard Worker 								if (plen >= wlen && !strncmp(w->text, p, strlen(w->text))){
1259*2d543d20SAndroid Build Coastguard Worker 									if (ebitmap_andnot(&set, &w->cat, &g->def, maxbit) < 0) goto err;
1260*2d543d20SAndroid Build Coastguard Worker 
1261*2d543d20SAndroid Build Coastguard Worker 									if (ebitmap_xor(&tmp, &w->cat, &g->def) < 0) goto err;
1262*2d543d20SAndroid Build Coastguard Worker 									if (ebitmap_and(&clear, &tmp, &g->def) < 0) goto err;
1263*2d543d20SAndroid Build Coastguard Worker 									if (ebitmap_union(&mraw->cat, &set) < 0) goto err;
1264*2d543d20SAndroid Build Coastguard Worker 
1265*2d543d20SAndroid Build Coastguard Worker 									ebitmap_destroy(&tmp);
1266*2d543d20SAndroid Build Coastguard Worker 									if (ebitmap_cpy(&tmp, &mraw->cat) < 0) goto err;
1267*2d543d20SAndroid Build Coastguard Worker 									ebitmap_destroy(&mraw->cat);
1268*2d543d20SAndroid Build Coastguard Worker 									if (ebitmap_andnot(&mraw->cat, &tmp, &clear, maxbit) < 0) goto err;
1269*2d543d20SAndroid Build Coastguard Worker 
1270*2d543d20SAndroid Build Coastguard Worker 									ebitmap_destroy(&tmp);
1271*2d543d20SAndroid Build Coastguard Worker 									ebitmap_destroy(&set);
1272*2d543d20SAndroid Build Coastguard Worker 									ebitmap_destroy(&clear);
1273*2d543d20SAndroid Build Coastguard Worker 									p += strlen(w->text);
1274*2d543d20SAndroid Build Coastguard Worker 									change++;
1275*2d543d20SAndroid Build Coastguard Worker 									break;
1276*2d543d20SAndroid Build Coastguard Worker 								}
1277*2d543d20SAndroid Build Coastguard Worker 							}
1278*2d543d20SAndroid Build Coastguard Worker 							if (i == g->sword_len) {
1279*2d543d20SAndroid Build Coastguard Worker 								syslog(LOG_ERR, "conversion error");
1280*2d543d20SAndroid Build Coastguard Worker 								break;
1281*2d543d20SAndroid Build Coastguard Worker 							}
1282*2d543d20SAndroid Build Coastguard Worker 							p = triml(p, g->whitespace);
1283*2d543d20SAndroid Build Coastguard Worker 						}
1284*2d543d20SAndroid Build Coastguard Worker 						memset(work + prefix_offset, '#', prefix_len);
1285*2d543d20SAndroid Build Coastguard Worker 						memset(work + suffix_offset, '#', suffix_len);
1286*2d543d20SAndroid Build Coastguard Worker 						memset(s + ovector[0], '#', ovector[1] - ovector[0]);
1287*2d543d20SAndroid Build Coastguard Worker 					}
1288*2d543d20SAndroid Build Coastguard Worker 					free(match);
1289*2d543d20SAndroid Build Coastguard Worker 					match = NULL;
1290*2d543d20SAndroid Build Coastguard Worker 				} else if (rc != PCRE2_ERROR_NOMATCH) {
1291*2d543d20SAndroid Build Coastguard Worker 					log_error("compute_raw_from_trans: word matching error for input '%s' for substring '%s': %d\n", level, s, rc);
1292*2d543d20SAndroid Build Coastguard Worker 				}
1293*2d543d20SAndroid Build Coastguard Worker 				pcre2_match_data_free(match_data);
1294*2d543d20SAndroid Build Coastguard Worker 				match_data = NULL;
1295*2d543d20SAndroid Build Coastguard Worker 			}
1296*2d543d20SAndroid Build Coastguard Worker /* YYY */
1297*2d543d20SAndroid Build Coastguard Worker 			complete=1;
1298*2d543d20SAndroid Build Coastguard Worker 			char *p = work;
1299*2d543d20SAndroid Build Coastguard Worker 			while(*p) {
1300*2d543d20SAndroid Build Coastguard Worker 				if (isalnum(*p++)) {
1301*2d543d20SAndroid Build Coastguard Worker 					complete=0;
1302*2d543d20SAndroid Build Coastguard Worker 					break;
1303*2d543d20SAndroid Build Coastguard Worker 				}
1304*2d543d20SAndroid Build Coastguard Worker 			}
1305*2d543d20SAndroid Build Coastguard Worker 		}
1306*2d543d20SAndroid Build Coastguard Worker 	}
1307*2d543d20SAndroid Build Coastguard Worker 	free(work);
1308*2d543d20SAndroid Build Coastguard Worker 	if (violates_constraints(mraw)) {
1309*2d543d20SAndroid Build Coastguard Worker 		complete = 0;
1310*2d543d20SAndroid Build Coastguard Worker 	}
1311*2d543d20SAndroid Build Coastguard Worker 	if (complete)
1312*2d543d20SAndroid Build Coastguard Worker 		r = mls_level_to_string(mraw);
1313*2d543d20SAndroid Build Coastguard Worker 	mls_level_destroy(mraw);
1314*2d543d20SAndroid Build Coastguard Worker 	free(mraw);
1315*2d543d20SAndroid Build Coastguard Worker 
1316*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
1317*2d543d20SAndroid Build Coastguard Worker 	struct timeval stopTime;
1318*2d543d20SAndroid Build Coastguard Worker 	gettimeofday(&stopTime, 0);
1319*2d543d20SAndroid Build Coastguard Worker 	long int ms;
1320*2d543d20SAndroid Build Coastguard Worker 	if (startTime.tv_usec > stopTime.tv_usec)
1321*2d543d20SAndroid Build Coastguard Worker 		ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
1322*2d543d20SAndroid Build Coastguard Worker 	else
1323*2d543d20SAndroid Build Coastguard Worker 		ms = (stopTime.tv_sec - startTime.tv_sec    ) * 1000 + (stopTime.tv_usec/1000        - startTime.tv_usec/1000);
1324*2d543d20SAndroid Build Coastguard Worker 	log_debug(" compute_raw_from_trans in %ld ms'\n", ms);
1325*2d543d20SAndroid Build Coastguard Worker #endif
1326*2d543d20SAndroid Build Coastguard Worker 
1327*2d543d20SAndroid Build Coastguard Worker 	return r;
1328*2d543d20SAndroid Build Coastguard Worker 
1329*2d543d20SAndroid Build Coastguard Worker err:
1330*2d543d20SAndroid Build Coastguard Worker 	mls_level_destroy(mraw);
1331*2d543d20SAndroid Build Coastguard Worker 	free(mraw);
1332*2d543d20SAndroid Build Coastguard Worker 	free(work);
1333*2d543d20SAndroid Build Coastguard Worker 	free(match);
1334*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&tmp);
1335*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&set);
1336*2d543d20SAndroid Build Coastguard Worker 	ebitmap_destroy(&clear);
1337*2d543d20SAndroid Build Coastguard Worker 	pcre2_match_data_free(match_data);
1338*2d543d20SAndroid Build Coastguard Worker 	return NULL;
1339*2d543d20SAndroid Build Coastguard Worker }
1340*2d543d20SAndroid Build Coastguard Worker 
1341*2d543d20SAndroid Build Coastguard Worker static char *
compute_trans_from_raw(const char * level,domain_t * domain)1342*2d543d20SAndroid Build Coastguard Worker compute_trans_from_raw(const char *level, domain_t *domain) {
1343*2d543d20SAndroid Build Coastguard Worker 
1344*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
1345*2d543d20SAndroid Build Coastguard Worker 	struct timeval startTime;
1346*2d543d20SAndroid Build Coastguard Worker 	gettimeofday(&startTime, 0);
1347*2d543d20SAndroid Build Coastguard Worker #endif
1348*2d543d20SAndroid Build Coastguard Worker 
1349*2d543d20SAndroid Build Coastguard Worker 	word_group_t *g;
1350*2d543d20SAndroid Build Coastguard Worker 	mls_level_t *l = NULL;
1351*2d543d20SAndroid Build Coastguard Worker 	char *rval = NULL;
1352*2d543d20SAndroid Build Coastguard Worker 	word_group_t *groups = NULL;
1353*2d543d20SAndroid Build Coastguard Worker 	ebitmap_t bit_diff, temp, handled, nothandled, unhandled, orig_unhandled;
1354*2d543d20SAndroid Build Coastguard Worker 
1355*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&bit_diff);
1356*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&temp);
1357*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&handled);
1358*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&nothandled);
1359*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&unhandled);
1360*2d543d20SAndroid Build Coastguard Worker 	ebitmap_init(&orig_unhandled);
1361*2d543d20SAndroid Build Coastguard Worker 
1362*2d543d20SAndroid Build Coastguard Worker 	if (!level)
1363*2d543d20SAndroid Build Coastguard Worker 		goto err;
1364*2d543d20SAndroid Build Coastguard Worker 
1365*2d543d20SAndroid Build Coastguard Worker 	l = parse_raw(level);
1366*2d543d20SAndroid Build Coastguard Worker 	if (!l)
1367*2d543d20SAndroid Build Coastguard Worker 		goto err;
1368*2d543d20SAndroid Build Coastguard Worker 	log_debug(" compute_trans_from_raw raw = %s\n", level);
1369*2d543d20SAndroid Build Coastguard Worker 
1370*2d543d20SAndroid Build Coastguard Worker /* YYY */
1371*2d543d20SAndroid Build Coastguard Worker 	/* check constraints */
1372*2d543d20SAndroid Build Coastguard Worker 	if (violates_constraints(l)) {
1373*2d543d20SAndroid Build Coastguard Worker 		syslog(LOG_ERR, "%s violates constraints", level);
1374*2d543d20SAndroid Build Coastguard Worker 		goto err;
1375*2d543d20SAndroid Build Coastguard Worker 	}
1376*2d543d20SAndroid Build Coastguard Worker 
1377*2d543d20SAndroid Build Coastguard Worker 	int doInverse = l->sens > 0;
1378*2d543d20SAndroid Build Coastguard Worker 
1379*2d543d20SAndroid Build Coastguard Worker 	base_classification_t *bc, *last = NULL;
1380*2d543d20SAndroid Build Coastguard Worker 	int done = 0;
1381*2d543d20SAndroid Build Coastguard Worker 	for (bc = domain->base_classifications; bc && !done; bc = bc->next) {
1382*2d543d20SAndroid Build Coastguard Worker 		if (l->sens == bc->level->sens) {
1383*2d543d20SAndroid Build Coastguard Worker 			/* skip if alias of last bc */
1384*2d543d20SAndroid Build Coastguard Worker 			if (last &&
1385*2d543d20SAndroid Build Coastguard Worker 			    last->level->sens == bc->level->sens &&
1386*2d543d20SAndroid Build Coastguard Worker 			    ebitmap_cmp(&last->level->cat, &bc->level->cat) == 0)
1387*2d543d20SAndroid Build Coastguard Worker 				continue;
1388*2d543d20SAndroid Build Coastguard Worker 
1389*2d543d20SAndroid Build Coastguard Worker 			/* compute bits not consumed by base classification */
1390*2d543d20SAndroid Build Coastguard Worker 			if (ebitmap_xor(&unhandled, &l->cat, &bc->level->cat) < 0)
1391*2d543d20SAndroid Build Coastguard Worker 				goto err;
1392*2d543d20SAndroid Build Coastguard Worker 			if (ebitmap_cpy(&orig_unhandled, &unhandled) < 0)
1393*2d543d20SAndroid Build Coastguard Worker 				goto err;
1394*2d543d20SAndroid Build Coastguard Worker 
1395*2d543d20SAndroid Build Coastguard Worker 			/* prebuild groups */
1396*2d543d20SAndroid Build Coastguard Worker 			for (g = domain->groups; g; g = g->next) {
1397*2d543d20SAndroid Build Coastguard Worker 				word_group_t **t;
1398*2d543d20SAndroid Build Coastguard Worker 				for (t = &groups; *t; t = &(*t)->next)
1399*2d543d20SAndroid Build Coastguard Worker 					if (!strcmp(g->name, (*t)->name))
1400*2d543d20SAndroid Build Coastguard Worker 						break;
1401*2d543d20SAndroid Build Coastguard Worker 
1402*2d543d20SAndroid Build Coastguard Worker 				if (! *t) {
1403*2d543d20SAndroid Build Coastguard Worker 					word_group_t *wg = create_group(&groups, g->name);
1404*2d543d20SAndroid Build Coastguard Worker 					if (g->prefixes)
1405*2d543d20SAndroid Build Coastguard Worker 						if (append(&wg->prefixes, g->prefixes->text) < 0)
1406*2d543d20SAndroid Build Coastguard Worker 							goto err;
1407*2d543d20SAndroid Build Coastguard Worker 					if (g->suffixes)
1408*2d543d20SAndroid Build Coastguard Worker 						if (append(&wg->suffixes, g->suffixes->text) < 0)
1409*2d543d20SAndroid Build Coastguard Worker 							goto err;
1410*2d543d20SAndroid Build Coastguard Worker 					if (g->join)
1411*2d543d20SAndroid Build Coastguard Worker 						if (update(&wg->join, g->join) < 0)
1412*2d543d20SAndroid Build Coastguard Worker 							goto err;
1413*2d543d20SAndroid Build Coastguard Worker 				}
1414*2d543d20SAndroid Build Coastguard Worker 			}
1415*2d543d20SAndroid Build Coastguard Worker 
1416*2d543d20SAndroid Build Coastguard Worker 			int loops, hamming, change=1;
1417*2d543d20SAndroid Build Coastguard Worker 			for (loops = 50; ebitmap_cardinality(&unhandled) && loops > 0 && change; loops--) {
1418*2d543d20SAndroid Build Coastguard Worker 				change = 0;
1419*2d543d20SAndroid Build Coastguard Worker 				hamming = 10000;
1420*2d543d20SAndroid Build Coastguard Worker 				if (ebitmap_xor(&handled, &unhandled, &orig_unhandled) < 0)
1421*2d543d20SAndroid Build Coastguard Worker 					goto err;
1422*2d543d20SAndroid Build Coastguard Worker 				if (ebitmap_not(&nothandled, &handled, maxbit) < 0)
1423*2d543d20SAndroid Build Coastguard Worker 					goto err;
1424*2d543d20SAndroid Build Coastguard Worker 				word_group_t *currentGroup = NULL;
1425*2d543d20SAndroid Build Coastguard Worker 				word_t *currentWord = NULL;
1426*2d543d20SAndroid Build Coastguard Worker 				for (g = domain->groups; g && hamming; g = g->next) {
1427*2d543d20SAndroid Build Coastguard Worker 					word_t *w;
1428*2d543d20SAndroid Build Coastguard Worker 					for (w = g->words; w && hamming; w = w->next) {
1429*2d543d20SAndroid Build Coastguard Worker 						int cardinality = ebitmap_cardinality(&w->normal);
1430*2d543d20SAndroid Build Coastguard Worker 						/* If the word is all inverse bits and the level does not have inverse bits - skip */
1431*2d543d20SAndroid Build Coastguard Worker 						if (cardinality && !doInverse) {
1432*2d543d20SAndroid Build Coastguard Worker 							continue;
1433*2d543d20SAndroid Build Coastguard Worker 						}
1434*2d543d20SAndroid Build Coastguard Worker 
1435*2d543d20SAndroid Build Coastguard Worker 						/* if only unhandled bits are different */
1436*2d543d20SAndroid Build Coastguard Worker 						if (ebitmap_or(&temp, &w->normal, &w->inverse) < 0)
1437*2d543d20SAndroid Build Coastguard Worker 							goto err;
1438*2d543d20SAndroid Build Coastguard Worker 						if (ebitmap_and(&bit_diff, &temp, &nothandled) < 0)
1439*2d543d20SAndroid Build Coastguard Worker 							goto err;
1440*2d543d20SAndroid Build Coastguard Worker 						ebitmap_destroy(&temp);
1441*2d543d20SAndroid Build Coastguard Worker // xor bit_diff handled?
1442*2d543d20SAndroid Build Coastguard Worker 						if (ebitmap_and(&temp, &bit_diff, &unhandled) < 0)
1443*2d543d20SAndroid Build Coastguard Worker 							goto err;
1444*2d543d20SAndroid Build Coastguard Worker 						if (ebitmap_cmp(&bit_diff, &temp)) {
1445*2d543d20SAndroid Build Coastguard Worker 							int h = ebitmap_hamming_distance(&bit_diff, &unhandled);
1446*2d543d20SAndroid Build Coastguard Worker 							if (h < hamming) {
1447*2d543d20SAndroid Build Coastguard Worker 								hamming = h;
1448*2d543d20SAndroid Build Coastguard Worker 								currentGroup = g;
1449*2d543d20SAndroid Build Coastguard Worker 								currentWord = w;
1450*2d543d20SAndroid Build Coastguard Worker 							}
1451*2d543d20SAndroid Build Coastguard Worker 						}
1452*2d543d20SAndroid Build Coastguard Worker 						ebitmap_destroy(&bit_diff);
1453*2d543d20SAndroid Build Coastguard Worker 						ebitmap_destroy(&temp);
1454*2d543d20SAndroid Build Coastguard Worker 					}
1455*2d543d20SAndroid Build Coastguard Worker 				}
1456*2d543d20SAndroid Build Coastguard Worker 				ebitmap_destroy(&handled);
1457*2d543d20SAndroid Build Coastguard Worker 				ebitmap_destroy(&nothandled);
1458*2d543d20SAndroid Build Coastguard Worker 
1459*2d543d20SAndroid Build Coastguard Worker 				if (currentWord) {
1460*2d543d20SAndroid Build Coastguard Worker 					if (ebitmap_xor(&bit_diff, &currentWord->cat, &bc->level->cat) < 0)
1461*2d543d20SAndroid Build Coastguard Worker 						goto err;
1462*2d543d20SAndroid Build Coastguard Worker 
1463*2d543d20SAndroid Build Coastguard Worker 					if (ebitmap_cpy(&temp, &unhandled) < 0)
1464*2d543d20SAndroid Build Coastguard Worker 						goto err;
1465*2d543d20SAndroid Build Coastguard Worker 					ebitmap_destroy(&unhandled);
1466*2d543d20SAndroid Build Coastguard Worker 					if (ebitmap_andnot(&unhandled, &temp, &bit_diff, maxbit) < 0)
1467*2d543d20SAndroid Build Coastguard Worker 						goto err;
1468*2d543d20SAndroid Build Coastguard Worker 
1469*2d543d20SAndroid Build Coastguard Worker 					ebitmap_destroy(&bit_diff);
1470*2d543d20SAndroid Build Coastguard Worker 					ebitmap_destroy(&temp);
1471*2d543d20SAndroid Build Coastguard Worker 
1472*2d543d20SAndroid Build Coastguard Worker 					word_group_t **t;
1473*2d543d20SAndroid Build Coastguard Worker 					for (t = &groups; *t; t = &(*t)->next)
1474*2d543d20SAndroid Build Coastguard Worker 						if (!strcmp(currentGroup->name, (*t)->name))
1475*2d543d20SAndroid Build Coastguard Worker 							break;
1476*2d543d20SAndroid Build Coastguard Worker 					create_word(&(*t)->words, currentWord->text);
1477*2d543d20SAndroid Build Coastguard Worker 					change++;
1478*2d543d20SAndroid Build Coastguard Worker 				}
1479*2d543d20SAndroid Build Coastguard Worker 			}
1480*2d543d20SAndroid Build Coastguard Worker 
1481*2d543d20SAndroid Build Coastguard Worker 			done = (ebitmap_cardinality(&unhandled) == 0);
1482*2d543d20SAndroid Build Coastguard Worker 			ebitmap_destroy(&unhandled);
1483*2d543d20SAndroid Build Coastguard Worker 			ebitmap_destroy(&orig_unhandled);
1484*2d543d20SAndroid Build Coastguard Worker 			if (done) {
1485*2d543d20SAndroid Build Coastguard Worker 				char buffer[9999];
1486*2d543d20SAndroid Build Coastguard Worker 				buffer[0] = 0;
1487*2d543d20SAndroid Build Coastguard Worker 				strcat(buffer, bc->trans);
1488*2d543d20SAndroid Build Coastguard Worker 				strcat(buffer, " ");
1489*2d543d20SAndroid Build Coastguard Worker 				for (g=groups; g; g = g->next) {
1490*2d543d20SAndroid Build Coastguard Worker 					if (g->words && g->prefixes) {
1491*2d543d20SAndroid Build Coastguard Worker 						strcat(buffer, g->prefixes->text);
1492*2d543d20SAndroid Build Coastguard Worker 						strcat(buffer, " ");
1493*2d543d20SAndroid Build Coastguard Worker 					}
1494*2d543d20SAndroid Build Coastguard Worker 					word_t *w;
1495*2d543d20SAndroid Build Coastguard Worker 					for (w=g->words; w; w = w->next) {
1496*2d543d20SAndroid Build Coastguard Worker 						strcat(buffer, w->text);
1497*2d543d20SAndroid Build Coastguard Worker 						if (w->next)
1498*2d543d20SAndroid Build Coastguard Worker 							strcat(buffer, g->join);
1499*2d543d20SAndroid Build Coastguard Worker 					}
1500*2d543d20SAndroid Build Coastguard Worker 					if (g->words && g->suffixes) {
1501*2d543d20SAndroid Build Coastguard Worker 						strcat(buffer, " ");
1502*2d543d20SAndroid Build Coastguard Worker 						strcat(buffer, g->suffixes->text);
1503*2d543d20SAndroid Build Coastguard Worker 					}
1504*2d543d20SAndroid Build Coastguard Worker 					word_group_t *n = g->next;
1505*2d543d20SAndroid Build Coastguard Worker 					while(g->words && n) {
1506*2d543d20SAndroid Build Coastguard Worker 						if (n->words) {
1507*2d543d20SAndroid Build Coastguard Worker 							strcat(buffer, " ");
1508*2d543d20SAndroid Build Coastguard Worker 							break;
1509*2d543d20SAndroid Build Coastguard Worker 						}
1510*2d543d20SAndroid Build Coastguard Worker 						n = n->next;
1511*2d543d20SAndroid Build Coastguard Worker 					}
1512*2d543d20SAndroid Build Coastguard Worker 				}
1513*2d543d20SAndroid Build Coastguard Worker 				rval = strdup(buffer);
1514*2d543d20SAndroid Build Coastguard Worker 				if (!rval) {
1515*2d543d20SAndroid Build Coastguard Worker 					log_error("compute_trans_from_raw: allocation error %s", strerror(errno));
1516*2d543d20SAndroid Build Coastguard Worker 					goto err;
1517*2d543d20SAndroid Build Coastguard Worker 				}
1518*2d543d20SAndroid Build Coastguard Worker 			}
1519*2d543d20SAndroid Build Coastguard Worker 			/* clean up */
1520*2d543d20SAndroid Build Coastguard Worker 			while (groups)
1521*2d543d20SAndroid Build Coastguard Worker 				destroy_group(&groups, groups);
1522*2d543d20SAndroid Build Coastguard Worker 		}
1523*2d543d20SAndroid Build Coastguard Worker 		last = bc;
1524*2d543d20SAndroid Build Coastguard Worker 	}
1525*2d543d20SAndroid Build Coastguard Worker 	if (l) {
1526*2d543d20SAndroid Build Coastguard Worker 		mls_level_destroy(l);
1527*2d543d20SAndroid Build Coastguard Worker 		free(l);
1528*2d543d20SAndroid Build Coastguard Worker 	}
1529*2d543d20SAndroid Build Coastguard Worker 
1530*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
1531*2d543d20SAndroid Build Coastguard Worker 	struct timeval stopTime;
1532*2d543d20SAndroid Build Coastguard Worker 	gettimeofday(&stopTime, 0);
1533*2d543d20SAndroid Build Coastguard Worker 	long int ms;
1534*2d543d20SAndroid Build Coastguard Worker 	if (startTime.tv_usec > stopTime.tv_usec)
1535*2d543d20SAndroid Build Coastguard Worker 		ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
1536*2d543d20SAndroid Build Coastguard Worker 	else
1537*2d543d20SAndroid Build Coastguard Worker 		ms = (stopTime.tv_sec - startTime.tv_sec    ) * 1000 + (stopTime.tv_usec/1000        - startTime.tv_usec/1000);
1538*2d543d20SAndroid Build Coastguard Worker 
1539*2d543d20SAndroid Build Coastguard Worker 	log_debug(" compute_trans_from_raw in %ld ms'\n", ms);
1540*2d543d20SAndroid Build Coastguard Worker #endif
1541*2d543d20SAndroid Build Coastguard Worker 
1542*2d543d20SAndroid Build Coastguard Worker 	return rval;
1543*2d543d20SAndroid Build Coastguard Worker 
1544*2d543d20SAndroid Build Coastguard Worker err:
1545*2d543d20SAndroid Build Coastguard Worker 	while (groups)
1546*2d543d20SAndroid Build Coastguard Worker 		destroy_group(&groups, groups);
1547*2d543d20SAndroid Build Coastguard Worker 	mls_level_destroy(l);
1548*2d543d20SAndroid Build Coastguard Worker 	free(l);
1549*2d543d20SAndroid Build Coastguard Worker 	return NULL;
1550*2d543d20SAndroid Build Coastguard Worker }
1551*2d543d20SAndroid Build Coastguard Worker 
1552*2d543d20SAndroid Build Coastguard Worker int
trans_context(const char * incon,char ** rcon)1553*2d543d20SAndroid Build Coastguard Worker trans_context(const char *incon, char **rcon) {
1554*2d543d20SAndroid Build Coastguard Worker 	char *trans = NULL;
1555*2d543d20SAndroid Build Coastguard Worker 	*rcon = NULL;
1556*2d543d20SAndroid Build Coastguard Worker 
1557*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
1558*2d543d20SAndroid Build Coastguard Worker 	struct timeval startTime;
1559*2d543d20SAndroid Build Coastguard Worker 	gettimeofday(&startTime, 0);
1560*2d543d20SAndroid Build Coastguard Worker #endif
1561*2d543d20SAndroid Build Coastguard Worker 
1562*2d543d20SAndroid Build Coastguard Worker 	log_debug(" trans_context input = %s\n", incon);
1563*2d543d20SAndroid Build Coastguard Worker 	char *range = extract_range(incon);
1564*2d543d20SAndroid Build Coastguard Worker 	if (!range) return -1;
1565*2d543d20SAndroid Build Coastguard Worker 
1566*2d543d20SAndroid Build Coastguard Worker 	domain_t *domain = domains;
1567*2d543d20SAndroid Build Coastguard Worker 	for (;domain; domain = domain->next) {
1568*2d543d20SAndroid Build Coastguard Worker 		trans = find_in_hashtable(range, domain, domain->raw_to_trans);
1569*2d543d20SAndroid Build Coastguard Worker 		if (trans) break;
1570*2d543d20SAndroid Build Coastguard Worker 
1571*2d543d20SAndroid Build Coastguard Worker 		/* try split and translate */
1572*2d543d20SAndroid Build Coastguard Worker 		char *lrange = NULL, *urange = NULL;
1573*2d543d20SAndroid Build Coastguard Worker 		char *ltrans = NULL, *utrans = NULL;
1574*2d543d20SAndroid Build Coastguard Worker 		char *dashp = strchr(range,'-');
1575*2d543d20SAndroid Build Coastguard Worker 		if (dashp) {
1576*2d543d20SAndroid Build Coastguard Worker 			*dashp = 0;
1577*2d543d20SAndroid Build Coastguard Worker 			lrange = range;
1578*2d543d20SAndroid Build Coastguard Worker 			urange = dashp+1;
1579*2d543d20SAndroid Build Coastguard Worker 		} else {
1580*2d543d20SAndroid Build Coastguard Worker 			trans = compute_trans_from_raw(range, domain);
1581*2d543d20SAndroid Build Coastguard Worker 			if (trans)
1582*2d543d20SAndroid Build Coastguard Worker 				if (add_cache(domain, range, trans) < 0) {
1583*2d543d20SAndroid Build Coastguard Worker 					free(trans);
1584*2d543d20SAndroid Build Coastguard Worker 					free(range);
1585*2d543d20SAndroid Build Coastguard Worker 					return -1;
1586*2d543d20SAndroid Build Coastguard Worker 				}
1587*2d543d20SAndroid Build Coastguard Worker 		}
1588*2d543d20SAndroid Build Coastguard Worker 
1589*2d543d20SAndroid Build Coastguard Worker 		if (lrange && urange) {
1590*2d543d20SAndroid Build Coastguard Worker 			ltrans = find_in_hashtable(lrange, domain, domain->raw_to_trans);
1591*2d543d20SAndroid Build Coastguard Worker 			if (! ltrans) {
1592*2d543d20SAndroid Build Coastguard Worker 				ltrans = compute_trans_from_raw(lrange, domain);
1593*2d543d20SAndroid Build Coastguard Worker 				if (ltrans) {
1594*2d543d20SAndroid Build Coastguard Worker 					if (add_cache(domain, lrange, ltrans) < 0) {
1595*2d543d20SAndroid Build Coastguard Worker 						free(ltrans);
1596*2d543d20SAndroid Build Coastguard Worker 						free(range);
1597*2d543d20SAndroid Build Coastguard Worker 						return -1;
1598*2d543d20SAndroid Build Coastguard Worker 					}
1599*2d543d20SAndroid Build Coastguard Worker 				} else {
1600*2d543d20SAndroid Build Coastguard Worker 					ltrans = strdup(lrange);
1601*2d543d20SAndroid Build Coastguard Worker 					if (! ltrans) {
1602*2d543d20SAndroid Build Coastguard Worker 						log_error("strdup failed %s", strerror(errno));
1603*2d543d20SAndroid Build Coastguard Worker 						free(range);
1604*2d543d20SAndroid Build Coastguard Worker 						return -1;
1605*2d543d20SAndroid Build Coastguard Worker 					}
1606*2d543d20SAndroid Build Coastguard Worker 				}
1607*2d543d20SAndroid Build Coastguard Worker 			}
1608*2d543d20SAndroid Build Coastguard Worker 
1609*2d543d20SAndroid Build Coastguard Worker 			utrans = find_in_hashtable(urange, domain, domain->raw_to_trans);
1610*2d543d20SAndroid Build Coastguard Worker 			if (! utrans) {
1611*2d543d20SAndroid Build Coastguard Worker 				utrans = compute_trans_from_raw(urange, domain);
1612*2d543d20SAndroid Build Coastguard Worker 				if (utrans) {
1613*2d543d20SAndroid Build Coastguard Worker 					if (add_cache(domain, urange, utrans) < 0) {
1614*2d543d20SAndroid Build Coastguard Worker 						free(utrans);
1615*2d543d20SAndroid Build Coastguard Worker 						free(ltrans);
1616*2d543d20SAndroid Build Coastguard Worker 						free(range);
1617*2d543d20SAndroid Build Coastguard Worker 						return -1;
1618*2d543d20SAndroid Build Coastguard Worker 					}
1619*2d543d20SAndroid Build Coastguard Worker 				} else {
1620*2d543d20SAndroid Build Coastguard Worker 					utrans = strdup(urange);
1621*2d543d20SAndroid Build Coastguard Worker 					if (! utrans) {
1622*2d543d20SAndroid Build Coastguard Worker 						log_error("strdup failed %s", strerror(errno));
1623*2d543d20SAndroid Build Coastguard Worker 						free(ltrans);
1624*2d543d20SAndroid Build Coastguard Worker 						free(range);
1625*2d543d20SAndroid Build Coastguard Worker 						return -1;
1626*2d543d20SAndroid Build Coastguard Worker 					}
1627*2d543d20SAndroid Build Coastguard Worker 				}
1628*2d543d20SAndroid Build Coastguard Worker 			}
1629*2d543d20SAndroid Build Coastguard Worker 
1630*2d543d20SAndroid Build Coastguard Worker 			if (strcmp(ltrans, utrans) == 0) {
1631*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&trans, "%s", ltrans) < 0) {
1632*2d543d20SAndroid Build Coastguard Worker 					log_error("asprintf failed %s", strerror(errno));
1633*2d543d20SAndroid Build Coastguard Worker 					free(utrans);
1634*2d543d20SAndroid Build Coastguard Worker 					free(ltrans);
1635*2d543d20SAndroid Build Coastguard Worker 					free(range);
1636*2d543d20SAndroid Build Coastguard Worker 					return -1;
1637*2d543d20SAndroid Build Coastguard Worker 				}
1638*2d543d20SAndroid Build Coastguard Worker 			} else {
1639*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&trans, "%s-%s", ltrans, utrans) < 0) {
1640*2d543d20SAndroid Build Coastguard Worker 					log_error("asprintf failed %s", strerror(errno));
1641*2d543d20SAndroid Build Coastguard Worker 					free(utrans);
1642*2d543d20SAndroid Build Coastguard Worker 					free(ltrans);
1643*2d543d20SAndroid Build Coastguard Worker 					free(range);
1644*2d543d20SAndroid Build Coastguard Worker 					return -1;
1645*2d543d20SAndroid Build Coastguard Worker 				}
1646*2d543d20SAndroid Build Coastguard Worker 			}
1647*2d543d20SAndroid Build Coastguard Worker 			free(ltrans);
1648*2d543d20SAndroid Build Coastguard Worker 			free(utrans);
1649*2d543d20SAndroid Build Coastguard Worker 			*dashp = '-';
1650*2d543d20SAndroid Build Coastguard Worker 			break;
1651*2d543d20SAndroid Build Coastguard Worker 		}
1652*2d543d20SAndroid Build Coastguard Worker 		if (dashp)
1653*2d543d20SAndroid Build Coastguard Worker 			*dashp = '-';
1654*2d543d20SAndroid Build Coastguard Worker 		if (trans) {
1655*2d543d20SAndroid Build Coastguard Worker 			free(trans);
1656*2d543d20SAndroid Build Coastguard Worker 			trans = NULL;
1657*2d543d20SAndroid Build Coastguard Worker 		}
1658*2d543d20SAndroid Build Coastguard Worker 	}
1659*2d543d20SAndroid Build Coastguard Worker 
1660*2d543d20SAndroid Build Coastguard Worker 	if (trans) {
1661*2d543d20SAndroid Build Coastguard Worker 		*rcon = new_context_str(incon, trans);
1662*2d543d20SAndroid Build Coastguard Worker 		free(trans);
1663*2d543d20SAndroid Build Coastguard Worker 	} else {
1664*2d543d20SAndroid Build Coastguard Worker 		*rcon = new_context_str(incon, range);
1665*2d543d20SAndroid Build Coastguard Worker 	}
1666*2d543d20SAndroid Build Coastguard Worker 	free(range);
1667*2d543d20SAndroid Build Coastguard Worker 
1668*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
1669*2d543d20SAndroid Build Coastguard Worker 	struct timeval stopTime;
1670*2d543d20SAndroid Build Coastguard Worker 	gettimeofday(&stopTime, 0);
1671*2d543d20SAndroid Build Coastguard Worker 	long int ms;
1672*2d543d20SAndroid Build Coastguard Worker 	if (startTime.tv_usec > stopTime.tv_usec)
1673*2d543d20SAndroid Build Coastguard Worker 		ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
1674*2d543d20SAndroid Build Coastguard Worker 	else
1675*2d543d20SAndroid Build Coastguard Worker 		ms = (stopTime.tv_sec - startTime.tv_sec    ) * 1000 + (stopTime.tv_usec/1000        - startTime.tv_usec/1000);
1676*2d543d20SAndroid Build Coastguard Worker 
1677*2d543d20SAndroid Build Coastguard Worker 	log_debug(" trans_context input='%s' output='%s in %ld ms'\n", incon, *rcon, ms);
1678*2d543d20SAndroid Build Coastguard Worker #endif
1679*2d543d20SAndroid Build Coastguard Worker 	return 0;
1680*2d543d20SAndroid Build Coastguard Worker }
1681*2d543d20SAndroid Build Coastguard Worker 
1682*2d543d20SAndroid Build Coastguard Worker int
untrans_context(const char * incon,char ** rcon)1683*2d543d20SAndroid Build Coastguard Worker untrans_context(const char *incon, char **rcon) {
1684*2d543d20SAndroid Build Coastguard Worker 	char *raw = NULL;
1685*2d543d20SAndroid Build Coastguard Worker 	*rcon = NULL;
1686*2d543d20SAndroid Build Coastguard Worker 
1687*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
1688*2d543d20SAndroid Build Coastguard Worker 	struct timeval startTime;
1689*2d543d20SAndroid Build Coastguard Worker 	gettimeofday(&startTime, 0);
1690*2d543d20SAndroid Build Coastguard Worker #endif
1691*2d543d20SAndroid Build Coastguard Worker 
1692*2d543d20SAndroid Build Coastguard Worker 	log_debug(" untrans_context incon = %s\n", incon);
1693*2d543d20SAndroid Build Coastguard Worker 	char *range = extract_range(incon);
1694*2d543d20SAndroid Build Coastguard Worker 	if (!range) return -1;
1695*2d543d20SAndroid Build Coastguard Worker 	log_debug(" untrans_context range = %s\n", range);
1696*2d543d20SAndroid Build Coastguard Worker 
1697*2d543d20SAndroid Build Coastguard Worker 	domain_t *domain = domains;
1698*2d543d20SAndroid Build Coastguard Worker 	for (;domain; domain = domain->next) {
1699*2d543d20SAndroid Build Coastguard Worker 		raw = find_in_hashtable(range, domain, domain->trans_to_raw);
1700*2d543d20SAndroid Build Coastguard Worker 		if (raw) break;
1701*2d543d20SAndroid Build Coastguard Worker 
1702*2d543d20SAndroid Build Coastguard Worker 		/* try split and translate */
1703*2d543d20SAndroid Build Coastguard Worker 		char *lrange = NULL, *urange = NULL;
1704*2d543d20SAndroid Build Coastguard Worker 		char *lraw = NULL, *uraw = NULL;
1705*2d543d20SAndroid Build Coastguard Worker 		char *dashp = strchr(range,'-');
1706*2d543d20SAndroid Build Coastguard Worker 		if (dashp) {
1707*2d543d20SAndroid Build Coastguard Worker 			*dashp = 0;
1708*2d543d20SAndroid Build Coastguard Worker 			lrange = range;
1709*2d543d20SAndroid Build Coastguard Worker 			urange = dashp+1;
1710*2d543d20SAndroid Build Coastguard Worker 		} else {
1711*2d543d20SAndroid Build Coastguard Worker 			raw = compute_raw_from_trans(range, domain);
1712*2d543d20SAndroid Build Coastguard Worker 			if (raw) {
1713*2d543d20SAndroid Build Coastguard Worker 				char *canonical = find_in_hashtable(raw, domain, domain->raw_to_trans);
1714*2d543d20SAndroid Build Coastguard Worker 				if (!canonical) {
1715*2d543d20SAndroid Build Coastguard Worker 					canonical = compute_trans_from_raw(raw, domain);
1716*2d543d20SAndroid Build Coastguard Worker 					if (canonical && strcmp(canonical, range))
1717*2d543d20SAndroid Build Coastguard Worker 						if (add_cache(domain, raw, canonical) < 0) {
1718*2d543d20SAndroid Build Coastguard Worker 							free(canonical);
1719*2d543d20SAndroid Build Coastguard Worker 							free(range);
1720*2d543d20SAndroid Build Coastguard Worker 							free(raw);
1721*2d543d20SAndroid Build Coastguard Worker 							return -1;
1722*2d543d20SAndroid Build Coastguard Worker 						}
1723*2d543d20SAndroid Build Coastguard Worker 				}
1724*2d543d20SAndroid Build Coastguard Worker 				if (canonical)
1725*2d543d20SAndroid Build Coastguard Worker 					free(canonical);
1726*2d543d20SAndroid Build Coastguard Worker 				if (add_cache(domain, raw, range) < 0) {
1727*2d543d20SAndroid Build Coastguard Worker 					free(range);
1728*2d543d20SAndroid Build Coastguard Worker 					free(raw);
1729*2d543d20SAndroid Build Coastguard Worker 					return -1;
1730*2d543d20SAndroid Build Coastguard Worker 				}
1731*2d543d20SAndroid Build Coastguard Worker 			} else {
1732*2d543d20SAndroid Build Coastguard Worker 				log_debug("untrans_context unable to compute raw context %s\n", range);
1733*2d543d20SAndroid Build Coastguard Worker 			}
1734*2d543d20SAndroid Build Coastguard Worker 		}
1735*2d543d20SAndroid Build Coastguard Worker 
1736*2d543d20SAndroid Build Coastguard Worker 		if (lrange && urange) {
1737*2d543d20SAndroid Build Coastguard Worker 			lraw = find_in_hashtable(lrange, domain, domain->trans_to_raw);
1738*2d543d20SAndroid Build Coastguard Worker 			if (! lraw) {
1739*2d543d20SAndroid Build Coastguard Worker 				lraw = compute_raw_from_trans(lrange, domain);
1740*2d543d20SAndroid Build Coastguard Worker 				if (lraw) {
1741*2d543d20SAndroid Build Coastguard Worker 					char *canonical = find_in_hashtable(lraw, domain, domain->raw_to_trans);
1742*2d543d20SAndroid Build Coastguard Worker 					if (!canonical) {
1743*2d543d20SAndroid Build Coastguard Worker 						canonical = compute_trans_from_raw(lraw, domain);
1744*2d543d20SAndroid Build Coastguard Worker 						if (canonical)
1745*2d543d20SAndroid Build Coastguard Worker 							if (add_cache(domain, lraw, canonical) < 0) {
1746*2d543d20SAndroid Build Coastguard Worker 								free(canonical);
1747*2d543d20SAndroid Build Coastguard Worker 								free(lraw);
1748*2d543d20SAndroid Build Coastguard Worker 								free(range);
1749*2d543d20SAndroid Build Coastguard Worker 								return -1;
1750*2d543d20SAndroid Build Coastguard Worker 							}
1751*2d543d20SAndroid Build Coastguard Worker 					}
1752*2d543d20SAndroid Build Coastguard Worker 					if (canonical)
1753*2d543d20SAndroid Build Coastguard Worker 						free(canonical);
1754*2d543d20SAndroid Build Coastguard Worker 					if (add_cache(domain, lraw, lrange) < 0) {
1755*2d543d20SAndroid Build Coastguard Worker 						free(lraw);
1756*2d543d20SAndroid Build Coastguard Worker 						free(range);
1757*2d543d20SAndroid Build Coastguard Worker 						return -1;
1758*2d543d20SAndroid Build Coastguard Worker 					}
1759*2d543d20SAndroid Build Coastguard Worker 				} else {
1760*2d543d20SAndroid Build Coastguard Worker 					lraw = strdup(lrange);
1761*2d543d20SAndroid Build Coastguard Worker 					if (! lraw) {
1762*2d543d20SAndroid Build Coastguard Worker 						log_error("strdup failed %s", strerror(errno));
1763*2d543d20SAndroid Build Coastguard Worker 						free(range);
1764*2d543d20SAndroid Build Coastguard Worker 						return -1;
1765*2d543d20SAndroid Build Coastguard Worker 					}
1766*2d543d20SAndroid Build Coastguard Worker 				}
1767*2d543d20SAndroid Build Coastguard Worker 			}
1768*2d543d20SAndroid Build Coastguard Worker 
1769*2d543d20SAndroid Build Coastguard Worker 			uraw = find_in_hashtable(urange, domain, domain->trans_to_raw);
1770*2d543d20SAndroid Build Coastguard Worker 			if (! uraw) {
1771*2d543d20SAndroid Build Coastguard Worker 				uraw = compute_raw_from_trans(urange, domain);
1772*2d543d20SAndroid Build Coastguard Worker 				if (uraw) {
1773*2d543d20SAndroid Build Coastguard Worker 					char *canonical = find_in_hashtable(uraw, domain, domain->raw_to_trans);
1774*2d543d20SAndroid Build Coastguard Worker 					if (!canonical) {
1775*2d543d20SAndroid Build Coastguard Worker 						canonical = compute_trans_from_raw(uraw, domain);
1776*2d543d20SAndroid Build Coastguard Worker 						if (canonical)
1777*2d543d20SAndroid Build Coastguard Worker 							if (add_cache(domain, uraw, canonical) < 0) {
1778*2d543d20SAndroid Build Coastguard Worker 								free(canonical);
1779*2d543d20SAndroid Build Coastguard Worker 								free(uraw);
1780*2d543d20SAndroid Build Coastguard Worker 								free(lraw);
1781*2d543d20SAndroid Build Coastguard Worker 								free(range);
1782*2d543d20SAndroid Build Coastguard Worker 								return -1;
1783*2d543d20SAndroid Build Coastguard Worker 							}
1784*2d543d20SAndroid Build Coastguard Worker 					}
1785*2d543d20SAndroid Build Coastguard Worker 					if (canonical)
1786*2d543d20SAndroid Build Coastguard Worker 						free(canonical);
1787*2d543d20SAndroid Build Coastguard Worker 					if (add_cache(domain, uraw, urange) < 0) {
1788*2d543d20SAndroid Build Coastguard Worker 						free(uraw);
1789*2d543d20SAndroid Build Coastguard Worker 						free(lraw);
1790*2d543d20SAndroid Build Coastguard Worker 						free(range);
1791*2d543d20SAndroid Build Coastguard Worker 						return -1;
1792*2d543d20SAndroid Build Coastguard Worker 					}
1793*2d543d20SAndroid Build Coastguard Worker 				} else {
1794*2d543d20SAndroid Build Coastguard Worker 					uraw = strdup(urange);
1795*2d543d20SAndroid Build Coastguard Worker 					if (! uraw) {
1796*2d543d20SAndroid Build Coastguard Worker 						log_error("strdup failed %s", strerror(errno));
1797*2d543d20SAndroid Build Coastguard Worker 						free(lraw);
1798*2d543d20SAndroid Build Coastguard Worker 						free(range);
1799*2d543d20SAndroid Build Coastguard Worker 						return -1;
1800*2d543d20SAndroid Build Coastguard Worker 					}
1801*2d543d20SAndroid Build Coastguard Worker 				}
1802*2d543d20SAndroid Build Coastguard Worker 			}
1803*2d543d20SAndroid Build Coastguard Worker 
1804*2d543d20SAndroid Build Coastguard Worker 
1805*2d543d20SAndroid Build Coastguard Worker 			if (strcmp(lraw, uraw) == 0) {
1806*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&raw, "%s", lraw) < 0) {
1807*2d543d20SAndroid Build Coastguard Worker 					log_error("asprintf failed %s", strerror(errno));
1808*2d543d20SAndroid Build Coastguard Worker 					free(uraw);
1809*2d543d20SAndroid Build Coastguard Worker 					free(lraw);
1810*2d543d20SAndroid Build Coastguard Worker 					free(range);
1811*2d543d20SAndroid Build Coastguard Worker 					return -1;
1812*2d543d20SAndroid Build Coastguard Worker 				}
1813*2d543d20SAndroid Build Coastguard Worker 			} else {
1814*2d543d20SAndroid Build Coastguard Worker 				if (asprintf(&raw, "%s-%s", lraw, uraw) < 0) {
1815*2d543d20SAndroid Build Coastguard Worker 					log_error("asprintf failed %s", strerror(errno));
1816*2d543d20SAndroid Build Coastguard Worker 					free(uraw);
1817*2d543d20SAndroid Build Coastguard Worker 					free(lraw);
1818*2d543d20SAndroid Build Coastguard Worker 					free(range);
1819*2d543d20SAndroid Build Coastguard Worker 					return -1;
1820*2d543d20SAndroid Build Coastguard Worker 				}
1821*2d543d20SAndroid Build Coastguard Worker 			}
1822*2d543d20SAndroid Build Coastguard Worker 			free(lraw);
1823*2d543d20SAndroid Build Coastguard Worker 			free(uraw);
1824*2d543d20SAndroid Build Coastguard Worker 			*dashp = '-';
1825*2d543d20SAndroid Build Coastguard Worker 			break;
1826*2d543d20SAndroid Build Coastguard Worker 		}
1827*2d543d20SAndroid Build Coastguard Worker 		if (dashp)
1828*2d543d20SAndroid Build Coastguard Worker 			*dashp = '-';
1829*2d543d20SAndroid Build Coastguard Worker 		if (raw) {
1830*2d543d20SAndroid Build Coastguard Worker 			free(raw);
1831*2d543d20SAndroid Build Coastguard Worker 			raw = NULL;
1832*2d543d20SAndroid Build Coastguard Worker 		}
1833*2d543d20SAndroid Build Coastguard Worker 	}
1834*2d543d20SAndroid Build Coastguard Worker 
1835*2d543d20SAndroid Build Coastguard Worker 	if (raw) {
1836*2d543d20SAndroid Build Coastguard Worker 		*rcon = new_context_str(incon, raw);
1837*2d543d20SAndroid Build Coastguard Worker 		free(raw);
1838*2d543d20SAndroid Build Coastguard Worker 	} else {
1839*2d543d20SAndroid Build Coastguard Worker 		*rcon = new_context_str(incon, range);
1840*2d543d20SAndroid Build Coastguard Worker 	}
1841*2d543d20SAndroid Build Coastguard Worker 	free(range);
1842*2d543d20SAndroid Build Coastguard Worker 
1843*2d543d20SAndroid Build Coastguard Worker #ifdef DEBUG
1844*2d543d20SAndroid Build Coastguard Worker 	struct timeval stopTime;
1845*2d543d20SAndroid Build Coastguard Worker 	gettimeofday(&stopTime, 0);
1846*2d543d20SAndroid Build Coastguard Worker 	long int ms;
1847*2d543d20SAndroid Build Coastguard Worker 	if (startTime.tv_usec > stopTime.tv_usec)
1848*2d543d20SAndroid Build Coastguard Worker 		ms = (stopTime.tv_sec - startTime.tv_sec - 1) * 1000 + (stopTime.tv_usec/1000 + 1000 - startTime.tv_usec/1000);
1849*2d543d20SAndroid Build Coastguard Worker 	else
1850*2d543d20SAndroid Build Coastguard Worker 		ms = (stopTime.tv_sec - startTime.tv_sec    ) * 1000 + (stopTime.tv_usec/1000        - startTime.tv_usec/1000);
1851*2d543d20SAndroid Build Coastguard Worker 
1852*2d543d20SAndroid Build Coastguard Worker 	log_debug(" untrans_context input='%s' output='%s' n %ld ms\n", incon, *rcon, ms);
1853*2d543d20SAndroid Build Coastguard Worker #endif
1854*2d543d20SAndroid Build Coastguard Worker 	return 0;
1855*2d543d20SAndroid Build Coastguard Worker }
1856*2d543d20SAndroid Build Coastguard Worker 
1857*2d543d20SAndroid Build Coastguard Worker void
finish_context_translations(void)1858*2d543d20SAndroid Build Coastguard Worker finish_context_translations(void) {
1859*2d543d20SAndroid Build Coastguard Worker 	while(domains) {
1860*2d543d20SAndroid Build Coastguard Worker 		domain_t *next = domains->next;
1861*2d543d20SAndroid Build Coastguard Worker 		destroy_domain(domains);
1862*2d543d20SAndroid Build Coastguard Worker 		domains = next;
1863*2d543d20SAndroid Build Coastguard Worker 	}
1864*2d543d20SAndroid Build Coastguard Worker 	while(sens_constraints) {
1865*2d543d20SAndroid Build Coastguard Worker 		sens_constraint_t *next = sens_constraints->next;
1866*2d543d20SAndroid Build Coastguard Worker 		destroy_sens_constraint(&sens_constraints, sens_constraints);
1867*2d543d20SAndroid Build Coastguard Worker 		sens_constraints = next;
1868*2d543d20SAndroid Build Coastguard Worker 	}
1869*2d543d20SAndroid Build Coastguard Worker 	while(cat_constraints) {
1870*2d543d20SAndroid Build Coastguard Worker 		cat_constraint_t *next = cat_constraints->next;
1871*2d543d20SAndroid Build Coastguard Worker 		destroy_cat_constraint(&cat_constraints, cat_constraints);
1872*2d543d20SAndroid Build Coastguard Worker 		cat_constraints = next;
1873*2d543d20SAndroid Build Coastguard Worker 	}
1874*2d543d20SAndroid Build Coastguard Worker }
1875*2d543d20SAndroid Build Coastguard Worker 
1876