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