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