1 #include "asn1fix_internal.h"
2 #include "asn1fix.h"
3 
4 /* Print everything to stderr */
5 static void _default_error_logger(int _severity, const char *fmt, ...);
6 
7 /*
8  * Internal check functions.
9  */
10 static int asn1f_fix_module__phase_1(arg_t *arg);
11 static int asn1f_fix_module__phase_2(arg_t *arg);
12 static int asn1f_fix_simple(arg_t *arg);	/* For INTEGER/ENUMERATED */
13 static int asn1f_fix_constructed(arg_t *arg);	/* For SEQUENCE/SET/CHOICE */
14 static int asn1f_resolve_constraints(arg_t *arg); /* For subtype constraints */
15 static int asn1f_check_constraints(arg_t *arg);	/* For subtype constraints */
16 static int asn1f_check_duplicate(arg_t *arg);
17 static int asn1f_apply_unique_index(arg_t *arg);
18 static int phase_1_1(arg_t *arg, int prm2);
19 
20 arg_t a1f_replace_me_with_proper_interface_arg;
21 
22 /*
23  * Scan every module defined here in search for inconsistences.
24  */
25 int
asn1f_process(asn1p_t * asn,enum asn1f_flags flags,error_logger_f error_logger)26 asn1f_process(asn1p_t *asn, enum asn1f_flags flags,
27 		error_logger_f error_logger) {
28 	arg_t arg;
29 	int fatals = 0;
30 	int warnings = 0;
31 	int ret;
32 
33 	/*
34 	 * Check validity of arguments.
35 	 */
36 	if(asn == NULL) {
37 		errno = EINVAL;
38 		return -1;
39 	}
40 
41 	/*
42 	 * If errors handler is not specified, default to internal one.
43 	 */
44 	if(error_logger == 0) {
45 		error_logger = _default_error_logger;
46 	}
47 
48 	memset(&arg, 0, sizeof(arg));
49 	arg.asn = asn;
50 	arg.eh = error_logger;
51 
52 	if(flags & A1F_DEBUG) {
53 		arg.debug = arg.eh;
54 		arg.debug(-1, "Called %s() with flags %d", __func__, flags);
55 		flags &= ~A1F_DEBUG;
56 	}
57 
58 	/* Allow SIZE() constraint for INTEGER and other types */
59 	if(flags & A1F_EXTENDED_SizeConstraint) {
60 		arg.flags |= A1F_EXTENDED_SizeConstraint;
61 		flags &= ~A1F_EXTENDED_SizeConstraint;
62 		if(arg.debug) {
63 			arg.debug(-1,
64 				"Extended SizeConstraint support enabled");
65 		}
66 	}
67 
68 	a1f_replace_me_with_proper_interface_arg = arg;
69 
70 	/*
71 	 * Check that we haven't missed an unknown flag.
72 	 */
73 	if(flags) {
74 		errno = EINVAL;
75 		return -1;
76 	}
77 
78 	/*
79 	 * Process each module in the list.
80 	 * PHASE I.
81 	 */
82 	TQ_FOR(arg.mod, &(asn->modules), mod_next) {
83 		ret = asn1f_fix_module__phase_1(&arg);
84 		/*
85 		 * These lines are used for illustration purposes.
86 		 * RET2RVAL() is used everywhere else.
87 		 */
88 		if(ret == -1) fatals++;
89 		if(ret == 1) warnings++;
90 	}
91 	/* PHASE II. */
92 	TQ_FOR(arg.mod, &(asn->modules), mod_next) {
93 		ret = asn1f_fix_module__phase_2(&arg);
94 		if(ret == -1) fatals++;
95 		if(ret == 1) warnings++;
96 	}
97 
98 	memset(&a1f_replace_me_with_proper_interface_arg, 0, sizeof(arg_t));
99 
100 	/*
101 	 * Compute a return value.
102 	 */
103 	return fatals?-1:warnings?1:0;
104 }
105 
106 /*
107  * Check the internals of a single module.
108  */
109 static int
asn1f_fix_module__phase_1(arg_t * arg)110 asn1f_fix_module__phase_1(arg_t *arg) {
111 	asn1p_expr_t *expr;
112 	int rvalue = 0;
113 	int ret;
114 	asn1p_module_t *omod;
115 
116 	/*
117 	 * Check that we don't have a similarly named module.
118 	 */
119 	TQ_FOR(omod, &arg->asn->modules, mod_next) {
120 		int sameNames;
121 		if(omod == arg->mod) break;
122 		sameNames = strcmp(omod->ModuleName, arg->mod->ModuleName)?0:1;
123 		if(omod->module_oid && arg->mod->module_oid) {
124 			/* Compare only the OID. */
125 			if(asn1p_oid_compare(omod->module_oid,
126 					arg->mod->module_oid) == 0) {
127 				FATAL("ASN.1 module %s in %s "
128 					"has the same OBJECT IDENTIFIER"
129 					" as module %s",
130 					omod->ModuleName,
131 					omod->source_file_name,
132 					arg->mod->ModuleName
133 				);
134 				RET2RVAL(-1, rvalue);
135 			} else if(sameNames) {
136 				WARNING("ASN.1 module %s is defined more than once, with different OIDs", omod->ModuleName);
137 				RET2RVAL(1, rvalue);
138 			}
139 		} else if(sameNames) {
140 			FATAL("ASN.1 module %s is defined more than once",
141 				omod->ModuleName);
142 			RET2RVAL(-1, rvalue);
143 		}
144 	}
145 
146 	switch((arg->mod->module_flags & MSF_MASK_TAGS)) {
147 	case MSF_NOFLAGS:
148 	case MSF_EXPLICIT_TAGS:
149 	case MSF_IMPLICIT_TAGS:
150 	case MSF_AUTOMATIC_TAGS:
151 		break;
152 	default:
153 		FATAL("Module %s defined with ambiguous global tagging mode",
154 			arg->mod->ModuleName);
155 		RET2RVAL(-1, rvalue);
156 	}
157 
158 	switch((arg->mod->module_flags & MSF_MASK_INSTRUCTIONS)) {
159 	case MSF_NOFLAGS:
160 		/*
161 		 * arg->mod->module_flags |= MSF_TAG_INSTRUCTIONS;
162 		 */
163 		break;
164 	case MSF_unk_INSTRUCTIONS:
165 		WARNING("Module %s defined with unrecognized "
166 			"encoding reference", arg->mod->ModuleName);
167 		RET2RVAL(1, rvalue);
168 		/* Fall through */
169 	case MSF_TAG_INSTRUCTIONS:
170 	case MSF_XER_INSTRUCTIONS:
171 		break;
172 	default:
173 		FATAL("Module %s defined with ambiguous encoding reference",
174 			arg->mod->ModuleName);
175 		RET2RVAL(-1, rvalue);
176 	}
177 
178 	/*
179 	 * Do various non-recursive transformations.
180 	 */
181 	TQ_FOR(expr, &(arg->mod->members), next) {
182 		arg->expr = expr;
183 		ret = phase_1_1(arg, 0);
184 		RET2RVAL(ret, rvalue);
185 		/*
186 		 * Make sure everybody's behaving well.
187 		 */
188 		assert(arg->expr == expr);
189 	}
190 	TQ_FOR(expr, &(arg->mod->members), next) {
191 		arg->expr = expr;
192 		ret = phase_1_1(arg, 1);
193 		RET2RVAL(ret, rvalue);
194 		assert(arg->expr == expr);
195 	}
196 
197 
198 
199 	/*
200 	 * 5. Automatic tagging
201 	 */
202 	TQ_FOR(expr, &(arg->mod->members), next) {
203 
204 		arg->expr = expr;
205 
206 		ret = asn1f_recurse_expr(arg, asn1f_fix_constr_autotag);
207 		RET2RVAL(ret, rvalue);
208 
209 		assert(arg->expr == expr);
210 	}
211 
212 	/*
213 	 * 8. fix BIT STRING
214 	 * 9. fix spaces in cstrings
215 	 */
216 	TQ_FOR(expr, &(arg->mod->members), next) {
217 		arg->expr = expr;
218 
219 		ret = asn1f_recurse_expr(arg, asn1f_fix_bit_string);
220 		RET2RVAL(ret, rvalue);
221 
222 		ret = asn1f_recurse_expr(arg, asn1f_fix_cstring);
223 		RET2RVAL(ret, rvalue);
224 
225 		assert(arg->expr == expr);
226 	}
227 
228 	/*
229 	 * ... Check for tags distinctness.
230 	 */
231 	TQ_FOR(expr, &(arg->mod->members), next) {
232 		arg->expr = expr;
233 
234 		ret = asn1f_recurse_expr(arg, asn1f_check_constr_tags_distinct);
235 		RET2RVAL(ret, rvalue);
236 
237 		assert(arg->expr == expr);
238 	}
239 
240 	return rvalue;
241 }
242 
243 static int
asn1f_fix_module__phase_2(arg_t * arg)244 asn1f_fix_module__phase_2(arg_t *arg) {
245 	asn1p_expr_t *expr;
246 	int rvalue = 0;
247 	int ret;
248 
249 	TQ_FOR(expr, &(arg->mod->members), next) {
250 		arg->expr = expr;
251 
252 		/*
253 		 * Dereference DEFAULT values.
254 		 */
255 		ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_defaults);
256 		RET2RVAL(ret, rvalue);
257 
258 		/*
259 		 * Check semantic validity of constraints.
260 		 */
261 		ret = asn1f_recurse_expr(arg, asn1f_check_constraints);
262 		RET2RVAL(ret, rvalue);
263 
264 		/*
265 		 * Uniquely tag each inner type.
266 		 */
267 		asn1f_apply_unique_index(0);
268 		ret = asn1f_recurse_expr(arg, asn1f_apply_unique_index);
269 		RET2RVAL(ret, rvalue);
270 
271 		assert(arg->expr == expr);
272 	}
273 
274 	return rvalue;
275 }
276 
277 static int
phase_1_1(arg_t * arg,int prm2)278 phase_1_1(arg_t *arg, int prm2) {
279 	asn1p_expr_t *expr = arg->expr;
280 	int rvalue = 0;
281 	int ret;
282 
283 	if(expr->lhs_params && expr->spec_index == -1) {
284 		int i;
285 		if(!prm2)
286 			/* Do not process the parameterized type just yet */
287 			return 0;
288 		for(i = 0; i < expr->specializations.pspecs_count; i++) {
289 			arg->expr = expr->specializations.pspec[i].my_clone;
290 			ret = phase_1_1(arg, 0);
291 			RET2RVAL(ret, rvalue);
292 		}
293 		arg->expr = expr;	/* revert */
294 		return rvalue;
295 	} else if(prm2) {
296 		return 0;	/* Already done! */
297 	}
298 
299 	/* Check whether this type is a duplicate */
300 	if(!expr->lhs_params) {
301 		ret = asn1f_check_duplicate(arg);
302 		RET2RVAL(ret, rvalue);
303 	}
304 
305 	DEBUG("=== Now processing \"%s\" (%d/0x%x) at line %d ===",
306 		expr->Identifier, expr->meta_type, expr->expr_type,
307 		expr->_lineno);
308 	assert(expr->meta_type != AMT_INVALID);
309 
310 	/*
311 	 * 2.1 Pre-process simple types (ENUMERATED, INTEGER, etc).
312 	 */
313 	ret = asn1f_recurse_expr(arg, asn1f_fix_simple);
314 	RET2RVAL(ret, rvalue);
315 
316 	/*
317 	 * 2.5.4
318 	 */
319 	ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_types);
320 	RET2RVAL(ret, rvalue);
321 
322 	/*
323 	 * Fix tagging of top-level types.
324 	 */
325 	ret = asn1f_fix_constr_tag(arg, 1);
326 	RET2RVAL(ret, rvalue);
327 
328 	/*
329 	 * 2.[234] Process SEQUENCE/SET/CHOICE types.
330 	 */
331 	ret = asn1f_recurse_expr(arg, asn1f_fix_constructed);
332 	RET2RVAL(ret, rvalue);
333 
334 	/*
335 	 * 2.5.5
336 	 */
337 	ret = asn1f_recurse_expr(arg, asn1f_fix_dereference_values);
338 	RET2RVAL(ret, rvalue);
339 
340 	/*
341 	 * Parse class objects and fill up the object class with data.
342 	 */
343 	ret = asn1f_parse_class_object(arg);
344 	RET2RVAL(ret, rvalue);
345 
346 	/*
347 	 * Resolve references in constraints.
348 	 */
349 	ret = asn1f_recurse_expr(arg, asn1f_resolve_constraints);
350 	RET2RVAL(ret, rvalue);
351 
352 	/*
353 	 * 6. INTEGER value processed at 2.5.4.
354 	 */
355 
356 	return rvalue;
357 }
358 
359 static int
asn1f_fix_simple(arg_t * arg)360 asn1f_fix_simple(arg_t *arg) {
361 	int rvalue = 0;
362 	int ret;
363 
364 	ret = asn1f_fix_enum(arg);
365 	RET2RVAL(ret, rvalue);
366 
367 	ret = asn1f_fix_integer(arg);
368 	RET2RVAL(ret, rvalue);
369 
370 	return rvalue;
371 }
372 
373 static int
asn1f_fix_constructed(arg_t * arg)374 asn1f_fix_constructed(arg_t *arg) {
375 	int rvalue = 0;
376 	int ret;
377 
378 	switch(arg->expr->expr_type) {
379 	case ASN_CONSTR_SEQUENCE:
380 	case ASN_CONSTR_SET:
381 	case ASN_CONSTR_CHOICE:
382 		break;
383 	default:
384 		return 0;
385 	}
386 
387 	/* Check identifier distinctness */
388 	ret = asn1f_check_unique_expr(arg);
389 	RET2RVAL(ret, rvalue);
390 
391 	/* Fix extensibility */
392 	ret = asn1f_fix_constr_ext(arg);
393 	RET2RVAL(ret, rvalue);
394 
395 	/* Fix tagging */
396 	ret = asn1f_fix_constr_tag(arg, 0);
397 	RET2RVAL(ret, rvalue);
398 
399 	/* Import COMPONENTS OF stuff */
400 	ret = asn1f_pull_components_of(arg);
401 	RET2RVAL(ret, rvalue);
402 
403 	return rvalue;
404 }
405 
406 static int
asn1f_resolve_constraints(arg_t * arg)407 asn1f_resolve_constraints(arg_t *arg) {
408 	asn1p_expr_t *top_parent;
409 	asn1p_expr_type_e etype;
410 	int rvalue = 0;
411 	int ret;
412 
413 	top_parent = asn1f_find_terminal_type(arg, arg->expr);
414 	if(top_parent)
415 		etype = top_parent->expr_type;
416 	else	etype = A1TC_INVALID;
417 
418 	DEBUG("(%s)", arg->expr->Identifier);
419 
420 	ret = asn1constraint_resolve(arg, arg->expr->constraints, etype, 0);
421 	RET2RVAL(ret, rvalue);
422 
423 	return rvalue;
424 }
425 
426 static int
asn1f_check_constraints(arg_t * arg)427 asn1f_check_constraints(arg_t *arg) {
428 	static enum asn1p_constraint_type_e test_types[] = {
429 		ACT_EL_RANGE, ACT_CT_SIZE, ACT_CT_FROM };
430 	asn1p_expr_t *top_parent;
431 	asn1cnst_range_t *range;
432 	asn1p_expr_type_e etype;
433 	unsigned int i;
434 	int rvalue = 0;
435 	int ret;
436 
437 	DEBUG("(%s{%d/%d})",
438 		arg->expr->Identifier,
439 		arg->expr->meta_type, arg->expr->expr_type);
440 
441 	top_parent = asn1f_find_terminal_type(arg, arg->expr);
442 	if(!top_parent)
443 		return 0;
444 	etype = top_parent->expr_type;
445 
446 	ret = asn1constraint_pullup(arg);
447 	RET2RVAL(ret, rvalue);
448 
449 	for(i = 0; i < sizeof(test_types)/sizeof(test_types[0]); i++) {
450 		range = asn1constraint_compute_PER_range(
451 				etype,
452 				arg->expr->combined_constraints,
453 				test_types[i], 0, 0,
454 				CPR_noflags /* ignore -fbless-SIZE */);
455 		if(!range && errno == EPERM) {
456 			FATAL("This error happened for \"%s\" (meta %d) "
457 				"at line %d",
458 				arg->expr->Identifier,
459 				arg->expr->meta_type,
460 				arg->expr->_lineno);
461 			return -1;
462 		}
463 		asn1constraint_range_free(range);
464 	}
465 
466 	return rvalue;
467 }
468 
469 static int
asn1f_check_duplicate(arg_t * arg)470 asn1f_check_duplicate(arg_t *arg) {
471 	arg_t tmparg = *arg;
472 	int rvalue = 0;
473 
474 	/*
475 	 * This is a linear scan in search of a similar type.
476 	 * The linear scan is just fine for the task, no need to over-optimize.
477 	 */
478 	TQ_FOR(tmparg.mod, &arg->asn->modules, mod_next) {
479 		int critical = 1;	/* FATAL */
480 
481 		if((arg->mod->_tags & MT_STANDARD_MODULE)
482 		!= (tmparg.mod->_tags & MT_STANDARD_MODULE)) {
483 			/* Ignore clashes with standard module */
484 			critical = 0;	/* WARNING */
485 		}
486 
487 		TQ_FOR(tmparg.expr, &(tmparg.mod->members), next) {
488 			int diff_files;	/* different files */
489 
490 			assert(tmparg.expr->Identifier);
491 			assert(arg->expr->Identifier);
492 
493 			if(arg->expr->spec_index != -1)
494 				continue;
495 
496 			if(tmparg.expr == arg->expr) break;
497 
498 			if(strcmp(tmparg.expr->Identifier,
499 				  arg->expr->Identifier))
500 				continue;
501 
502 			diff_files = strcmp(arg->mod->source_file_name,
503 					tmparg.mod->source_file_name) ? 1 : 0;
504 
505 			LOG(critical,
506 			"ASN.1 expression \"%s\" at line %d of module %s\n"
507 			"clashes with expression \"%s\" at line %d of module %s"
508 			"%s%s%s.\n"
509 			"Rename or remove either instance "
510 				"to resolve the conflict",
511 				arg->expr->Identifier,
512 				arg->expr->_lineno,
513 				arg->mod->ModuleName,
514 				tmparg.expr->Identifier,
515 				tmparg.expr->_lineno,
516 				tmparg.mod->ModuleName,
517 				diff_files ? " (" : "",
518 				diff_files ? tmparg.mod->source_file_name : "",
519 				diff_files ? ")" : "");
520 			if(critical)
521 				return -1;
522 			RET2RVAL(1, rvalue);
523 		}
524 		if(tmparg.mod == arg->mod) break;
525 	}
526 
527 	return rvalue;
528 }
529 
530 static int
asn1f_apply_unique_index(arg_t * arg)531 asn1f_apply_unique_index(arg_t *arg) {
532 	static int unique_index;
533 	if(!arg) { unique_index = 0; return 0; }
534 
535 	arg->expr->_type_unique_index = ++unique_index;
536 
537 	return 0;
538 }
539 
540 /*
541  * Print everything to stderr
542  */
543 static void
_default_error_logger(int _severity,const char * fmt,...)544 _default_error_logger(int _severity, const char *fmt, ...) {
545 	va_list ap;
546 	char *pfx = "";
547 
548 	switch(_severity) {
549 	case -1: pfx = "DEBUG: "; break;
550 	case 0: pfx = "WARNING: "; break;
551 	case 1: pfx = "FATAL: "; break;
552 	}
553 
554 	fprintf(stderr, "%s", pfx);
555 	va_start(ap, fmt);
556 	vfprintf(stderr, fmt, ap);
557 	va_end(ap);
558 	fprintf(stderr, "\n");
559 }
560