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