1 /* $OpenBSD: schema.c,v 1.19 2019/10/24 12:39:26 tb Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Martin Hedenfalk <martinh@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <ctype.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <syslog.h> 25 26 #include "ldapd.h" 27 #include "log.h" 28 29 #define ERROR -1 30 #define STRING 1 31 32 static int 33 attr_oid_cmp(struct attr_type *a, struct attr_type *b) 34 { 35 return strcasecmp(a->oid, b->oid); 36 } 37 38 static int 39 obj_oid_cmp(struct object *a, struct object *b) 40 { 41 return strcasecmp(a->oid, b->oid); 42 } 43 44 static int 45 oidname_cmp(struct oidname *a, struct oidname *b) 46 { 47 return strcasecmp(a->on_name, b->on_name); 48 } 49 50 static int 51 symoid_cmp(struct symoid *a, struct symoid *b) 52 { 53 return strcasecmp(a->name, b->name); 54 } 55 56 RB_GENERATE(attr_type_tree, attr_type, link, attr_oid_cmp); 57 RB_GENERATE(object_tree, object, link, obj_oid_cmp); 58 RB_GENERATE(oidname_tree, oidname, link, oidname_cmp); 59 RB_GENERATE(symoid_tree, symoid, link, symoid_cmp); 60 61 static struct attr_list *push_attr(struct attr_list *alist, struct attr_type *a); 62 static struct obj_list *push_obj(struct obj_list *olist, struct object *obj); 63 static struct name_list *push_name(struct name_list *nl, char *name); 64 int is_oidstr(const char *oidstr); 65 66 struct attr_type * 67 lookup_attribute_by_name(struct schema *schema, char *name) 68 { 69 struct oidname *on, find; 70 71 find.on_name = name; 72 on = RB_FIND(oidname_tree, &schema->attr_names, &find); 73 74 if (on) 75 return on->on_attr_type; 76 return NULL; 77 } 78 79 struct attr_type * 80 lookup_attribute_by_oid(struct schema *schema, char *oid) 81 { 82 struct attr_type find; 83 84 find.oid = oid; 85 return RB_FIND(attr_type_tree, &schema->attr_types, &find); 86 } 87 88 struct attr_type * 89 lookup_attribute(struct schema *schema, char *oid_or_name) 90 { 91 if (is_oidstr(oid_or_name)) 92 return lookup_attribute_by_oid(schema, oid_or_name); 93 return lookup_attribute_by_name(schema, oid_or_name); 94 } 95 96 struct object * 97 lookup_object_by_oid(struct schema *schema, char *oid) 98 { 99 struct object find; 100 101 find.oid = oid; 102 return RB_FIND(object_tree, &schema->objects, &find); 103 } 104 105 struct object * 106 lookup_object_by_name(struct schema *schema, char *name) 107 { 108 struct oidname *on, find; 109 110 find.on_name = name; 111 on = RB_FIND(oidname_tree, &schema->object_names, &find); 112 113 if (on) 114 return on->on_object; 115 return NULL; 116 } 117 118 struct object * 119 lookup_object(struct schema *schema, char *oid_or_name) 120 { 121 if (is_oidstr(oid_or_name)) 122 return lookup_object_by_oid(schema, oid_or_name); 123 return lookup_object_by_name(schema, oid_or_name); 124 } 125 126 /* 127 * Looks up a symbolic OID, optionally with a suffix OID, so if 128 * SYMBOL = 1.2.3.4 129 * then 130 * SYMBOL:5.6 = 1.2.3.4.5.6 131 * 132 * Returned string must be freed by the caller. 133 * Modifies the name argument. 134 */ 135 char * 136 lookup_symbolic_oid(struct schema *schema, char *name) 137 { 138 struct symoid *symoid, find; 139 char *colon, *oid; 140 size_t sz; 141 142 colon = strchr(name, ':'); 143 if (colon != NULL) { 144 if (!is_oidstr(colon + 1)) { 145 log_warnx("invalid OID after colon: %s", colon + 1); 146 return NULL; 147 } 148 *colon = '\0'; 149 } 150 151 find.name = name; 152 symoid = RB_FIND(symoid_tree, &schema->symbolic_oids, &find); 153 if (symoid == NULL) 154 return NULL; 155 156 if (colon == NULL) 157 return strdup(symoid->oid); 158 159 /* Expand SYMBOL:OID. */ 160 sz = strlen(symoid->oid) + 1 + strlen(colon + 1) + 1; 161 if ((oid = malloc(sz)) == NULL) { 162 log_warnx("malloc"); 163 return NULL; 164 } 165 166 strlcpy(oid, symoid->oid, sz); 167 strlcat(oid, ".", sz); 168 strlcat(oid, colon + 1, sz); 169 170 return oid; 171 } 172 173 /* 174 * Push a symbol-OID pair on the tree. Name and OID must be valid pointers 175 * during the lifetime of the tree. 176 */ 177 static struct symoid * 178 push_symbolic_oid(struct schema *schema, char *name, char *oid) 179 { 180 struct symoid *symoid, find; 181 182 find.name = name; 183 symoid = RB_FIND(symoid_tree, &schema->symbolic_oids, &find); 184 185 if (symoid == NULL) { 186 symoid = calloc(1, sizeof(*symoid)); 187 if (symoid == NULL) { 188 log_warnx("calloc"); 189 return NULL; 190 } 191 192 symoid->name = name; 193 RB_INSERT(symoid_tree, &schema->symbolic_oids, symoid); 194 } 195 196 free(symoid->oid); 197 symoid->oid = oid; 198 199 return symoid; 200 } 201 202 static struct attr_list * 203 push_attr(struct attr_list *alist, struct attr_type *a) 204 { 205 struct attr_ptr *aptr; 206 207 if (alist == NULL) { 208 if ((alist = calloc(1, sizeof(*alist))) == NULL) { 209 log_warn("calloc"); 210 return NULL; 211 } 212 SLIST_INIT(alist); 213 } 214 215 if ((aptr = calloc(1, sizeof(*aptr))) == NULL) { 216 log_warn("calloc"); 217 free(alist); 218 return NULL; 219 } 220 aptr->attr_type = a; 221 SLIST_INSERT_HEAD(alist, aptr, next); 222 223 return alist; 224 } 225 226 static struct obj_list * 227 push_obj(struct obj_list *olist, struct object *obj) 228 { 229 struct obj_ptr *optr; 230 231 if (olist == NULL) { 232 if ((olist = calloc(1, sizeof(*olist))) == NULL) { 233 log_warn("calloc"); 234 return NULL; 235 } 236 SLIST_INIT(olist); 237 } 238 239 if ((optr = calloc(1, sizeof(*optr))) == NULL) { 240 log_warn("calloc"); 241 free(olist); 242 return NULL; 243 } 244 optr->object = obj; 245 SLIST_INSERT_HEAD(olist, optr, next); 246 247 return olist; 248 } 249 250 int 251 is_oidstr(const char *oidstr) 252 { 253 struct ber_oid oid; 254 return (ober_string2oid(oidstr, &oid) == 0); 255 } 256 257 static struct name_list * 258 push_name(struct name_list *nl, char *name) 259 { 260 struct name *n; 261 262 if (nl == NULL) { 263 if ((nl = calloc(1, sizeof(*nl))) == NULL) { 264 log_warn("calloc"); 265 return NULL; 266 } 267 SLIST_INIT(nl); 268 } 269 if ((n = calloc(1, sizeof(*n))) == NULL) { 270 log_warn("calloc"); 271 free(nl); 272 return NULL; 273 } 274 n->name = name; 275 SLIST_INSERT_HEAD(nl, n, next); 276 277 return nl; 278 } 279 280 static int 281 schema_getc(struct schema *schema, int quotec) 282 { 283 int c, next; 284 285 if (schema->pushback_index) 286 return (schema->pushback_buffer[--schema->pushback_index]); 287 288 if (quotec) { 289 if ((c = getc(schema->fp)) == EOF) { 290 log_warnx("reached end of file while parsing " 291 "quoted string"); 292 return EOF; 293 } 294 return (c); 295 } 296 297 while ((c = getc(schema->fp)) == '\\') { 298 next = getc(schema->fp); 299 if (next != '\n') { 300 c = next; 301 break; 302 } 303 schema->lineno++; 304 } 305 306 return (c); 307 } 308 309 static int 310 schema_ungetc(struct schema *schema, int c) 311 { 312 if (c == EOF) 313 return EOF; 314 315 if (schema->pushback_index < SCHEMA_MAXPUSHBACK-1) 316 return (schema->pushback_buffer[schema->pushback_index++] = c); 317 else 318 return (EOF); 319 } 320 321 static int 322 findeol(struct schema *schema) 323 { 324 int c; 325 326 /* skip to either EOF or the first real EOL */ 327 while (1) { 328 if (schema->pushback_index) 329 c = schema->pushback_buffer[--schema->pushback_index]; 330 else 331 c = schema_getc(schema, 0); 332 if (c == '\n') { 333 schema->lineno++; 334 break; 335 } 336 if (c == EOF) 337 break; 338 } 339 return (ERROR); 340 } 341 342 static int 343 schema_lex(struct schema *schema, char **kw) 344 { 345 char buf[8096]; 346 char *p; 347 int quotec, next, c; 348 349 if (kw) 350 *kw = NULL; 351 352 top: 353 p = buf; 354 while ((c = schema_getc(schema, 0)) == ' ' || c == '\t') 355 ; /* nothing */ 356 357 if (c == '#') 358 while ((c = schema_getc(schema, 0)) != '\n' && c != EOF) 359 ; /* nothing */ 360 361 switch (c) { 362 case '\'': 363 case '"': 364 quotec = c; 365 while (1) { 366 if ((c = schema_getc(schema, quotec)) == EOF) 367 return (0); 368 if (c == '\n') { 369 schema->lineno++; 370 continue; 371 } else if (c == '\\') { 372 if ((next = schema_getc(schema, quotec)) == EOF) 373 return (0); 374 if (next == quotec || c == ' ' || c == '\t') 375 c = next; 376 else if (next == '\n') 377 continue; 378 else 379 schema_ungetc(schema, next); 380 } else if (c == quotec) { 381 *p = '\0'; 382 break; 383 } 384 if (p + 1 >= buf + sizeof(buf) - 1) { 385 log_warnx("string too long"); 386 return (findeol(schema)); 387 } 388 *p++ = (char)c; 389 } 390 if (kw != NULL && (*kw = strdup(buf)) == NULL) 391 fatal("schema_lex: strdup"); 392 return (STRING); 393 } 394 395 #define allowed_in_string(x) \ 396 (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ 397 x != '{' && x != '}' && x != '<' && x != '>' && \ 398 x != '!' && x != '=' && x != '/' && x != '#' && \ 399 x != ',')) 400 401 if (isalnum(c) || c == ':' || c == '_' || c == '*') { 402 do { 403 *p++ = c; 404 if ((size_t)(p-buf) >= sizeof(buf)) { 405 log_warnx("string too long"); 406 return (findeol(schema)); 407 } 408 } while ((c = schema_getc(schema, 0)) != EOF && (allowed_in_string(c))); 409 schema_ungetc(schema, c); 410 *p = '\0'; 411 if (kw != NULL && (*kw = strdup(buf)) == NULL) 412 fatal("schema_lex: strdup"); 413 return STRING; 414 } 415 if (c == '\n') { 416 schema->lineno++; 417 goto top; 418 } 419 if (c == EOF) 420 return (0); 421 return (c); 422 } 423 424 struct schema * 425 schema_new(void) 426 { 427 struct schema *schema; 428 429 if ((schema = calloc(1, sizeof(*schema))) == NULL) 430 return NULL; 431 432 RB_INIT(&schema->attr_types); 433 RB_INIT(&schema->attr_names); 434 RB_INIT(&schema->objects); 435 RB_INIT(&schema->object_names); 436 RB_INIT(&schema->symbolic_oids); 437 438 return schema; 439 } 440 441 static void 442 schema_err(struct schema *schema, const char *fmt, ...) 443 { 444 va_list ap; 445 char *msg; 446 447 va_start(ap, fmt); 448 if (vasprintf(&msg, fmt, ap) == -1) 449 fatal("vasprintf"); 450 va_end(ap); 451 logit(LOG_CRIT, "%s:%d: %s", schema->filename, schema->lineno, msg); 452 free(msg); 453 454 schema->error++; 455 } 456 457 static int 458 schema_link_attr_name(struct schema *schema, const char *name, struct attr_type *attr) 459 { 460 struct oidname *oidname, *prev; 461 462 if ((oidname = calloc(1, sizeof(*oidname))) == NULL) { 463 log_warn("calloc"); 464 return -1; 465 } 466 467 oidname->on_name = name; 468 oidname->on_attr_type = attr; 469 prev = RB_INSERT(oidname_tree, &schema->attr_names, oidname); 470 if (prev != NULL) { 471 schema_err(schema, "attribute type name '%s'" 472 " already defined for oid %s", 473 name, prev->on_attr_type->oid); 474 free(oidname); 475 return -1; 476 } 477 478 return 0; 479 } 480 481 static int 482 schema_link_attr_names(struct schema *schema, struct attr_type *attr) 483 { 484 struct name *name; 485 486 SLIST_FOREACH(name, attr->names, next) { 487 if (schema_link_attr_name(schema, name->name, attr) != 0) 488 return -1; 489 } 490 return 0; 491 } 492 493 static int 494 schema_link_obj_name(struct schema *schema, const char *name, struct object *obj) 495 { 496 struct oidname *oidname, *prev; 497 498 if ((oidname = calloc(1, sizeof(*oidname))) == NULL) { 499 log_warn("calloc"); 500 return -1; 501 } 502 503 oidname->on_name = name; 504 oidname->on_object = obj; 505 prev = RB_INSERT(oidname_tree, &schema->object_names, oidname); 506 if (prev != NULL) { 507 schema_err(schema, "object class name '%s'" 508 " already defined for oid %s", 509 name, prev->on_object->oid); 510 free(oidname); 511 return -1; 512 } 513 514 return 0; 515 } 516 517 static int 518 schema_link_obj_names(struct schema *schema, struct object *obj) 519 { 520 struct name *name; 521 522 SLIST_FOREACH(name, obj->names, next) { 523 if (schema_link_obj_name(schema, name->name, obj) != 0) 524 return -1; 525 } 526 return 0; 527 } 528 529 static struct name_list * 530 schema_parse_names(struct schema *schema) 531 { 532 struct name_list *nlist = NULL; 533 char *kw; 534 int token; 535 536 token = schema_lex(schema, &kw); 537 if (token == STRING) 538 return push_name(NULL, kw); 539 540 if (token != '(') 541 goto fail; 542 543 for (;;) { 544 token = schema_lex(schema, &kw); 545 if (token == ')') 546 break; 547 if (token != STRING) 548 goto fail; 549 nlist = push_name(nlist, kw); 550 } 551 552 return nlist; 553 554 fail: 555 free(kw); 556 /* FIXME: leaks nlist here */ 557 return NULL; 558 } 559 560 static void 561 schema_free_name_list(struct name_list *nlist) 562 { 563 struct name *name; 564 565 while ((name = SLIST_FIRST(nlist)) != NULL) { 566 SLIST_REMOVE_HEAD(nlist, next); 567 free(name->name); 568 free(name); 569 } 570 free(nlist); 571 } 572 573 static struct attr_list * 574 schema_parse_attrlist(struct schema *schema) 575 { 576 struct attr_list *alist = NULL; 577 struct attr_type *attr; 578 char *kw; 579 int token, want_dollar = 0; 580 581 token = schema_lex(schema, &kw); 582 if (token == STRING) { 583 if ((attr = lookup_attribute(schema, kw)) == NULL) { 584 schema_err(schema, "undeclared attribute type '%s'", kw); 585 goto fail; 586 } 587 free(kw); 588 return push_attr(NULL, attr); 589 } 590 591 if (token != '(') 592 goto fail; 593 594 for (;;) { 595 token = schema_lex(schema, &kw); 596 if (token == ')') 597 break; 598 if (token == '$') { 599 if (!want_dollar) 600 goto fail; 601 want_dollar = 0; 602 continue; 603 } 604 if (token != STRING) 605 goto fail; 606 if ((attr = lookup_attribute(schema, kw)) == NULL) { 607 schema_err(schema, "%s: no such attribute", kw); 608 goto fail; 609 } 610 alist = push_attr(alist, attr); 611 free(kw); 612 want_dollar = 1; 613 } 614 615 return alist; 616 617 fail: 618 free(kw); 619 /* FIXME: leaks alist here */ 620 return NULL; 621 } 622 623 static struct obj_list * 624 schema_parse_objlist(struct schema *schema) 625 { 626 struct obj_list *olist = NULL; 627 struct object *obj; 628 char *kw; 629 int token, want_dollar = 0; 630 631 token = schema_lex(schema, &kw); 632 if (token == STRING) { 633 if ((obj = lookup_object(schema, kw)) == NULL) { 634 schema_err(schema, "undeclared object class '%s'", kw); 635 goto fail; 636 } 637 free(kw); 638 return push_obj(NULL, obj); 639 } 640 641 if (token != '(') 642 goto fail; 643 644 for (;;) { 645 token = schema_lex(schema, &kw); 646 if (token == ')') 647 break; 648 if (token == '$') { 649 if (!want_dollar) 650 goto fail; 651 want_dollar = 0; 652 continue; 653 } 654 if (token != STRING) 655 goto fail; 656 if ((obj = lookup_object(schema, kw)) == NULL) 657 goto fail; 658 olist = push_obj(olist, obj); 659 want_dollar = 1; 660 } 661 662 return olist; 663 664 fail: 665 free(kw); 666 /* FIXME: leaks olist here */ 667 return NULL; 668 } 669 670 static int 671 schema_validate_match_rule(struct schema *schema, struct attr_type *at, 672 const struct match_rule *mrule, enum match_rule_type type) 673 { 674 int i; 675 676 if (mrule == NULL) 677 return 0; 678 679 if ((mrule->type & type) != type) { 680 schema_err(schema, "%s: bad matching rule '%s'", 681 ATTR_NAME(at), mrule->name); 682 return -1; 683 } 684 685 /* Is this matching rule compatible with the attribute syntax? */ 686 if (strcmp(mrule->syntax_oid, at->syntax->oid) == 0) 687 return 0; 688 689 /* Check any alternative syntaxes for compatibility. */ 690 for (i = 0; mrule->alt_syntax_oids && mrule->alt_syntax_oids[i]; i++) 691 if (strcmp(mrule->alt_syntax_oids[i], at->syntax->oid) == 0) 692 return 0; 693 694 schema_err(schema, "%s: inappropriate matching rule '%s' for syntax [%s]", 695 ATTR_NAME(at), mrule->name, at->syntax->oid); 696 return -1; 697 } 698 699 static int 700 schema_parse_attributetype(struct schema *schema) 701 { 702 struct attr_type *attr = NULL, *prev, *sup; 703 struct name_list *xnames; 704 char *kw = NULL, *arg = NULL; 705 int token, ret = 0, c; 706 707 if (schema_lex(schema, NULL) != '(') 708 goto fail; 709 710 if (schema_lex(schema, &kw) != STRING) 711 goto fail; 712 713 if ((attr = calloc(1, sizeof(*attr))) == NULL) { 714 log_warn("calloc"); 715 goto fail; 716 } 717 attr->usage = USAGE_USER_APP; 718 719 if (is_oidstr(kw)) 720 attr->oid = kw; 721 else { 722 attr->oid = lookup_symbolic_oid(schema, kw); 723 if (attr->oid == NULL) 724 goto fail; 725 free(kw); 726 } 727 kw = NULL; 728 729 prev = RB_INSERT(attr_type_tree, &schema->attr_types, attr); 730 if (prev != NULL) { 731 schema_err(schema, "attribute type %s already defined", attr->oid); 732 goto fail; 733 } 734 735 while (ret == 0) { 736 token = schema_lex(schema, &kw); 737 if (token == ')') 738 break; 739 else if (token != STRING) 740 goto fail; 741 if (strcasecmp(kw, "NAME") == 0) { 742 attr->names = schema_parse_names(schema); 743 if (attr->names == NULL) 744 goto fail; 745 schema_link_attr_names(schema, attr); 746 } else if (strcasecmp(kw, "DESC") == 0) { 747 if (schema_lex(schema, &attr->desc) != STRING) 748 goto fail; 749 } else if (strcasecmp(kw, "OBSOLETE") == 0) { 750 attr->obsolete = 1; 751 } else if (strcasecmp(kw, "SUP") == 0) { 752 if (schema_lex(schema, &arg) != STRING) 753 goto fail; 754 if ((attr->sup = lookup_attribute(schema, arg)) == NULL) { 755 schema_err(schema, "%s: no such attribute", arg); 756 goto fail; 757 } 758 free(arg); 759 } else if (strcasecmp(kw, "EQUALITY") == 0) { 760 if (schema_lex(schema, &arg) != STRING) 761 goto fail; 762 if ((attr->equality = match_rule_lookup(arg)) == NULL) { 763 schema_err(schema, "%s: unknown matching rule", 764 arg); 765 goto fail; 766 } 767 free(arg); 768 } else if (strcasecmp(kw, "ORDERING") == 0) { 769 if (schema_lex(schema, &arg) != STRING) 770 goto fail; 771 if ((attr->ordering = match_rule_lookup(arg)) == NULL) { 772 schema_err(schema, "%s: unknown matching rule", 773 arg); 774 goto fail; 775 } 776 free(arg); 777 } else if (strcasecmp(kw, "SUBSTR") == 0) { 778 if (schema_lex(schema, &arg) != STRING) 779 goto fail; 780 if ((attr->substr = match_rule_lookup(arg)) == NULL) { 781 schema_err(schema, "%s: unknown matching rule", 782 arg); 783 goto fail; 784 } 785 free(arg); 786 } else if (strcasecmp(kw, "SYNTAX") == 0) { 787 if (schema_lex(schema, &arg) != STRING || 788 !is_oidstr(arg)) 789 goto fail; 790 791 if ((attr->syntax = syntax_lookup(arg)) == NULL) { 792 schema_err(schema, "syntax not supported: %s", 793 arg); 794 goto fail; 795 } 796 797 if ((c = schema_getc(schema, 0)) == '{') { 798 if (schema_lex(schema, NULL) != STRING || 799 schema_lex(schema, NULL) != '}') 800 goto fail; 801 } else 802 schema_ungetc(schema, c); 803 free(arg); 804 } else if (strcasecmp(kw, "SINGLE-VALUE") == 0) { 805 attr->single = 1; 806 } else if (strcasecmp(kw, "COLLECTIVE") == 0) { 807 attr->collective = 1; 808 } else if (strcasecmp(kw, "NO-USER-MODIFICATION") == 0) { 809 attr->immutable = 1; 810 } else if (strcasecmp(kw, "USAGE") == 0) { 811 if (schema_lex(schema, &arg) != STRING) 812 goto fail; 813 if (strcasecmp(arg, "dSAOperation") == 0) 814 attr->usage = USAGE_DSA_OP; 815 else if (strcasecmp(arg, "directoryOperation") == 0) 816 attr->usage = USAGE_DIR_OP; 817 else if (strcasecmp(arg, "distributedOperation") == 0) 818 attr->usage = USAGE_DIST_OP; 819 else if (strcasecmp(arg, "userApplications") == 0) 820 attr->usage = USAGE_USER_APP; 821 else { 822 schema_err(schema, "invalid usage '%s'", arg); 823 goto fail; 824 } 825 free(arg); 826 } else if (strncmp(kw, "X-", 2) == 0) { 827 /* unknown extension, eat argument(s) */ 828 xnames = schema_parse_names(schema); 829 if (xnames == NULL) 830 goto fail; 831 schema_free_name_list(xnames); 832 } else { 833 schema_err(schema, "syntax error at token '%s'", kw); 834 goto fail; 835 } 836 free(kw); 837 } 838 839 /* Check that a syntax is defined, either directly or 840 * indirectly via a superior attribute type. 841 */ 842 sup = attr->sup; 843 while (attr->syntax == NULL && sup != NULL) { 844 attr->syntax = sup->syntax; 845 sup = sup->sup; 846 } 847 if (attr->syntax == NULL) { 848 schema_err(schema, "%s: no syntax defined", ATTR_NAME(attr)); 849 goto fail; 850 } 851 852 /* If the attribute type doesn't explicitly define equality, check 853 * if any superior attribute type does. 854 */ 855 sup = attr->sup; 856 while (attr->equality == NULL && sup != NULL) { 857 attr->equality = sup->equality; 858 sup = sup->sup; 859 } 860 /* Same thing with ordering matching rule. */ 861 sup = attr->sup; 862 while (attr->ordering == NULL && sup != NULL) { 863 attr->ordering = sup->ordering; 864 sup = sup->sup; 865 } 866 /* ...and substring matching rule. */ 867 sup = attr->sup; 868 while (attr->substr == NULL && sup != NULL) { 869 attr->substr = sup->substr; 870 sup = sup->sup; 871 } 872 873 if (schema_validate_match_rule(schema, attr, attr->equality, MATCH_EQUALITY) != 0 || 874 schema_validate_match_rule(schema, attr, attr->ordering, MATCH_ORDERING) != 0 || 875 schema_validate_match_rule(schema, attr, attr->substr, MATCH_SUBSTR) != 0) 876 goto fail; 877 878 return 0; 879 880 fail: 881 free(kw); 882 if (attr != NULL) { 883 if (attr->oid != NULL) { 884 RB_REMOVE(attr_type_tree, &schema->attr_types, attr); 885 free(attr->oid); 886 } 887 free(attr->desc); 888 free(attr); 889 } 890 return -1; 891 } 892 893 static int 894 schema_parse_objectclass(struct schema *schema) 895 { 896 struct object *obj = NULL, *prev; 897 struct obj_ptr *optr; 898 struct name_list *xnames; 899 char *kw = NULL; 900 int token, ret = 0; 901 902 if (schema_lex(schema, NULL) != '(') 903 goto fail; 904 905 if (schema_lex(schema, &kw) != STRING) 906 goto fail; 907 908 if ((obj = calloc(1, sizeof(*obj))) == NULL) { 909 log_warn("calloc"); 910 goto fail; 911 } 912 obj->kind = KIND_STRUCTURAL; 913 914 if (is_oidstr(kw)) 915 obj->oid = kw; 916 else { 917 obj->oid = lookup_symbolic_oid(schema, kw); 918 if (obj->oid == NULL) 919 goto fail; 920 free(kw); 921 } 922 kw = NULL; 923 924 prev = RB_INSERT(object_tree, &schema->objects, obj); 925 if (prev != NULL) { 926 schema_err(schema, "object class %s already defined", obj->oid); 927 goto fail; 928 } 929 930 while (ret == 0) { 931 token = schema_lex(schema, &kw); 932 if (token == ')') 933 break; 934 else if (token != STRING) 935 goto fail; 936 if (strcasecmp(kw, "NAME") == 0) { 937 obj->names = schema_parse_names(schema); 938 if (obj->names == NULL) 939 goto fail; 940 schema_link_obj_names(schema, obj); 941 } else if (strcasecmp(kw, "DESC") == 0) { 942 if (schema_lex(schema, &obj->desc) != STRING) 943 goto fail; 944 } else if (strcasecmp(kw, "OBSOLETE") == 0) { 945 obj->obsolete = 1; 946 } else if (strcasecmp(kw, "SUP") == 0) { 947 obj->sup = schema_parse_objlist(schema); 948 if (obj->sup == NULL) 949 goto fail; 950 } else if (strcasecmp(kw, "ABSTRACT") == 0) { 951 obj->kind = KIND_ABSTRACT; 952 } else if (strcasecmp(kw, "STRUCTURAL") == 0) { 953 obj->kind = KIND_STRUCTURAL; 954 } else if (strcasecmp(kw, "AUXILIARY") == 0) { 955 obj->kind = KIND_AUXILIARY; 956 } else if (strcasecmp(kw, "MUST") == 0) { 957 obj->must = schema_parse_attrlist(schema); 958 if (obj->must == NULL) 959 goto fail; 960 } else if (strcasecmp(kw, "MAY") == 0) { 961 obj->may = schema_parse_attrlist(schema); 962 if (obj->may == NULL) 963 goto fail; 964 } else if (strncasecmp(kw, "X-", 2) == 0) { 965 /* unknown extension, eat argument(s) */ 966 xnames = schema_parse_names(schema); 967 if (xnames == NULL) 968 goto fail; 969 schema_free_name_list(xnames); 970 } else { 971 schema_err(schema, "syntax error at token '%s'", kw); 972 goto fail; 973 } 974 free(kw); 975 } 976 977 /* Verify the subclassing is allowed. 978 * 979 * Structural object classes cannot subclass auxiliary object classes. 980 * Auxiliary object classes cannot subclass structural object classes. 981 * Abstract object classes cannot derive from structural or auxiliary 982 * object classes. 983 */ 984 if (obj->sup != NULL) { 985 SLIST_FOREACH(optr, obj->sup, next) { 986 if (obj->kind == KIND_STRUCTURAL && 987 optr->object->kind == KIND_AUXILIARY) { 988 log_warnx("structural object class '%s' cannot" 989 " subclass auxiliary object class '%s'", 990 OBJ_NAME(obj), OBJ_NAME(optr->object)); 991 goto fail; 992 } 993 994 if (obj->kind == KIND_AUXILIARY && 995 optr->object->kind == KIND_STRUCTURAL) { 996 log_warnx("auxiliary object class '%s' cannot" 997 " subclass structural object class '%s'", 998 OBJ_NAME(obj), OBJ_NAME(optr->object)); 999 goto fail; 1000 } 1001 1002 if (obj->kind == KIND_ABSTRACT && 1003 optr->object->kind != KIND_ABSTRACT) { 1004 log_warnx("abstract object class '%s' cannot" 1005 " subclass non-abstract object class '%s'", 1006 OBJ_NAME(obj), OBJ_NAME(optr->object)); 1007 goto fail; 1008 } 1009 } 1010 } 1011 1012 return 0; 1013 1014 fail: 1015 free(kw); 1016 if (obj != NULL) { 1017 if (obj->oid != NULL) { 1018 RB_REMOVE(object_tree, &schema->objects, obj); 1019 free(obj->oid); 1020 } 1021 free(obj->desc); 1022 free(obj); 1023 } 1024 return -1; 1025 } 1026 1027 static int 1028 schema_parse_objectidentifier(struct schema *schema) 1029 { 1030 char *symname = NULL, *symoid = NULL; 1031 char *oid = NULL; 1032 1033 if (schema_lex(schema, &symname) != STRING) 1034 goto fail; 1035 if (schema_lex(schema, &symoid) != STRING) 1036 goto fail; 1037 1038 if (is_oidstr(symoid)) { 1039 oid = symoid; 1040 symoid = NULL; 1041 } else if ((oid = lookup_symbolic_oid(schema, symoid)) == NULL) 1042 goto fail; 1043 1044 if (push_symbolic_oid(schema, symname, oid) == NULL) 1045 goto fail; 1046 1047 free(symoid); 1048 return 0; 1049 1050 fail: 1051 free(symname); 1052 free(symoid); 1053 free(oid); 1054 return -1; 1055 } 1056 1057 int 1058 schema_parse(struct schema *schema, const char *filename) 1059 { 1060 char *kw; 1061 int token, ret = 0; 1062 1063 log_debug("parsing schema file '%s'", filename); 1064 1065 if ((schema->fp = fopen(filename, "r")) == NULL) { 1066 log_warn("%s", filename); 1067 return -1; 1068 } 1069 schema->filename = filename; 1070 schema->lineno = 1; 1071 1072 while (ret == 0) { 1073 token = schema_lex(schema, &kw); 1074 if (token == STRING) { 1075 if (strcasecmp(kw, "attributetype") == 0) 1076 ret = schema_parse_attributetype(schema); 1077 else if (strcasecmp(kw, "objectclass") == 0) 1078 ret = schema_parse_objectclass(schema); 1079 else if (strcasecmp(kw, "objectidentifier") == 0) 1080 ret = schema_parse_objectidentifier(schema); 1081 else { 1082 schema_err(schema, "syntax error at '%s'", kw); 1083 ret = -1; 1084 } 1085 if (ret == -1 && schema->error == 0) 1086 schema_err(schema, "syntax error"); 1087 free(kw); 1088 } else if (token == 0) { /* EOF */ 1089 break; 1090 } else { 1091 schema_err(schema, "syntax error"); 1092 ret = -1; 1093 } 1094 } 1095 1096 fclose(schema->fp); 1097 schema->fp = NULL; 1098 schema->filename = NULL; 1099 1100 return ret; 1101 } 1102 1103 static int 1104 schema_dump_names(const char *desc, struct name_list *nlist, 1105 char *buf, size_t size) 1106 { 1107 struct name *name; 1108 1109 if (nlist == NULL || SLIST_EMPTY(nlist)) 1110 return 0; 1111 1112 if (strlcat(buf, " ", size) >= size || 1113 strlcat(buf, desc, size) >= size) 1114 return -1; 1115 1116 name = SLIST_FIRST(nlist); 1117 if (SLIST_NEXT(name, next) == NULL) { 1118 /* single name, no parenthesis */ 1119 if (strlcat(buf, " '", size) >= size || 1120 strlcat(buf, name->name, size) >= size || 1121 strlcat(buf, "'", size) >= size) 1122 return -1; 1123 } else { 1124 if (strlcat(buf, " ( ", size) >= size) 1125 return -1; 1126 SLIST_FOREACH(name, nlist, next) 1127 if (strlcat(buf, "'", size) >= size || 1128 strlcat(buf, name->name, size) >= size || 1129 strlcat(buf, "' ", size) >= size) 1130 return -1; 1131 if (strlcat(buf, ")", size) >= size) 1132 return -1; 1133 } 1134 1135 return 0; 1136 } 1137 1138 static int 1139 schema_dump_attrlist(const char *desc, struct attr_list *alist, 1140 char *buf, size_t size) 1141 { 1142 struct attr_ptr *aptr; 1143 1144 if (alist == NULL || SLIST_EMPTY(alist)) 1145 return 0; 1146 1147 if (strlcat(buf, " ", size) >= size || 1148 strlcat(buf, desc, size) >= size) 1149 return -1; 1150 1151 aptr = SLIST_FIRST(alist); 1152 if (SLIST_NEXT(aptr, next) == NULL) { 1153 /* single attribute, no parenthesis */ 1154 if (strlcat(buf, " ", size) >= size || 1155 strlcat(buf, ATTR_NAME(aptr->attr_type), size) >= size) 1156 return -1; 1157 } else { 1158 if (strlcat(buf, " ( ", size) >= size) 1159 return -1; 1160 SLIST_FOREACH(aptr, alist, next) { 1161 if (strlcat(buf, ATTR_NAME(aptr->attr_type), 1162 size) >= size || 1163 strlcat(buf, " ", size) >= size) 1164 return -1; 1165 if (SLIST_NEXT(aptr, next) != NULL && 1166 strlcat(buf, "$ ", size) >= size) 1167 return -1; 1168 } 1169 if (strlcat(buf, ")", size) >= size) 1170 return -1; 1171 } 1172 1173 return 0; 1174 } 1175 1176 static int 1177 schema_dump_objlist(const char *desc, struct obj_list *olist, 1178 char *buf, size_t size) 1179 { 1180 struct obj_ptr *optr; 1181 1182 if (olist == NULL || SLIST_EMPTY(olist)) 1183 return 0; 1184 1185 if (strlcat(buf, " ", size) >= size || 1186 strlcat(buf, desc, size) >= size) 1187 return -1; 1188 1189 optr = SLIST_FIRST(olist); 1190 if (SLIST_NEXT(optr, next) == NULL) { 1191 /* single attribute, no parenthesis */ 1192 if (strlcat(buf, " ", size) >= size || 1193 strlcat(buf, OBJ_NAME(optr->object), size) >= size) 1194 return -1; 1195 } else { 1196 if (strlcat(buf, " ( ", size) >= size) 1197 return -1; 1198 SLIST_FOREACH(optr, olist, next) { 1199 if (strlcat(buf, OBJ_NAME(optr->object), size) >= size || 1200 strlcat(buf, " ", size) >= size) 1201 return -1; 1202 if (SLIST_NEXT(optr, next) != NULL && 1203 strlcat(buf, "$ ", size) >= size) 1204 return -1; 1205 } 1206 if (strlcat(buf, ")", size) >= size) 1207 return -1; 1208 } 1209 1210 return 0; 1211 } 1212 1213 int 1214 schema_dump_object(struct object *obj, char *buf, size_t size) 1215 { 1216 if (strlcpy(buf, "( ", size) >= size || 1217 strlcat(buf, obj->oid, size) >= size) 1218 return -1; 1219 1220 if (schema_dump_names("NAME", obj->names, buf, size) != 0) 1221 return -1; 1222 1223 if (obj->desc != NULL) 1224 if (strlcat(buf, " DESC '", size) >= size || 1225 strlcat(buf, obj->desc, size) >= size || 1226 strlcat(buf, "'", size) >= size) 1227 return -1; 1228 1229 switch (obj->kind) { 1230 case KIND_STRUCTURAL: 1231 if (strlcat(buf, " STRUCTURAL", size) >= size) 1232 return -1; 1233 break; 1234 case KIND_ABSTRACT: 1235 if (strlcat(buf, " ABSTRACT", size) >= size) 1236 return -1; 1237 break; 1238 case KIND_AUXILIARY: 1239 if (strlcat(buf, " AUXILIARY", size) >= size) 1240 return -1; 1241 break; 1242 } 1243 1244 if (schema_dump_objlist("SUP", obj->sup, buf, size) != 0) 1245 return -1; 1246 1247 if (obj->obsolete && strlcat(buf, " OBSOLETE", size) >= size) 1248 return -1; 1249 1250 if (schema_dump_attrlist("MUST", obj->must, buf, size) != 0) 1251 return -1; 1252 1253 if (schema_dump_attrlist("MAY", obj->may, buf, size) != 0) 1254 return -1; 1255 1256 if (strlcat(buf, " )", size) >= size) 1257 return -1; 1258 1259 return 0; 1260 } 1261 1262 int 1263 schema_dump_attribute(struct attr_type *at, char *buf, size_t size) 1264 { 1265 if (strlcpy(buf, "( ", size) >= size || 1266 strlcat(buf, at->oid, size) >= size) 1267 return -1; 1268 1269 if (schema_dump_names("NAME", at->names, buf, size) != 0) 1270 return -1; 1271 1272 if (at->desc != NULL) 1273 if (strlcat(buf, " DESC '", size) >= size || 1274 strlcat(buf, at->desc, size) >= size || 1275 strlcat(buf, "'", size) >= size) 1276 return -1; 1277 1278 if (at->obsolete && strlcat(buf, " OBSOLETE", size) >= size) 1279 return -1; 1280 1281 if (at->sup != NULL) 1282 if (strlcat(buf, " SUP ", size) >= size || 1283 strlcat(buf, ATTR_NAME(at->sup), size) >= size) 1284 return -1; 1285 1286 if (at->equality != NULL) 1287 if (strlcat(buf, " EQUALITY ", size) >= size || 1288 strlcat(buf, at->equality->name, size) >= size) 1289 return -1; 1290 1291 if (at->ordering != NULL) 1292 if (strlcat(buf, " ORDERING ", size) >= size || 1293 strlcat(buf, at->ordering->name, size) >= size) 1294 return -1; 1295 1296 if (at->substr != NULL) 1297 if (strlcat(buf, " SUBSTR ", size) >= size || 1298 strlcat(buf, at->substr->name, size) >= size) 1299 return -1; 1300 1301 if (at->syntax != NULL) 1302 if (strlcat(buf, " SYNTAX ", size) >= size || 1303 strlcat(buf, at->syntax->oid, size) >= size) 1304 return -1; 1305 1306 if (at->single && strlcat(buf, " SINGLE-VALUE", size) >= size) 1307 return -1; 1308 1309 if (at->collective && strlcat(buf, " COLLECTIVE", size) >= size) 1310 return -1; 1311 1312 if (at->immutable && strlcat(buf, " NO-USER-MODIFICATION", size) >= size) 1313 return -1; 1314 1315 switch (at->usage) { 1316 case USAGE_USER_APP: 1317 /* User application usage is the default. */ 1318 break; 1319 case USAGE_DIR_OP: 1320 if (strlcat(buf, " USAGE directoryOperation", size) >= size) 1321 return -1; 1322 break; 1323 case USAGE_DIST_OP: 1324 if (strlcat(buf, " USAGE distributedOperation", size) >= size) 1325 return -1; 1326 break; 1327 case USAGE_DSA_OP: 1328 if (strlcat(buf, " USAGE dSAOperation", size) >= size) 1329 return -1; 1330 break; 1331 } 1332 1333 if (strlcat(buf, " )", size) >= size) 1334 return -1; 1335 1336 return 0; 1337 } 1338 1339 int 1340 schema_dump_match_rule(struct match_rule *mr, char *buf, size_t size) 1341 { 1342 if (strlcpy(buf, "( ", size) >= size || 1343 strlcat(buf, mr->oid, size) >= size || 1344 strlcat(buf, " NAME '", size) >= size || 1345 strlcat(buf, mr->name, size) >= size || 1346 strlcat(buf, "' SYNTAX ", size) >= size || 1347 strlcat(buf, mr->syntax_oid, size) >= size || 1348 strlcat(buf, " )", size) >= size) 1349 return -1; 1350 1351 return 0; 1352 } 1353 1354