1 /* $NetBSD: schema.c,v 1.2 2020/08/11 13:15:37 christos Exp $ */ 2 3 /* $OpenLDAP$ */ 4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 5 * 6 * Copyright 1998-2020 The OpenLDAP Foundation. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted only as authorized by the OpenLDAP 11 * Public License. 12 * 13 * A copy of this license is available in the file LICENSE in the 14 * top-level directory of the distribution or, alternatively, at 15 * <http://www.OpenLDAP.org/license.html>. 16 */ 17 18 /* 19 * schema.c: parsing routines used by servers and clients to process 20 * schema definitions 21 */ 22 23 #include <sys/cdefs.h> 24 __RCSID("$NetBSD: schema.c,v 1.2 2020/08/11 13:15:37 christos Exp $"); 25 26 #include "portable.h" 27 28 #include <stdio.h> 29 #include <ac/stdlib.h> 30 31 #include <ac/string.h> 32 #include <ac/time.h> 33 34 #include "ldap-int.h" 35 36 #include <ldap_schema.h> 37 38 static const char EndOfInput[] = "end of input"; 39 40 static const char * 41 choose_name( char *names[], const char *fallback ) 42 { 43 return (names != NULL && names[0] != NULL) ? names[0] : fallback; 44 } 45 46 LDAP_CONST char * 47 ldap_syntax2name( LDAPSyntax * syn ) 48 { 49 if (!syn) return NULL; 50 return( syn->syn_oid ); 51 } 52 53 LDAP_CONST char * 54 ldap_matchingrule2name( LDAPMatchingRule * mr ) 55 { 56 if (!mr) return NULL; 57 return( choose_name( mr->mr_names, mr->mr_oid ) ); 58 } 59 60 LDAP_CONST char * 61 ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru ) 62 { 63 if (!mru) return NULL; 64 return( choose_name( mru->mru_names, mru->mru_oid ) ); 65 } 66 67 LDAP_CONST char * 68 ldap_attributetype2name( LDAPAttributeType * at ) 69 { 70 if (!at) return NULL; 71 return( choose_name( at->at_names, at->at_oid ) ); 72 } 73 74 LDAP_CONST char * 75 ldap_objectclass2name( LDAPObjectClass * oc ) 76 { 77 if (!oc) return NULL; 78 return( choose_name( oc->oc_names, oc->oc_oid ) ); 79 } 80 81 LDAP_CONST char * 82 ldap_contentrule2name( LDAPContentRule * cr ) 83 { 84 if (!cr) return NULL; 85 return( choose_name( cr->cr_names, cr->cr_oid ) ); 86 } 87 88 LDAP_CONST char * 89 ldap_nameform2name( LDAPNameForm * nf ) 90 { 91 if (!nf) return NULL; 92 return( choose_name( nf->nf_names, nf->nf_oid ) ); 93 } 94 95 LDAP_CONST char * 96 ldap_structurerule2name( LDAPStructureRule * sr ) 97 { 98 if (!sr) return NULL; 99 return( choose_name( sr->sr_names, NULL ) ); 100 } 101 102 /* 103 * When pretty printing the entities we will be appending to a buffer. 104 * Since checking for overflow, realloc'ing and checking if no error 105 * is extremely boring, we will use a protection layer that will let 106 * us blissfully ignore the error until the end. This layer is 107 * implemented with the help of the next type. 108 */ 109 110 typedef struct safe_string { 111 char * val; 112 ber_len_t size; 113 ber_len_t pos; 114 int at_whsp; 115 } safe_string; 116 117 static safe_string * 118 new_safe_string(int size) 119 { 120 safe_string * ss; 121 122 ss = LDAP_MALLOC(sizeof(safe_string)); 123 if ( !ss ) 124 return(NULL); 125 126 ss->val = LDAP_MALLOC(size); 127 if ( !ss->val ) { 128 LDAP_FREE(ss); 129 return(NULL); 130 } 131 132 ss->size = size; 133 ss->pos = 0; 134 ss->at_whsp = 0; 135 136 return ss; 137 } 138 139 static void 140 safe_string_free(safe_string * ss) 141 { 142 if ( !ss ) 143 return; 144 LDAP_FREE(ss->val); 145 LDAP_FREE(ss); 146 } 147 148 #if 0 /* unused */ 149 static char * 150 safe_string_val(safe_string * ss) 151 { 152 ss->val[ss->pos] = '\0'; 153 return(ss->val); 154 } 155 #endif 156 157 static char * 158 safe_strdup(safe_string * ss) 159 { 160 char *ret = LDAP_MALLOC(ss->pos+1); 161 if (!ret) 162 return NULL; 163 AC_MEMCPY(ret, ss->val, ss->pos); 164 ret[ss->pos] = '\0'; 165 return ret; 166 } 167 168 static int 169 append_to_safe_string(safe_string * ss, char * s) 170 { 171 int l = strlen(s); 172 char * temp; 173 174 /* 175 * Some runaway process is trying to append to a string that 176 * overflowed and we could not extend. 177 */ 178 if ( !ss->val ) 179 return -1; 180 181 /* We always make sure there is at least one position available */ 182 if ( ss->pos + l >= ss->size-1 ) { 183 ss->size *= 2; 184 if ( ss->pos + l >= ss->size-1 ) { 185 ss->size = ss->pos + l + 1; 186 } 187 188 temp = LDAP_REALLOC(ss->val, ss->size); 189 if ( !temp ) { 190 /* Trouble, out of memory */ 191 LDAP_FREE(ss->val); 192 return -1; 193 } 194 ss->val = temp; 195 } 196 strncpy(&ss->val[ss->pos], s, l); 197 ss->pos += l; 198 if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) ) 199 ss->at_whsp = 1; 200 else 201 ss->at_whsp = 0; 202 203 return 0; 204 } 205 206 static int 207 print_literal(safe_string *ss, char *s) 208 { 209 return(append_to_safe_string(ss,s)); 210 } 211 212 static int 213 print_whsp(safe_string *ss) 214 { 215 if ( ss->at_whsp ) 216 return(append_to_safe_string(ss,"")); 217 else 218 return(append_to_safe_string(ss," ")); 219 } 220 221 static int 222 print_numericoid(safe_string *ss, char *s) 223 { 224 if ( s ) 225 return(append_to_safe_string(ss,s)); 226 else 227 return(append_to_safe_string(ss,"")); 228 } 229 230 /* This one is identical to print_qdescr */ 231 static int 232 print_qdstring(safe_string *ss, char *s) 233 { 234 print_whsp(ss); 235 print_literal(ss,"'"); 236 append_to_safe_string(ss,s); 237 print_literal(ss,"'"); 238 return(print_whsp(ss)); 239 } 240 241 static int 242 print_qdescr(safe_string *ss, char *s) 243 { 244 print_whsp(ss); 245 print_literal(ss,"'"); 246 append_to_safe_string(ss,s); 247 print_literal(ss,"'"); 248 return(print_whsp(ss)); 249 } 250 251 static int 252 print_qdescrlist(safe_string *ss, char **sa) 253 { 254 char **sp; 255 int ret = 0; 256 257 for (sp=sa; *sp; sp++) { 258 ret = print_qdescr(ss,*sp); 259 } 260 /* If the list was empty, we return zero that is potentially 261 * incorrect, but since we will be still appending things, the 262 * overflow will be detected later. Maybe FIX. 263 */ 264 return(ret); 265 } 266 267 static int 268 print_qdescrs(safe_string *ss, char **sa) 269 { 270 /* The only way to represent an empty list is as a qdescrlist 271 * so, if the list is empty we treat it as a long list. 272 * Really, this is what the syntax mandates. We should not 273 * be here if the list was empty, but if it happens, a label 274 * has already been output and we cannot undo it. 275 */ 276 if ( !sa[0] || ( sa[0] && sa[1] ) ) { 277 print_whsp(ss); 278 print_literal(ss,"("/*)*/); 279 print_qdescrlist(ss,sa); 280 print_literal(ss,/*(*/")"); 281 return(print_whsp(ss)); 282 } else { 283 return(print_qdescr(ss,*sa)); 284 } 285 } 286 287 static int 288 print_woid(safe_string *ss, char *s) 289 { 290 print_whsp(ss); 291 append_to_safe_string(ss,s); 292 return print_whsp(ss); 293 } 294 295 static int 296 print_oidlist(safe_string *ss, char **sa) 297 { 298 char **sp; 299 300 for (sp=sa; *(sp+1); sp++) { 301 print_woid(ss,*sp); 302 print_literal(ss,"$"); 303 } 304 return(print_woid(ss,*sp)); 305 } 306 307 static int 308 print_oids(safe_string *ss, char **sa) 309 { 310 if ( sa[0] && sa[1] ) { 311 print_literal(ss,"("/*)*/); 312 print_oidlist(ss,sa); 313 print_whsp(ss); 314 return(print_literal(ss,/*(*/")")); 315 } else { 316 return(print_woid(ss,*sa)); 317 } 318 } 319 320 static int 321 print_noidlen(safe_string *ss, char *s, int l) 322 { 323 char buf[64]; 324 int ret; 325 326 ret = print_numericoid(ss,s); 327 if ( l ) { 328 snprintf(buf, sizeof buf, "{%d}",l); 329 ret = print_literal(ss,buf); 330 } 331 return(ret); 332 } 333 334 static int 335 print_ruleid(safe_string *ss, int rid) 336 { 337 char buf[64]; 338 snprintf(buf, sizeof buf, "%d", rid); 339 return print_literal(ss,buf); 340 } 341 342 static int 343 print_ruleids(safe_string *ss, int n, int *rids) 344 { 345 int i; 346 347 if( n == 1 ) { 348 print_ruleid(ss,rids[0]); 349 return print_whsp(ss); 350 } else { 351 print_literal(ss,"("/*)*/); 352 for( i=0; i<n; i++ ) { 353 print_whsp(ss); 354 print_ruleid(ss,rids[i]); 355 } 356 print_whsp(ss); 357 return print_literal(ss,/*(*/")"); 358 } 359 } 360 361 362 static int 363 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions) 364 { 365 LDAPSchemaExtensionItem **ext; 366 367 if ( extensions ) { 368 print_whsp(ss); 369 for ( ext = extensions; *ext != NULL; ext++ ) { 370 print_literal(ss, (*ext)->lsei_name); 371 print_whsp(ss); 372 /* Should be print_qdstrings */ 373 print_qdescrs(ss, (*ext)->lsei_values); 374 print_whsp(ss); 375 } 376 } 377 378 return 0; 379 } 380 381 char * 382 ldap_syntax2str( LDAPSyntax * syn ) 383 { 384 struct berval bv; 385 if (ldap_syntax2bv( syn, &bv )) 386 return(bv.bv_val); 387 else 388 return NULL; 389 } 390 391 struct berval * 392 ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv ) 393 { 394 safe_string * ss; 395 396 if ( !syn || !bv ) 397 return NULL; 398 399 ss = new_safe_string(256); 400 if ( !ss ) 401 return NULL; 402 403 print_literal(ss,"("/*)*/); 404 print_whsp(ss); 405 406 print_numericoid(ss, syn->syn_oid); 407 print_whsp(ss); 408 409 if ( syn->syn_desc ) { 410 print_literal(ss,"DESC"); 411 print_qdstring(ss,syn->syn_desc); 412 } 413 414 print_whsp(ss); 415 416 print_extensions(ss, syn->syn_extensions); 417 418 print_literal(ss,/*(*/ ")"); 419 420 bv->bv_val = safe_strdup(ss); 421 bv->bv_len = ss->pos; 422 safe_string_free(ss); 423 return(bv); 424 } 425 426 char * 427 ldap_matchingrule2str( LDAPMatchingRule * mr ) 428 { 429 struct berval bv; 430 if (ldap_matchingrule2bv( mr, &bv )) 431 return(bv.bv_val); 432 else 433 return NULL; 434 } 435 436 struct berval * 437 ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv ) 438 { 439 safe_string * ss; 440 441 if ( !mr || !bv ) 442 return NULL; 443 444 ss = new_safe_string(256); 445 if ( !ss ) 446 return NULL; 447 448 print_literal(ss,"(" /*)*/); 449 print_whsp(ss); 450 451 print_numericoid(ss, mr->mr_oid); 452 print_whsp(ss); 453 454 if ( mr->mr_names ) { 455 print_literal(ss,"NAME"); 456 print_qdescrs(ss,mr->mr_names); 457 } 458 459 if ( mr->mr_desc ) { 460 print_literal(ss,"DESC"); 461 print_qdstring(ss,mr->mr_desc); 462 } 463 464 if ( mr->mr_obsolete ) { 465 print_literal(ss, "OBSOLETE"); 466 print_whsp(ss); 467 } 468 469 if ( mr->mr_syntax_oid ) { 470 print_literal(ss,"SYNTAX"); 471 print_whsp(ss); 472 print_literal(ss, mr->mr_syntax_oid); 473 print_whsp(ss); 474 } 475 476 print_whsp(ss); 477 478 print_extensions(ss, mr->mr_extensions); 479 480 print_literal(ss,/*(*/")"); 481 482 bv->bv_val = safe_strdup(ss); 483 bv->bv_len = ss->pos; 484 safe_string_free(ss); 485 return(bv); 486 } 487 488 char * 489 ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru ) 490 { 491 struct berval bv; 492 if (ldap_matchingruleuse2bv( mru, &bv )) 493 return(bv.bv_val); 494 else 495 return NULL; 496 } 497 498 struct berval * 499 ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv ) 500 { 501 safe_string * ss; 502 503 if ( !mru || !bv ) 504 return NULL; 505 506 ss = new_safe_string(256); 507 if ( !ss ) 508 return NULL; 509 510 print_literal(ss,"(" /*)*/); 511 print_whsp(ss); 512 513 print_numericoid(ss, mru->mru_oid); 514 print_whsp(ss); 515 516 if ( mru->mru_names ) { 517 print_literal(ss,"NAME"); 518 print_qdescrs(ss,mru->mru_names); 519 } 520 521 if ( mru->mru_desc ) { 522 print_literal(ss,"DESC"); 523 print_qdstring(ss,mru->mru_desc); 524 } 525 526 if ( mru->mru_obsolete ) { 527 print_literal(ss, "OBSOLETE"); 528 print_whsp(ss); 529 } 530 531 if ( mru->mru_applies_oids ) { 532 print_literal(ss,"APPLIES"); 533 print_whsp(ss); 534 print_oids(ss, mru->mru_applies_oids); 535 print_whsp(ss); 536 } 537 538 print_whsp(ss); 539 540 print_extensions(ss, mru->mru_extensions); 541 542 print_literal(ss,/*(*/")"); 543 544 bv->bv_val = safe_strdup(ss); 545 bv->bv_len = ss->pos; 546 safe_string_free(ss); 547 return(bv); 548 } 549 550 char * 551 ldap_objectclass2str( LDAPObjectClass * oc ) 552 { 553 struct berval bv; 554 if (ldap_objectclass2bv( oc, &bv )) 555 return(bv.bv_val); 556 else 557 return NULL; 558 } 559 560 struct berval * 561 ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv ) 562 { 563 safe_string * ss; 564 565 if ( !oc || !bv ) 566 return NULL; 567 568 ss = new_safe_string(256); 569 if ( !ss ) 570 return NULL; 571 572 print_literal(ss,"("/*)*/); 573 print_whsp(ss); 574 575 print_numericoid(ss, oc->oc_oid); 576 print_whsp(ss); 577 578 if ( oc->oc_names ) { 579 print_literal(ss,"NAME"); 580 print_qdescrs(ss,oc->oc_names); 581 } 582 583 if ( oc->oc_desc ) { 584 print_literal(ss,"DESC"); 585 print_qdstring(ss,oc->oc_desc); 586 } 587 588 if ( oc->oc_obsolete ) { 589 print_literal(ss, "OBSOLETE"); 590 print_whsp(ss); 591 } 592 593 if ( oc->oc_sup_oids ) { 594 print_literal(ss,"SUP"); 595 print_whsp(ss); 596 print_oids(ss,oc->oc_sup_oids); 597 print_whsp(ss); 598 } 599 600 switch (oc->oc_kind) { 601 case LDAP_SCHEMA_ABSTRACT: 602 print_literal(ss,"ABSTRACT"); 603 break; 604 case LDAP_SCHEMA_STRUCTURAL: 605 print_literal(ss,"STRUCTURAL"); 606 break; 607 case LDAP_SCHEMA_AUXILIARY: 608 print_literal(ss,"AUXILIARY"); 609 break; 610 default: 611 print_literal(ss,"KIND-UNKNOWN"); 612 break; 613 } 614 print_whsp(ss); 615 616 if ( oc->oc_at_oids_must ) { 617 print_literal(ss,"MUST"); 618 print_whsp(ss); 619 print_oids(ss,oc->oc_at_oids_must); 620 print_whsp(ss); 621 } 622 623 if ( oc->oc_at_oids_may ) { 624 print_literal(ss,"MAY"); 625 print_whsp(ss); 626 print_oids(ss,oc->oc_at_oids_may); 627 print_whsp(ss); 628 } 629 630 print_whsp(ss); 631 632 print_extensions(ss, oc->oc_extensions); 633 634 print_literal(ss, /*(*/")"); 635 636 bv->bv_val = safe_strdup(ss); 637 bv->bv_len = ss->pos; 638 safe_string_free(ss); 639 return(bv); 640 } 641 642 char * 643 ldap_contentrule2str( LDAPContentRule * cr ) 644 { 645 struct berval bv; 646 if (ldap_contentrule2bv( cr, &bv )) 647 return(bv.bv_val); 648 else 649 return NULL; 650 } 651 652 struct berval * 653 ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv ) 654 { 655 safe_string * ss; 656 657 if ( !cr || !bv ) 658 return NULL; 659 660 ss = new_safe_string(256); 661 if ( !ss ) 662 return NULL; 663 664 print_literal(ss,"("/*)*/); 665 print_whsp(ss); 666 667 print_numericoid(ss, cr->cr_oid); 668 print_whsp(ss); 669 670 if ( cr->cr_names ) { 671 print_literal(ss,"NAME"); 672 print_qdescrs(ss,cr->cr_names); 673 } 674 675 if ( cr->cr_desc ) { 676 print_literal(ss,"DESC"); 677 print_qdstring(ss,cr->cr_desc); 678 } 679 680 if ( cr->cr_obsolete ) { 681 print_literal(ss, "OBSOLETE"); 682 print_whsp(ss); 683 } 684 685 if ( cr->cr_oc_oids_aux ) { 686 print_literal(ss,"AUX"); 687 print_whsp(ss); 688 print_oids(ss,cr->cr_oc_oids_aux); 689 print_whsp(ss); 690 } 691 692 if ( cr->cr_at_oids_must ) { 693 print_literal(ss,"MUST"); 694 print_whsp(ss); 695 print_oids(ss,cr->cr_at_oids_must); 696 print_whsp(ss); 697 } 698 699 if ( cr->cr_at_oids_may ) { 700 print_literal(ss,"MAY"); 701 print_whsp(ss); 702 print_oids(ss,cr->cr_at_oids_may); 703 print_whsp(ss); 704 } 705 706 if ( cr->cr_at_oids_not ) { 707 print_literal(ss,"NOT"); 708 print_whsp(ss); 709 print_oids(ss,cr->cr_at_oids_not); 710 print_whsp(ss); 711 } 712 713 print_whsp(ss); 714 print_extensions(ss, cr->cr_extensions); 715 716 print_literal(ss, /*(*/")"); 717 718 bv->bv_val = safe_strdup(ss); 719 bv->bv_len = ss->pos; 720 safe_string_free(ss); 721 return(bv); 722 } 723 724 char * 725 ldap_structurerule2str( LDAPStructureRule * sr ) 726 { 727 struct berval bv; 728 if (ldap_structurerule2bv( sr, &bv )) 729 return(bv.bv_val); 730 else 731 return NULL; 732 } 733 734 struct berval * 735 ldap_structurerule2bv( LDAPStructureRule * sr, struct berval *bv ) 736 { 737 safe_string * ss; 738 739 if ( !sr || !bv ) 740 return NULL; 741 742 ss = new_safe_string(256); 743 if ( !ss ) 744 return NULL; 745 746 print_literal(ss,"("/*)*/); 747 print_whsp(ss); 748 749 print_ruleid(ss, sr->sr_ruleid); 750 print_whsp(ss); 751 752 if ( sr->sr_names ) { 753 print_literal(ss,"NAME"); 754 print_qdescrs(ss,sr->sr_names); 755 } 756 757 if ( sr->sr_desc ) { 758 print_literal(ss,"DESC"); 759 print_qdstring(ss,sr->sr_desc); 760 } 761 762 if ( sr->sr_obsolete ) { 763 print_literal(ss, "OBSOLETE"); 764 print_whsp(ss); 765 } 766 767 print_literal(ss,"FORM"); 768 print_whsp(ss); 769 print_woid(ss,sr->sr_nameform); 770 print_whsp(ss); 771 772 if ( sr->sr_nsup_ruleids ) { 773 print_literal(ss,"SUP"); 774 print_whsp(ss); 775 print_ruleids(ss,sr->sr_nsup_ruleids,sr->sr_sup_ruleids); 776 print_whsp(ss); 777 } 778 779 print_whsp(ss); 780 print_extensions(ss, sr->sr_extensions); 781 782 print_literal(ss, /*(*/")"); 783 784 bv->bv_val = safe_strdup(ss); 785 bv->bv_len = ss->pos; 786 safe_string_free(ss); 787 return(bv); 788 } 789 790 791 char * 792 ldap_nameform2str( LDAPNameForm * nf ) 793 { 794 struct berval bv; 795 if (ldap_nameform2bv( nf, &bv )) 796 return(bv.bv_val); 797 else 798 return NULL; 799 } 800 801 struct berval * 802 ldap_nameform2bv( LDAPNameForm * nf, struct berval *bv ) 803 { 804 safe_string * ss; 805 806 if ( !nf || !bv ) 807 return NULL; 808 809 ss = new_safe_string(256); 810 if ( !ss ) 811 return NULL; 812 813 print_literal(ss,"("/*)*/); 814 print_whsp(ss); 815 816 print_numericoid(ss, nf->nf_oid); 817 print_whsp(ss); 818 819 if ( nf->nf_names ) { 820 print_literal(ss,"NAME"); 821 print_qdescrs(ss,nf->nf_names); 822 } 823 824 if ( nf->nf_desc ) { 825 print_literal(ss,"DESC"); 826 print_qdstring(ss,nf->nf_desc); 827 } 828 829 if ( nf->nf_obsolete ) { 830 print_literal(ss, "OBSOLETE"); 831 print_whsp(ss); 832 } 833 834 print_literal(ss,"OC"); 835 print_whsp(ss); 836 print_woid(ss,nf->nf_objectclass); 837 print_whsp(ss); 838 839 print_literal(ss,"MUST"); 840 print_whsp(ss); 841 print_oids(ss,nf->nf_at_oids_must); 842 print_whsp(ss); 843 844 845 if ( nf->nf_at_oids_may ) { 846 print_literal(ss,"MAY"); 847 print_whsp(ss); 848 print_oids(ss,nf->nf_at_oids_may); 849 print_whsp(ss); 850 } 851 852 print_whsp(ss); 853 print_extensions(ss, nf->nf_extensions); 854 855 print_literal(ss, /*(*/")"); 856 857 bv->bv_val = safe_strdup(ss); 858 bv->bv_len = ss->pos; 859 safe_string_free(ss); 860 return(bv); 861 } 862 863 char * 864 ldap_attributetype2str( LDAPAttributeType * at ) 865 { 866 struct berval bv; 867 if (ldap_attributetype2bv( at, &bv )) 868 return(bv.bv_val); 869 else 870 return NULL; 871 } 872 873 struct berval * 874 ldap_attributetype2bv( LDAPAttributeType * at, struct berval *bv ) 875 { 876 safe_string * ss; 877 878 if ( !at || !bv ) 879 return NULL; 880 881 ss = new_safe_string(256); 882 if ( !ss ) 883 return NULL; 884 885 print_literal(ss,"("/*)*/); 886 print_whsp(ss); 887 888 print_numericoid(ss, at->at_oid); 889 print_whsp(ss); 890 891 if ( at->at_names ) { 892 print_literal(ss,"NAME"); 893 print_qdescrs(ss,at->at_names); 894 } 895 896 if ( at->at_desc ) { 897 print_literal(ss,"DESC"); 898 print_qdstring(ss,at->at_desc); 899 } 900 901 if ( at->at_obsolete ) { 902 print_literal(ss, "OBSOLETE"); 903 print_whsp(ss); 904 } 905 906 if ( at->at_sup_oid ) { 907 print_literal(ss,"SUP"); 908 print_woid(ss,at->at_sup_oid); 909 } 910 911 if ( at->at_equality_oid ) { 912 print_literal(ss,"EQUALITY"); 913 print_woid(ss,at->at_equality_oid); 914 } 915 916 if ( at->at_ordering_oid ) { 917 print_literal(ss,"ORDERING"); 918 print_woid(ss,at->at_ordering_oid); 919 } 920 921 if ( at->at_substr_oid ) { 922 print_literal(ss,"SUBSTR"); 923 print_woid(ss,at->at_substr_oid); 924 } 925 926 if ( at->at_syntax_oid ) { 927 print_literal(ss,"SYNTAX"); 928 print_whsp(ss); 929 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len); 930 print_whsp(ss); 931 } 932 933 if ( at->at_single_value == LDAP_SCHEMA_YES ) { 934 print_literal(ss,"SINGLE-VALUE"); 935 print_whsp(ss); 936 } 937 938 if ( at->at_collective == LDAP_SCHEMA_YES ) { 939 print_literal(ss,"COLLECTIVE"); 940 print_whsp(ss); 941 } 942 943 if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) { 944 print_literal(ss,"NO-USER-MODIFICATION"); 945 print_whsp(ss); 946 } 947 948 if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) { 949 print_literal(ss,"USAGE"); 950 print_whsp(ss); 951 switch (at->at_usage) { 952 case LDAP_SCHEMA_DIRECTORY_OPERATION: 953 print_literal(ss,"directoryOperation"); 954 break; 955 case LDAP_SCHEMA_DISTRIBUTED_OPERATION: 956 print_literal(ss,"distributedOperation"); 957 break; 958 case LDAP_SCHEMA_DSA_OPERATION: 959 print_literal(ss,"dSAOperation"); 960 break; 961 default: 962 print_literal(ss,"UNKNOWN"); 963 break; 964 } 965 } 966 967 print_whsp(ss); 968 969 print_extensions(ss, at->at_extensions); 970 971 print_literal(ss,/*(*/")"); 972 973 bv->bv_val = safe_strdup(ss); 974 bv->bv_len = ss->pos; 975 safe_string_free(ss); 976 return(bv); 977 } 978 979 /* 980 * Now come the parsers. There is one parser for each entity type: 981 * objectclasses, attributetypes, etc. 982 * 983 * Each of them is written as a recursive-descent parser, except that 984 * none of them is really recursive. But the idea is kept: there 985 * is one routine per non-terminal that eithers gobbles lexical tokens 986 * or calls lower-level routines, etc. 987 * 988 * The scanner is implemented in the routine get_token. Actually, 989 * get_token is more than a scanner and will return tokens that are 990 * in fact non-terminals in the grammar. So you can see the whole 991 * approach as the combination of a low-level bottom-up recognizer 992 * combined with a scanner and a number of top-down parsers. Or just 993 * consider that the real grammars recognized by the parsers are not 994 * those of the standards. As a matter of fact, our parsers are more 995 * liberal than the spec when there is no ambiguity. 996 * 997 * The difference is pretty academic (modulo bugs or incorrect 998 * interpretation of the specs). 999 */ 1000 1001 typedef enum tk_t { 1002 TK_NOENDQUOTE = -2, 1003 TK_OUTOFMEM = -1, 1004 TK_EOS = 0, 1005 TK_UNEXPCHAR = 1, 1006 TK_BAREWORD = 2, 1007 TK_QDSTRING = 3, 1008 TK_LEFTPAREN = 4, 1009 TK_RIGHTPAREN = 5, 1010 TK_DOLLAR = 6, 1011 TK_QDESCR = TK_QDSTRING 1012 } tk_t; 1013 1014 static tk_t 1015 get_token( const char ** sp, char ** token_val ) 1016 { 1017 tk_t kind; 1018 const char * p; 1019 const char * q; 1020 char * res; 1021 1022 *token_val = NULL; 1023 switch (**sp) { 1024 case '\0': 1025 kind = TK_EOS; 1026 (*sp)++; 1027 break; 1028 case '(': 1029 kind = TK_LEFTPAREN; 1030 (*sp)++; 1031 break; 1032 case ')': 1033 kind = TK_RIGHTPAREN; 1034 (*sp)++; 1035 break; 1036 case '$': 1037 kind = TK_DOLLAR; 1038 (*sp)++; 1039 break; 1040 case '\'': 1041 kind = TK_QDSTRING; 1042 (*sp)++; 1043 p = *sp; 1044 while ( **sp != '\'' && **sp != '\0' ) 1045 (*sp)++; 1046 if ( **sp == '\'' ) { 1047 q = *sp; 1048 res = LDAP_MALLOC(q-p+1); 1049 if ( !res ) { 1050 kind = TK_OUTOFMEM; 1051 } else { 1052 strncpy(res,p,q-p); 1053 res[q-p] = '\0'; 1054 *token_val = res; 1055 } 1056 (*sp)++; 1057 } else { 1058 kind = TK_NOENDQUOTE; 1059 } 1060 break; 1061 default: 1062 kind = TK_BAREWORD; 1063 p = *sp; 1064 while ( !LDAP_SPACE(**sp) && 1065 **sp != '(' && 1066 **sp != ')' && 1067 **sp != '$' && 1068 **sp != '\'' && 1069 /* for suggested minimum upper bound on the number 1070 * of characters (RFC 4517) */ 1071 **sp != '{' && 1072 **sp != '\0' ) 1073 (*sp)++; 1074 q = *sp; 1075 res = LDAP_MALLOC(q-p+1); 1076 if ( !res ) { 1077 kind = TK_OUTOFMEM; 1078 } else { 1079 strncpy(res,p,q-p); 1080 res[q-p] = '\0'; 1081 *token_val = res; 1082 } 1083 break; 1084 /* kind = TK_UNEXPCHAR; */ 1085 /* break; */ 1086 } 1087 1088 return kind; 1089 } 1090 1091 /* Gobble optional whitespace */ 1092 static void 1093 parse_whsp(const char **sp) 1094 { 1095 while (LDAP_SPACE(**sp)) 1096 (*sp)++; 1097 } 1098 1099 /* TBC:!! 1100 * General note for all parsers: to guarantee the algorithm halts they 1101 * must always advance the pointer even when an error is found. For 1102 * this one is not that important since an error here is fatal at the 1103 * upper layers, but it is a simple strategy that will not get in 1104 * endless loops. 1105 */ 1106 1107 /* Parse a sequence of dot-separated decimal strings */ 1108 char * 1109 ldap_int_parse_numericoid(const char **sp, int *code, const int flags) 1110 { 1111 char * res = NULL; 1112 const char * start = *sp; 1113 int len; 1114 int quoted = 0; 1115 1116 /* Netscape puts the SYNTAX value in quotes (incorrectly) */ 1117 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) { 1118 quoted = 1; 1119 (*sp)++; 1120 start++; 1121 } 1122 /* Each iteration of this loop gets one decimal string */ 1123 while (**sp) { 1124 if ( !LDAP_DIGIT(**sp) ) { 1125 /* 1126 * Initial char is not a digit or char after dot is 1127 * not a digit 1128 */ 1129 *code = LDAP_SCHERR_NODIGIT; 1130 return NULL; 1131 } 1132 (*sp)++; 1133 while ( LDAP_DIGIT(**sp) ) 1134 (*sp)++; 1135 if ( **sp != '.' ) 1136 break; 1137 /* Otherwise, gobble the dot and loop again */ 1138 (*sp)++; 1139 } 1140 /* Now *sp points at the char past the numericoid. Perfect. */ 1141 len = *sp - start; 1142 if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) { 1143 if ( **sp == '\'' ) { 1144 (*sp)++; 1145 } else { 1146 *code = LDAP_SCHERR_UNEXPTOKEN; 1147 return NULL; 1148 } 1149 } 1150 if (flags & LDAP_SCHEMA_SKIP) { 1151 res = (char *)start; 1152 } else { 1153 res = LDAP_MALLOC(len+1); 1154 if (!res) { 1155 *code = LDAP_SCHERR_OUTOFMEM; 1156 return(NULL); 1157 } 1158 strncpy(res,start,len); 1159 res[len] = '\0'; 1160 } 1161 return(res); 1162 } 1163 1164 /* Parse a sequence of dot-separated decimal strings */ 1165 int 1166 ldap_int_parse_ruleid(const char **sp, int *code, const int flags, int *ruleid) 1167 { 1168 *ruleid=0; 1169 1170 if ( !LDAP_DIGIT(**sp) ) { 1171 *code = LDAP_SCHERR_NODIGIT; 1172 return -1; 1173 } 1174 *ruleid = (**sp) - '0'; 1175 (*sp)++; 1176 1177 while ( LDAP_DIGIT(**sp) ) { 1178 *ruleid *= 10; 1179 *ruleid += (**sp) - '0'; 1180 (*sp)++; 1181 } 1182 1183 return 0; 1184 } 1185 1186 /* Parse a qdescr or a list of them enclosed in () */ 1187 static char ** 1188 parse_qdescrs(const char **sp, int *code) 1189 { 1190 char ** res; 1191 char ** res1; 1192 tk_t kind; 1193 char * sval; 1194 int size; 1195 int pos; 1196 1197 parse_whsp(sp); 1198 kind = get_token(sp,&sval); 1199 if ( kind == TK_LEFTPAREN ) { 1200 /* Let's presume there will be at least 2 entries */ 1201 size = 3; 1202 res = LDAP_CALLOC(3,sizeof(char *)); 1203 if ( !res ) { 1204 *code = LDAP_SCHERR_OUTOFMEM; 1205 return NULL; 1206 } 1207 pos = 0; 1208 while (1) { 1209 parse_whsp(sp); 1210 kind = get_token(sp,&sval); 1211 if ( kind == TK_RIGHTPAREN ) 1212 break; 1213 if ( kind == TK_QDESCR ) { 1214 if ( pos == size-2 ) { 1215 size++; 1216 res1 = LDAP_REALLOC(res,size*sizeof(char *)); 1217 if ( !res1 ) { 1218 LDAP_VFREE(res); 1219 LDAP_FREE(sval); 1220 *code = LDAP_SCHERR_OUTOFMEM; 1221 return(NULL); 1222 } 1223 res = res1; 1224 } 1225 res[pos++] = sval; 1226 res[pos] = NULL; 1227 parse_whsp(sp); 1228 } else { 1229 LDAP_VFREE(res); 1230 LDAP_FREE(sval); 1231 *code = LDAP_SCHERR_UNEXPTOKEN; 1232 return(NULL); 1233 } 1234 } 1235 parse_whsp(sp); 1236 return(res); 1237 } else if ( kind == TK_QDESCR ) { 1238 res = LDAP_CALLOC(2,sizeof(char *)); 1239 if ( !res ) { 1240 *code = LDAP_SCHERR_OUTOFMEM; 1241 return NULL; 1242 } 1243 res[0] = sval; 1244 res[1] = NULL; 1245 parse_whsp(sp); 1246 return res; 1247 } else { 1248 LDAP_FREE(sval); 1249 *code = LDAP_SCHERR_BADNAME; 1250 return NULL; 1251 } 1252 } 1253 1254 /* Parse a woid */ 1255 static char * 1256 parse_woid(const char **sp, int *code) 1257 { 1258 char * sval; 1259 tk_t kind; 1260 1261 parse_whsp(sp); 1262 kind = get_token(sp, &sval); 1263 if ( kind != TK_BAREWORD ) { 1264 LDAP_FREE(sval); 1265 *code = LDAP_SCHERR_UNEXPTOKEN; 1266 return NULL; 1267 } 1268 parse_whsp(sp); 1269 return sval; 1270 } 1271 1272 /* Parse a noidlen */ 1273 static char * 1274 parse_noidlen(const char **sp, int *code, int *len, int flags) 1275 { 1276 char * sval; 1277 const char *savepos; 1278 int quoted = 0; 1279 int allow_quoted = ( flags & LDAP_SCHEMA_ALLOW_QUOTED ); 1280 int allow_oidmacro = ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ); 1281 1282 *len = 0; 1283 /* Netscape puts the SYNTAX value in quotes (incorrectly) */ 1284 if ( allow_quoted && **sp == '\'' ) { 1285 quoted = 1; 1286 (*sp)++; 1287 } 1288 savepos = *sp; 1289 sval = ldap_int_parse_numericoid(sp, code, 0); 1290 if ( !sval ) { 1291 if ( allow_oidmacro 1292 && *sp == savepos 1293 && *code == LDAP_SCHERR_NODIGIT ) 1294 { 1295 if ( get_token(sp, &sval) != TK_BAREWORD ) { 1296 if ( sval != NULL ) { 1297 LDAP_FREE(sval); 1298 } 1299 return NULL; 1300 } 1301 } else { 1302 return NULL; 1303 } 1304 } 1305 if ( **sp == '{' /*}*/ ) { 1306 (*sp)++; 1307 *len = atoi(*sp); 1308 while ( LDAP_DIGIT(**sp) ) 1309 (*sp)++; 1310 if ( **sp != /*{*/ '}' ) { 1311 *code = LDAP_SCHERR_UNEXPTOKEN; 1312 LDAP_FREE(sval); 1313 return NULL; 1314 } 1315 (*sp)++; 1316 } 1317 if ( allow_quoted && quoted ) { 1318 if ( **sp == '\'' ) { 1319 (*sp)++; 1320 } else { 1321 *code = LDAP_SCHERR_UNEXPTOKEN; 1322 LDAP_FREE(sval); 1323 return NULL; 1324 } 1325 } 1326 return sval; 1327 } 1328 1329 /* 1330 * Next routine will accept a qdstring in place of an oid if 1331 * allow_quoted is set. This is necessary to interoperate with 1332 * Netscape Directory server that will improperly quote each oid (at 1333 * least those of the descr kind) in the SUP clause. 1334 */ 1335 1336 /* Parse a woid or a $-separated list of them enclosed in () */ 1337 static char ** 1338 parse_oids(const char **sp, int *code, const int allow_quoted) 1339 { 1340 char ** res; 1341 char ** res1; 1342 tk_t kind; 1343 char * sval; 1344 int size; 1345 int pos; 1346 1347 /* 1348 * Strictly speaking, doing this here accepts whsp before the 1349 * ( at the begining of an oidlist, but this is harmless. Also, 1350 * we are very liberal in what we accept as an OID. Maybe 1351 * refine later. 1352 */ 1353 parse_whsp(sp); 1354 kind = get_token(sp,&sval); 1355 if ( kind == TK_LEFTPAREN ) { 1356 /* Let's presume there will be at least 2 entries */ 1357 size = 3; 1358 res = LDAP_CALLOC(3,sizeof(char *)); 1359 if ( !res ) { 1360 *code = LDAP_SCHERR_OUTOFMEM; 1361 return NULL; 1362 } 1363 pos = 0; 1364 parse_whsp(sp); 1365 kind = get_token(sp,&sval); 1366 if ( kind == TK_BAREWORD || 1367 ( allow_quoted && kind == TK_QDSTRING ) ) { 1368 res[pos++] = sval; 1369 res[pos] = NULL; 1370 } else if ( kind == TK_RIGHTPAREN ) { 1371 /* FIXME: be liberal in what we accept... */ 1372 parse_whsp(sp); 1373 LDAP_FREE(res); 1374 return NULL; 1375 } else { 1376 *code = LDAP_SCHERR_UNEXPTOKEN; 1377 LDAP_FREE(sval); 1378 LDAP_VFREE(res); 1379 return NULL; 1380 } 1381 parse_whsp(sp); 1382 while (1) { 1383 kind = get_token(sp,&sval); 1384 if ( kind == TK_RIGHTPAREN ) 1385 break; 1386 if ( kind == TK_DOLLAR ) { 1387 parse_whsp(sp); 1388 kind = get_token(sp,&sval); 1389 if ( kind == TK_BAREWORD || 1390 ( allow_quoted && 1391 kind == TK_QDSTRING ) ) { 1392 if ( pos == size-2 ) { 1393 size++; 1394 res1 = LDAP_REALLOC(res,size*sizeof(char *)); 1395 if ( !res1 ) { 1396 LDAP_FREE(sval); 1397 LDAP_VFREE(res); 1398 *code = LDAP_SCHERR_OUTOFMEM; 1399 return(NULL); 1400 } 1401 res = res1; 1402 } 1403 res[pos++] = sval; 1404 res[pos] = NULL; 1405 } else { 1406 *code = LDAP_SCHERR_UNEXPTOKEN; 1407 LDAP_FREE(sval); 1408 LDAP_VFREE(res); 1409 return NULL; 1410 } 1411 parse_whsp(sp); 1412 } else { 1413 *code = LDAP_SCHERR_UNEXPTOKEN; 1414 LDAP_FREE(sval); 1415 LDAP_VFREE(res); 1416 return NULL; 1417 } 1418 } 1419 parse_whsp(sp); 1420 return(res); 1421 } else if ( kind == TK_BAREWORD || 1422 ( allow_quoted && kind == TK_QDSTRING ) ) { 1423 res = LDAP_CALLOC(2,sizeof(char *)); 1424 if ( !res ) { 1425 LDAP_FREE(sval); 1426 *code = LDAP_SCHERR_OUTOFMEM; 1427 return NULL; 1428 } 1429 res[0] = sval; 1430 res[1] = NULL; 1431 parse_whsp(sp); 1432 return res; 1433 } else { 1434 LDAP_FREE(sval); 1435 *code = LDAP_SCHERR_BADNAME; 1436 return NULL; 1437 } 1438 } 1439 1440 static int 1441 add_extension(LDAPSchemaExtensionItem ***extensions, 1442 char * name, char ** values) 1443 { 1444 int n; 1445 LDAPSchemaExtensionItem **tmp, *ext; 1446 1447 ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem)); 1448 if ( !ext ) 1449 return 1; 1450 ext->lsei_name = name; 1451 ext->lsei_values = values; 1452 1453 if ( !*extensions ) { 1454 *extensions = 1455 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *)); 1456 if ( !*extensions ) { 1457 LDAP_FREE( ext ); 1458 return 1; 1459 } 1460 n = 0; 1461 } else { 1462 for ( n=0; (*extensions)[n] != NULL; n++ ) 1463 ; 1464 tmp = LDAP_REALLOC(*extensions, 1465 (n+2)*sizeof(LDAPSchemaExtensionItem *)); 1466 if ( !tmp ) { 1467 LDAP_FREE( ext ); 1468 return 1; 1469 } 1470 *extensions = tmp; 1471 } 1472 (*extensions)[n] = ext; 1473 (*extensions)[n+1] = NULL; 1474 return 0; 1475 } 1476 1477 static void 1478 free_extensions(LDAPSchemaExtensionItem **extensions) 1479 { 1480 LDAPSchemaExtensionItem **ext; 1481 1482 if ( extensions ) { 1483 for ( ext = extensions; *ext != NULL; ext++ ) { 1484 LDAP_FREE((*ext)->lsei_name); 1485 LDAP_VFREE((*ext)->lsei_values); 1486 LDAP_FREE(*ext); 1487 } 1488 LDAP_FREE(extensions); 1489 } 1490 } 1491 1492 void 1493 ldap_syntax_free( LDAPSyntax * syn ) 1494 { 1495 if ( !syn ) return; 1496 LDAP_FREE(syn->syn_oid); 1497 if (syn->syn_names) LDAP_VFREE(syn->syn_names); 1498 if (syn->syn_desc) LDAP_FREE(syn->syn_desc); 1499 free_extensions(syn->syn_extensions); 1500 LDAP_FREE(syn); 1501 } 1502 1503 LDAPSyntax * 1504 ldap_str2syntax( LDAP_CONST char * s, 1505 int * code, 1506 LDAP_CONST char ** errp, 1507 LDAP_CONST unsigned flags ) 1508 { 1509 tk_t kind; 1510 const char * ss = s; 1511 char * sval; 1512 int seen_name = 0; 1513 int seen_desc = 0; 1514 LDAPSyntax * syn; 1515 char ** ext_vals; 1516 1517 if ( !s ) { 1518 *code = LDAP_SCHERR_EMPTY; 1519 *errp = ""; 1520 return NULL; 1521 } 1522 1523 *errp = s; 1524 syn = LDAP_CALLOC(1,sizeof(LDAPSyntax)); 1525 1526 if ( !syn ) { 1527 *code = LDAP_SCHERR_OUTOFMEM; 1528 return NULL; 1529 } 1530 1531 kind = get_token(&ss,&sval); 1532 if ( kind != TK_LEFTPAREN ) { 1533 LDAP_FREE(sval); 1534 *code = LDAP_SCHERR_NOLEFTPAREN; 1535 ldap_syntax_free(syn); 1536 return NULL; 1537 } 1538 1539 parse_whsp(&ss); 1540 syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0); 1541 if ( !syn->syn_oid ) { 1542 *errp = ss; 1543 ldap_syntax_free(syn); 1544 return NULL; 1545 } 1546 parse_whsp(&ss); 1547 1548 /* 1549 * Beyond this point we will be liberal and accept the items 1550 * in any order. 1551 */ 1552 while (1) { 1553 kind = get_token(&ss,&sval); 1554 switch (kind) { 1555 case TK_EOS: 1556 *code = LDAP_SCHERR_NORIGHTPAREN; 1557 *errp = EndOfInput; 1558 ldap_syntax_free(syn); 1559 return NULL; 1560 case TK_RIGHTPAREN: 1561 return syn; 1562 case TK_BAREWORD: 1563 if ( !strcasecmp(sval,"NAME") ) { 1564 LDAP_FREE(sval); 1565 if ( seen_name ) { 1566 *code = LDAP_SCHERR_DUPOPT; 1567 *errp = ss; 1568 ldap_syntax_free(syn); 1569 return(NULL); 1570 } 1571 seen_name = 1; 1572 syn->syn_names = parse_qdescrs(&ss,code); 1573 if ( !syn->syn_names ) { 1574 if ( *code != LDAP_SCHERR_OUTOFMEM ) 1575 *code = LDAP_SCHERR_BADNAME; 1576 *errp = ss; 1577 ldap_syntax_free(syn); 1578 return NULL; 1579 } 1580 } else if ( !strcasecmp(sval,"DESC") ) { 1581 LDAP_FREE(sval); 1582 if ( seen_desc ) { 1583 *code = LDAP_SCHERR_DUPOPT; 1584 *errp = ss; 1585 ldap_syntax_free(syn); 1586 return(NULL); 1587 } 1588 seen_desc = 1; 1589 parse_whsp(&ss); 1590 kind = get_token(&ss,&sval); 1591 if ( kind != TK_QDSTRING ) { 1592 *code = LDAP_SCHERR_UNEXPTOKEN; 1593 *errp = ss; 1594 LDAP_FREE(sval); 1595 ldap_syntax_free(syn); 1596 return NULL; 1597 } 1598 syn->syn_desc = sval; 1599 parse_whsp(&ss); 1600 } else if ( sval[0] == 'X' && sval[1] == '-' ) { 1601 /* Should be parse_qdstrings */ 1602 ext_vals = parse_qdescrs(&ss, code); 1603 if ( !ext_vals ) { 1604 *errp = ss; 1605 ldap_syntax_free(syn); 1606 return NULL; 1607 } 1608 if ( add_extension(&syn->syn_extensions, 1609 sval, ext_vals) ) { 1610 *code = LDAP_SCHERR_OUTOFMEM; 1611 *errp = ss; 1612 LDAP_FREE(sval); 1613 ldap_syntax_free(syn); 1614 return NULL; 1615 } 1616 } else { 1617 *code = LDAP_SCHERR_UNEXPTOKEN; 1618 *errp = ss; 1619 LDAP_FREE(sval); 1620 ldap_syntax_free(syn); 1621 return NULL; 1622 } 1623 break; 1624 default: 1625 *code = LDAP_SCHERR_UNEXPTOKEN; 1626 *errp = ss; 1627 LDAP_FREE(sval); 1628 ldap_syntax_free(syn); 1629 return NULL; 1630 } 1631 } 1632 } 1633 1634 void 1635 ldap_matchingrule_free( LDAPMatchingRule * mr ) 1636 { 1637 if (!mr) return; 1638 LDAP_FREE(mr->mr_oid); 1639 if (mr->mr_names) LDAP_VFREE(mr->mr_names); 1640 if (mr->mr_desc) LDAP_FREE(mr->mr_desc); 1641 if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid); 1642 free_extensions(mr->mr_extensions); 1643 LDAP_FREE(mr); 1644 } 1645 1646 LDAPMatchingRule * 1647 ldap_str2matchingrule( LDAP_CONST char * s, 1648 int * code, 1649 LDAP_CONST char ** errp, 1650 LDAP_CONST unsigned flags ) 1651 { 1652 tk_t kind; 1653 const char * ss = s; 1654 char * sval; 1655 int seen_name = 0; 1656 int seen_desc = 0; 1657 int seen_obsolete = 0; 1658 int seen_syntax = 0; 1659 LDAPMatchingRule * mr; 1660 char ** ext_vals; 1661 const char * savepos; 1662 1663 if ( !s ) { 1664 *code = LDAP_SCHERR_EMPTY; 1665 *errp = ""; 1666 return NULL; 1667 } 1668 1669 *errp = s; 1670 mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule)); 1671 1672 if ( !mr ) { 1673 *code = LDAP_SCHERR_OUTOFMEM; 1674 return NULL; 1675 } 1676 1677 kind = get_token(&ss,&sval); 1678 if ( kind != TK_LEFTPAREN ) { 1679 *code = LDAP_SCHERR_NOLEFTPAREN; 1680 LDAP_FREE(sval); 1681 ldap_matchingrule_free(mr); 1682 return NULL; 1683 } 1684 1685 parse_whsp(&ss); 1686 savepos = ss; 1687 mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags); 1688 if ( !mr->mr_oid ) { 1689 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) { 1690 /* Backtracking */ 1691 ss = savepos; 1692 kind = get_token(&ss,&sval); 1693 if ( kind == TK_BAREWORD ) { 1694 if ( !strcasecmp(sval, "NAME") || 1695 !strcasecmp(sval, "DESC") || 1696 !strcasecmp(sval, "OBSOLETE") || 1697 !strcasecmp(sval, "SYNTAX") || 1698 !strncasecmp(sval, "X-", 2) ) { 1699 /* Missing OID, backtrack */ 1700 ss = savepos; 1701 } else { 1702 /* Non-numerical OID, ignore */ 1703 } 1704 } 1705 LDAP_FREE(sval); 1706 } else { 1707 *errp = ss; 1708 ldap_matchingrule_free(mr); 1709 return NULL; 1710 } 1711 } 1712 parse_whsp(&ss); 1713 1714 /* 1715 * Beyond this point we will be liberal and accept the items 1716 * in any order. 1717 */ 1718 while (1) { 1719 kind = get_token(&ss,&sval); 1720 switch (kind) { 1721 case TK_EOS: 1722 *code = LDAP_SCHERR_NORIGHTPAREN; 1723 *errp = EndOfInput; 1724 ldap_matchingrule_free(mr); 1725 return NULL; 1726 case TK_RIGHTPAREN: 1727 if( !seen_syntax ) { 1728 *code = LDAP_SCHERR_MISSING; 1729 ldap_matchingrule_free(mr); 1730 return NULL; 1731 } 1732 return mr; 1733 case TK_BAREWORD: 1734 if ( !strcasecmp(sval,"NAME") ) { 1735 LDAP_FREE(sval); 1736 if ( seen_name ) { 1737 *code = LDAP_SCHERR_DUPOPT; 1738 *errp = ss; 1739 ldap_matchingrule_free(mr); 1740 return(NULL); 1741 } 1742 seen_name = 1; 1743 mr->mr_names = parse_qdescrs(&ss,code); 1744 if ( !mr->mr_names ) { 1745 if ( *code != LDAP_SCHERR_OUTOFMEM ) 1746 *code = LDAP_SCHERR_BADNAME; 1747 *errp = ss; 1748 ldap_matchingrule_free(mr); 1749 return NULL; 1750 } 1751 } else if ( !strcasecmp(sval,"DESC") ) { 1752 LDAP_FREE(sval); 1753 if ( seen_desc ) { 1754 *code = LDAP_SCHERR_DUPOPT; 1755 *errp = ss; 1756 ldap_matchingrule_free(mr); 1757 return(NULL); 1758 } 1759 seen_desc = 1; 1760 parse_whsp(&ss); 1761 kind = get_token(&ss,&sval); 1762 if ( kind != TK_QDSTRING ) { 1763 *code = LDAP_SCHERR_UNEXPTOKEN; 1764 *errp = ss; 1765 LDAP_FREE(sval); 1766 ldap_matchingrule_free(mr); 1767 return NULL; 1768 } 1769 mr->mr_desc = sval; 1770 parse_whsp(&ss); 1771 } else if ( !strcasecmp(sval,"OBSOLETE") ) { 1772 LDAP_FREE(sval); 1773 if ( seen_obsolete ) { 1774 *code = LDAP_SCHERR_DUPOPT; 1775 *errp = ss; 1776 ldap_matchingrule_free(mr); 1777 return(NULL); 1778 } 1779 seen_obsolete = 1; 1780 mr->mr_obsolete = LDAP_SCHEMA_YES; 1781 parse_whsp(&ss); 1782 } else if ( !strcasecmp(sval,"SYNTAX") ) { 1783 LDAP_FREE(sval); 1784 if ( seen_syntax ) { 1785 *code = LDAP_SCHERR_DUPOPT; 1786 *errp = ss; 1787 ldap_matchingrule_free(mr); 1788 return(NULL); 1789 } 1790 seen_syntax = 1; 1791 parse_whsp(&ss); 1792 mr->mr_syntax_oid = 1793 ldap_int_parse_numericoid(&ss,code,flags); 1794 if ( !mr->mr_syntax_oid ) { 1795 *errp = ss; 1796 ldap_matchingrule_free(mr); 1797 return NULL; 1798 } 1799 parse_whsp(&ss); 1800 } else if ( sval[0] == 'X' && sval[1] == '-' ) { 1801 /* Should be parse_qdstrings */ 1802 ext_vals = parse_qdescrs(&ss, code); 1803 if ( !ext_vals ) { 1804 *errp = ss; 1805 ldap_matchingrule_free(mr); 1806 return NULL; 1807 } 1808 if ( add_extension(&mr->mr_extensions, 1809 sval, ext_vals) ) { 1810 *code = LDAP_SCHERR_OUTOFMEM; 1811 *errp = ss; 1812 LDAP_FREE(sval); 1813 ldap_matchingrule_free(mr); 1814 return NULL; 1815 } 1816 } else { 1817 *code = LDAP_SCHERR_UNEXPTOKEN; 1818 *errp = ss; 1819 LDAP_FREE(sval); 1820 ldap_matchingrule_free(mr); 1821 return NULL; 1822 } 1823 break; 1824 default: 1825 *code = LDAP_SCHERR_UNEXPTOKEN; 1826 *errp = ss; 1827 LDAP_FREE(sval); 1828 ldap_matchingrule_free(mr); 1829 return NULL; 1830 } 1831 } 1832 } 1833 1834 void 1835 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru ) 1836 { 1837 if (!mru) return; 1838 LDAP_FREE(mru->mru_oid); 1839 if (mru->mru_names) LDAP_VFREE(mru->mru_names); 1840 if (mru->mru_desc) LDAP_FREE(mru->mru_desc); 1841 if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids); 1842 free_extensions(mru->mru_extensions); 1843 LDAP_FREE(mru); 1844 } 1845 1846 LDAPMatchingRuleUse * 1847 ldap_str2matchingruleuse( LDAP_CONST char * s, 1848 int * code, 1849 LDAP_CONST char ** errp, 1850 LDAP_CONST unsigned flags ) 1851 { 1852 tk_t kind; 1853 const char * ss = s; 1854 char * sval; 1855 int seen_name = 0; 1856 int seen_desc = 0; 1857 int seen_obsolete = 0; 1858 int seen_applies = 0; 1859 LDAPMatchingRuleUse * mru; 1860 char ** ext_vals; 1861 const char * savepos; 1862 1863 if ( !s ) { 1864 *code = LDAP_SCHERR_EMPTY; 1865 *errp = ""; 1866 return NULL; 1867 } 1868 1869 *errp = s; 1870 mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse)); 1871 1872 if ( !mru ) { 1873 *code = LDAP_SCHERR_OUTOFMEM; 1874 return NULL; 1875 } 1876 1877 kind = get_token(&ss,&sval); 1878 if ( kind != TK_LEFTPAREN ) { 1879 *code = LDAP_SCHERR_NOLEFTPAREN; 1880 LDAP_FREE(sval); 1881 ldap_matchingruleuse_free(mru); 1882 return NULL; 1883 } 1884 1885 parse_whsp(&ss); 1886 savepos = ss; 1887 mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags); 1888 if ( !mru->mru_oid ) { 1889 if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) { 1890 /* Backtracking */ 1891 ss = savepos; 1892 kind = get_token(&ss,&sval); 1893 if ( kind == TK_BAREWORD ) { 1894 if ( !strcasecmp(sval, "NAME") || 1895 !strcasecmp(sval, "DESC") || 1896 !strcasecmp(sval, "OBSOLETE") || 1897 !strcasecmp(sval, "APPLIES") || 1898 !strncasecmp(sval, "X-", 2) ) { 1899 /* Missing OID, backtrack */ 1900 ss = savepos; 1901 } else { 1902 /* Non-numerical OID, ignore */ 1903 } 1904 } 1905 LDAP_FREE(sval); 1906 } else { 1907 *errp = ss; 1908 ldap_matchingruleuse_free(mru); 1909 return NULL; 1910 } 1911 } 1912 parse_whsp(&ss); 1913 1914 /* 1915 * Beyond this point we will be liberal and accept the items 1916 * in any order. 1917 */ 1918 while (1) { 1919 kind = get_token(&ss,&sval); 1920 switch (kind) { 1921 case TK_EOS: 1922 *code = LDAP_SCHERR_NORIGHTPAREN; 1923 *errp = EndOfInput; 1924 ldap_matchingruleuse_free(mru); 1925 return NULL; 1926 case TK_RIGHTPAREN: 1927 if( !seen_applies ) { 1928 *code = LDAP_SCHERR_MISSING; 1929 ldap_matchingruleuse_free(mru); 1930 return NULL; 1931 } 1932 return mru; 1933 case TK_BAREWORD: 1934 if ( !strcasecmp(sval,"NAME") ) { 1935 LDAP_FREE(sval); 1936 if ( seen_name ) { 1937 *code = LDAP_SCHERR_DUPOPT; 1938 *errp = ss; 1939 ldap_matchingruleuse_free(mru); 1940 return(NULL); 1941 } 1942 seen_name = 1; 1943 mru->mru_names = parse_qdescrs(&ss,code); 1944 if ( !mru->mru_names ) { 1945 if ( *code != LDAP_SCHERR_OUTOFMEM ) 1946 *code = LDAP_SCHERR_BADNAME; 1947 *errp = ss; 1948 ldap_matchingruleuse_free(mru); 1949 return NULL; 1950 } 1951 } else if ( !strcasecmp(sval,"DESC") ) { 1952 LDAP_FREE(sval); 1953 if ( seen_desc ) { 1954 *code = LDAP_SCHERR_DUPOPT; 1955 *errp = ss; 1956 ldap_matchingruleuse_free(mru); 1957 return(NULL); 1958 } 1959 seen_desc = 1; 1960 parse_whsp(&ss); 1961 kind = get_token(&ss,&sval); 1962 if ( kind != TK_QDSTRING ) { 1963 *code = LDAP_SCHERR_UNEXPTOKEN; 1964 *errp = ss; 1965 LDAP_FREE(sval); 1966 ldap_matchingruleuse_free(mru); 1967 return NULL; 1968 } 1969 mru->mru_desc = sval; 1970 parse_whsp(&ss); 1971 } else if ( !strcasecmp(sval,"OBSOLETE") ) { 1972 LDAP_FREE(sval); 1973 if ( seen_obsolete ) { 1974 *code = LDAP_SCHERR_DUPOPT; 1975 *errp = ss; 1976 ldap_matchingruleuse_free(mru); 1977 return(NULL); 1978 } 1979 seen_obsolete = 1; 1980 mru->mru_obsolete = LDAP_SCHEMA_YES; 1981 parse_whsp(&ss); 1982 } else if ( !strcasecmp(sval,"APPLIES") ) { 1983 LDAP_FREE(sval); 1984 if ( seen_applies ) { 1985 *code = LDAP_SCHERR_DUPOPT; 1986 *errp = ss; 1987 ldap_matchingruleuse_free(mru); 1988 return(NULL); 1989 } 1990 seen_applies = 1; 1991 mru->mru_applies_oids = parse_oids(&ss, 1992 code, 1993 flags); 1994 if ( !mru->mru_applies_oids && *code != LDAP_SUCCESS ) { 1995 *errp = ss; 1996 ldap_matchingruleuse_free(mru); 1997 return NULL; 1998 } 1999 } else if ( sval[0] == 'X' && sval[1] == '-' ) { 2000 /* Should be parse_qdstrings */ 2001 ext_vals = parse_qdescrs(&ss, code); 2002 if ( !ext_vals ) { 2003 *errp = ss; 2004 ldap_matchingruleuse_free(mru); 2005 return NULL; 2006 } 2007 if ( add_extension(&mru->mru_extensions, 2008 sval, ext_vals) ) { 2009 *code = LDAP_SCHERR_OUTOFMEM; 2010 *errp = ss; 2011 LDAP_FREE(sval); 2012 ldap_matchingruleuse_free(mru); 2013 return NULL; 2014 } 2015 } else { 2016 *code = LDAP_SCHERR_UNEXPTOKEN; 2017 *errp = ss; 2018 LDAP_FREE(sval); 2019 ldap_matchingruleuse_free(mru); 2020 return NULL; 2021 } 2022 break; 2023 default: 2024 *code = LDAP_SCHERR_UNEXPTOKEN; 2025 *errp = ss; 2026 LDAP_FREE(sval); 2027 ldap_matchingruleuse_free(mru); 2028 return NULL; 2029 } 2030 } 2031 } 2032 2033 void 2034 ldap_attributetype_free(LDAPAttributeType * at) 2035 { 2036 if (!at) return; 2037 LDAP_FREE(at->at_oid); 2038 if (at->at_names) LDAP_VFREE(at->at_names); 2039 if (at->at_desc) LDAP_FREE(at->at_desc); 2040 if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid); 2041 if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid); 2042 if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid); 2043 if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid); 2044 if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid); 2045 free_extensions(at->at_extensions); 2046 LDAP_FREE(at); 2047 } 2048 2049 LDAPAttributeType * 2050 ldap_str2attributetype( LDAP_CONST char * s, 2051 int * code, 2052 LDAP_CONST char ** errp, 2053 LDAP_CONST unsigned flags ) 2054 { 2055 tk_t kind; 2056 const char * ss = s; 2057 char * sval; 2058 int seen_name = 0; 2059 int seen_desc = 0; 2060 int seen_obsolete = 0; 2061 int seen_sup = 0; 2062 int seen_equality = 0; 2063 int seen_ordering = 0; 2064 int seen_substr = 0; 2065 int seen_syntax = 0; 2066 int seen_usage = 0; 2067 LDAPAttributeType * at; 2068 char ** ext_vals; 2069 const char * savepos; 2070 2071 if ( !s ) { 2072 *code = LDAP_SCHERR_EMPTY; 2073 *errp = ""; 2074 return NULL; 2075 } 2076 2077 *errp = s; 2078 at = LDAP_CALLOC(1,sizeof(LDAPAttributeType)); 2079 2080 if ( !at ) { 2081 *code = LDAP_SCHERR_OUTOFMEM; 2082 return NULL; 2083 } 2084 2085 kind = get_token(&ss,&sval); 2086 if ( kind != TK_LEFTPAREN ) { 2087 *code = LDAP_SCHERR_NOLEFTPAREN; 2088 LDAP_FREE(sval); 2089 ldap_attributetype_free(at); 2090 return NULL; 2091 } 2092 2093 /* 2094 * Definitions MUST begin with an OID in the numericoid format. 2095 * However, this routine is used by clients to parse the response 2096 * from servers and very well known servers will provide an OID 2097 * in the wrong format or even no OID at all. We do our best to 2098 * extract info from those servers. 2099 */ 2100 parse_whsp(&ss); 2101 savepos = ss; 2102 at->at_oid = ldap_int_parse_numericoid(&ss,code,0); 2103 if ( !at->at_oid ) { 2104 if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID 2105 | LDAP_SCHEMA_ALLOW_OID_MACRO ) ) 2106 && (ss == savepos) ) 2107 { 2108 /* Backtracking */ 2109 ss = savepos; 2110 kind = get_token(&ss,&sval); 2111 if ( kind == TK_BAREWORD ) { 2112 if ( !strcasecmp(sval, "NAME") || 2113 !strcasecmp(sval, "DESC") || 2114 !strcasecmp(sval, "OBSOLETE") || 2115 !strcasecmp(sval, "SUP") || 2116 !strcasecmp(sval, "EQUALITY") || 2117 !strcasecmp(sval, "ORDERING") || 2118 !strcasecmp(sval, "SUBSTR") || 2119 !strcasecmp(sval, "SYNTAX") || 2120 !strcasecmp(sval, "SINGLE-VALUE") || 2121 !strcasecmp(sval, "COLLECTIVE") || 2122 !strcasecmp(sval, "NO-USER-MODIFICATION") || 2123 !strcasecmp(sval, "USAGE") || 2124 !strncasecmp(sval, "X-", 2) ) 2125 { 2126 /* Missing OID, backtrack */ 2127 ss = savepos; 2128 } else if ( flags 2129 & LDAP_SCHEMA_ALLOW_OID_MACRO) 2130 { 2131 /* Non-numerical OID ... */ 2132 int len = ss-savepos; 2133 at->at_oid = LDAP_MALLOC(len+1); 2134 strncpy(at->at_oid, savepos, len); 2135 at->at_oid[len] = 0; 2136 } 2137 } 2138 LDAP_FREE(sval); 2139 } else { 2140 *errp = ss; 2141 ldap_attributetype_free(at); 2142 return NULL; 2143 } 2144 } 2145 parse_whsp(&ss); 2146 2147 /* 2148 * Beyond this point we will be liberal and accept the items 2149 * in any order. 2150 */ 2151 while (1) { 2152 kind = get_token(&ss,&sval); 2153 switch (kind) { 2154 case TK_EOS: 2155 *code = LDAP_SCHERR_NORIGHTPAREN; 2156 *errp = EndOfInput; 2157 ldap_attributetype_free(at); 2158 return NULL; 2159 case TK_RIGHTPAREN: 2160 return at; 2161 case TK_BAREWORD: 2162 if ( !strcasecmp(sval,"NAME") ) { 2163 LDAP_FREE(sval); 2164 if ( seen_name ) { 2165 *code = LDAP_SCHERR_DUPOPT; 2166 *errp = ss; 2167 ldap_attributetype_free(at); 2168 return(NULL); 2169 } 2170 seen_name = 1; 2171 at->at_names = parse_qdescrs(&ss,code); 2172 if ( !at->at_names ) { 2173 if ( *code != LDAP_SCHERR_OUTOFMEM ) 2174 *code = LDAP_SCHERR_BADNAME; 2175 *errp = ss; 2176 ldap_attributetype_free(at); 2177 return NULL; 2178 } 2179 } else if ( !strcasecmp(sval,"DESC") ) { 2180 LDAP_FREE(sval); 2181 if ( seen_desc ) { 2182 *code = LDAP_SCHERR_DUPOPT; 2183 *errp = ss; 2184 ldap_attributetype_free(at); 2185 return(NULL); 2186 } 2187 seen_desc = 1; 2188 parse_whsp(&ss); 2189 kind = get_token(&ss,&sval); 2190 if ( kind != TK_QDSTRING ) { 2191 *code = LDAP_SCHERR_UNEXPTOKEN; 2192 *errp = ss; 2193 LDAP_FREE(sval); 2194 ldap_attributetype_free(at); 2195 return NULL; 2196 } 2197 at->at_desc = sval; 2198 parse_whsp(&ss); 2199 } else if ( !strcasecmp(sval,"OBSOLETE") ) { 2200 LDAP_FREE(sval); 2201 if ( seen_obsolete ) { 2202 *code = LDAP_SCHERR_DUPOPT; 2203 *errp = ss; 2204 ldap_attributetype_free(at); 2205 return(NULL); 2206 } 2207 seen_obsolete = 1; 2208 at->at_obsolete = LDAP_SCHEMA_YES; 2209 parse_whsp(&ss); 2210 } else if ( !strcasecmp(sval,"SUP") ) { 2211 LDAP_FREE(sval); 2212 if ( seen_sup ) { 2213 *code = LDAP_SCHERR_DUPOPT; 2214 *errp = ss; 2215 ldap_attributetype_free(at); 2216 return(NULL); 2217 } 2218 seen_sup = 1; 2219 at->at_sup_oid = parse_woid(&ss,code); 2220 if ( !at->at_sup_oid ) { 2221 *errp = ss; 2222 ldap_attributetype_free(at); 2223 return NULL; 2224 } 2225 } else if ( !strcasecmp(sval,"EQUALITY") ) { 2226 LDAP_FREE(sval); 2227 if ( seen_equality ) { 2228 *code = LDAP_SCHERR_DUPOPT; 2229 *errp = ss; 2230 ldap_attributetype_free(at); 2231 return(NULL); 2232 } 2233 seen_equality = 1; 2234 at->at_equality_oid = parse_woid(&ss,code); 2235 if ( !at->at_equality_oid ) { 2236 *errp = ss; 2237 ldap_attributetype_free(at); 2238 return NULL; 2239 } 2240 } else if ( !strcasecmp(sval,"ORDERING") ) { 2241 LDAP_FREE(sval); 2242 if ( seen_ordering ) { 2243 *code = LDAP_SCHERR_DUPOPT; 2244 *errp = ss; 2245 ldap_attributetype_free(at); 2246 return(NULL); 2247 } 2248 seen_ordering = 1; 2249 at->at_ordering_oid = parse_woid(&ss,code); 2250 if ( !at->at_ordering_oid ) { 2251 *errp = ss; 2252 ldap_attributetype_free(at); 2253 return NULL; 2254 } 2255 } else if ( !strcasecmp(sval,"SUBSTR") ) { 2256 LDAP_FREE(sval); 2257 if ( seen_substr ) { 2258 *code = LDAP_SCHERR_DUPOPT; 2259 *errp = ss; 2260 ldap_attributetype_free(at); 2261 return(NULL); 2262 } 2263 seen_substr = 1; 2264 at->at_substr_oid = parse_woid(&ss,code); 2265 if ( !at->at_substr_oid ) { 2266 *errp = ss; 2267 ldap_attributetype_free(at); 2268 return NULL; 2269 } 2270 } else if ( !strcasecmp(sval,"SYNTAX") ) { 2271 LDAP_FREE(sval); 2272 if ( seen_syntax ) { 2273 *code = LDAP_SCHERR_DUPOPT; 2274 *errp = ss; 2275 ldap_attributetype_free(at); 2276 return(NULL); 2277 } 2278 seen_syntax = 1; 2279 parse_whsp(&ss); 2280 savepos = ss; 2281 at->at_syntax_oid = 2282 parse_noidlen(&ss, 2283 code, 2284 &at->at_syntax_len, 2285 flags); 2286 if ( !at->at_syntax_oid ) { 2287 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) { 2288 kind = get_token(&ss,&sval); 2289 if (kind == TK_BAREWORD) 2290 { 2291 char *sp = strchr(sval, '{'); 2292 at->at_syntax_oid = sval; 2293 if (sp) 2294 { 2295 *sp++ = 0; 2296 at->at_syntax_len = atoi(sp); 2297 while ( LDAP_DIGIT(*sp) ) 2298 sp++; 2299 if ( *sp != '}' ) { 2300 *code = LDAP_SCHERR_UNEXPTOKEN; 2301 *errp = ss; 2302 ldap_attributetype_free(at); 2303 return NULL; 2304 } 2305 } 2306 } 2307 } else { 2308 *errp = ss; 2309 ldap_attributetype_free(at); 2310 return NULL; 2311 } 2312 } 2313 parse_whsp(&ss); 2314 } else if ( !strcasecmp(sval,"SINGLE-VALUE") ) { 2315 LDAP_FREE(sval); 2316 if ( at->at_single_value ) { 2317 *code = LDAP_SCHERR_DUPOPT; 2318 *errp = ss; 2319 ldap_attributetype_free(at); 2320 return(NULL); 2321 } 2322 at->at_single_value = LDAP_SCHEMA_YES; 2323 parse_whsp(&ss); 2324 } else if ( !strcasecmp(sval,"COLLECTIVE") ) { 2325 LDAP_FREE(sval); 2326 if ( at->at_collective ) { 2327 *code = LDAP_SCHERR_DUPOPT; 2328 *errp = ss; 2329 ldap_attributetype_free(at); 2330 return(NULL); 2331 } 2332 at->at_collective = LDAP_SCHEMA_YES; 2333 parse_whsp(&ss); 2334 } else if ( !strcasecmp(sval,"NO-USER-MODIFICATION") ) { 2335 LDAP_FREE(sval); 2336 if ( at->at_no_user_mod ) { 2337 *code = LDAP_SCHERR_DUPOPT; 2338 *errp = ss; 2339 ldap_attributetype_free(at); 2340 return(NULL); 2341 } 2342 at->at_no_user_mod = LDAP_SCHEMA_YES; 2343 parse_whsp(&ss); 2344 } else if ( !strcasecmp(sval,"USAGE") ) { 2345 LDAP_FREE(sval); 2346 if ( seen_usage ) { 2347 *code = LDAP_SCHERR_DUPOPT; 2348 *errp = ss; 2349 ldap_attributetype_free(at); 2350 return(NULL); 2351 } 2352 seen_usage = 1; 2353 parse_whsp(&ss); 2354 kind = get_token(&ss,&sval); 2355 if ( kind != TK_BAREWORD ) { 2356 *code = LDAP_SCHERR_UNEXPTOKEN; 2357 *errp = ss; 2358 LDAP_FREE(sval); 2359 ldap_attributetype_free(at); 2360 return NULL; 2361 } 2362 if ( !strcasecmp(sval,"userApplications") ) 2363 at->at_usage = 2364 LDAP_SCHEMA_USER_APPLICATIONS; 2365 else if ( !strcasecmp(sval,"directoryOperation") ) 2366 at->at_usage = 2367 LDAP_SCHEMA_DIRECTORY_OPERATION; 2368 else if ( !strcasecmp(sval,"distributedOperation") ) 2369 at->at_usage = 2370 LDAP_SCHEMA_DISTRIBUTED_OPERATION; 2371 else if ( !strcasecmp(sval,"dSAOperation") ) 2372 at->at_usage = 2373 LDAP_SCHEMA_DSA_OPERATION; 2374 else { 2375 *code = LDAP_SCHERR_UNEXPTOKEN; 2376 *errp = ss; 2377 LDAP_FREE(sval); 2378 ldap_attributetype_free(at); 2379 return NULL; 2380 } 2381 LDAP_FREE(sval); 2382 parse_whsp(&ss); 2383 } else if ( sval[0] == 'X' && sval[1] == '-' ) { 2384 /* Should be parse_qdstrings */ 2385 ext_vals = parse_qdescrs(&ss, code); 2386 if ( !ext_vals ) { 2387 *errp = ss; 2388 ldap_attributetype_free(at); 2389 return NULL; 2390 } 2391 if ( add_extension(&at->at_extensions, 2392 sval, ext_vals) ) { 2393 *code = LDAP_SCHERR_OUTOFMEM; 2394 *errp = ss; 2395 LDAP_FREE(sval); 2396 ldap_attributetype_free(at); 2397 return NULL; 2398 } 2399 } else { 2400 *code = LDAP_SCHERR_UNEXPTOKEN; 2401 *errp = ss; 2402 LDAP_FREE(sval); 2403 ldap_attributetype_free(at); 2404 return NULL; 2405 } 2406 break; 2407 default: 2408 *code = LDAP_SCHERR_UNEXPTOKEN; 2409 *errp = ss; 2410 LDAP_FREE(sval); 2411 ldap_attributetype_free(at); 2412 return NULL; 2413 } 2414 } 2415 } 2416 2417 void 2418 ldap_objectclass_free(LDAPObjectClass * oc) 2419 { 2420 if (!oc) return; 2421 LDAP_FREE(oc->oc_oid); 2422 if (oc->oc_names) LDAP_VFREE(oc->oc_names); 2423 if (oc->oc_desc) LDAP_FREE(oc->oc_desc); 2424 if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids); 2425 if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must); 2426 if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may); 2427 free_extensions(oc->oc_extensions); 2428 LDAP_FREE(oc); 2429 } 2430 2431 LDAPObjectClass * 2432 ldap_str2objectclass( LDAP_CONST char * s, 2433 int * code, 2434 LDAP_CONST char ** errp, 2435 LDAP_CONST unsigned flags ) 2436 { 2437 tk_t kind; 2438 const char * ss = s; 2439 char * sval; 2440 int seen_name = 0; 2441 int seen_desc = 0; 2442 int seen_obsolete = 0; 2443 int seen_sup = 0; 2444 int seen_kind = 0; 2445 int seen_must = 0; 2446 int seen_may = 0; 2447 LDAPObjectClass * oc; 2448 char ** ext_vals; 2449 const char * savepos; 2450 2451 if ( !s ) { 2452 *code = LDAP_SCHERR_EMPTY; 2453 *errp = ""; 2454 return NULL; 2455 } 2456 2457 *errp = s; 2458 oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass)); 2459 2460 if ( !oc ) { 2461 *code = LDAP_SCHERR_OUTOFMEM; 2462 return NULL; 2463 } 2464 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL; 2465 2466 kind = get_token(&ss,&sval); 2467 if ( kind != TK_LEFTPAREN ) { 2468 *code = LDAP_SCHERR_NOLEFTPAREN; 2469 LDAP_FREE(sval); 2470 ldap_objectclass_free(oc); 2471 return NULL; 2472 } 2473 2474 /* 2475 * Definitions MUST begin with an OID in the numericoid format. 2476 * However, this routine is used by clients to parse the response 2477 * from servers and very well known servers will provide an OID 2478 * in the wrong format or even no OID at all. We do our best to 2479 * extract info from those servers. 2480 */ 2481 parse_whsp(&ss); 2482 savepos = ss; 2483 oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0); 2484 if ( !oc->oc_oid ) { 2485 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) { 2486 /* Backtracking */ 2487 ss = savepos; 2488 kind = get_token(&ss,&sval); 2489 if ( kind == TK_BAREWORD ) { 2490 if ( !strcasecmp(sval, "NAME") || 2491 !strcasecmp(sval, "DESC") || 2492 !strcasecmp(sval, "OBSOLETE") || 2493 !strcasecmp(sval, "SUP") || 2494 !strcasecmp(sval, "ABSTRACT") || 2495 !strcasecmp(sval, "STRUCTURAL") || 2496 !strcasecmp(sval, "AUXILIARY") || 2497 !strcasecmp(sval, "MUST") || 2498 !strcasecmp(sval, "MAY") || 2499 !strncasecmp(sval, "X-", 2) ) { 2500 /* Missing OID, backtrack */ 2501 ss = savepos; 2502 } else if ( flags & 2503 LDAP_SCHEMA_ALLOW_OID_MACRO ) { 2504 /* Non-numerical OID, ignore */ 2505 int len = ss-savepos; 2506 oc->oc_oid = LDAP_MALLOC(len+1); 2507 strncpy(oc->oc_oid, savepos, len); 2508 oc->oc_oid[len] = 0; 2509 } 2510 } 2511 LDAP_FREE(sval); 2512 *code = 0; 2513 } else { 2514 *errp = ss; 2515 ldap_objectclass_free(oc); 2516 return NULL; 2517 } 2518 } 2519 parse_whsp(&ss); 2520 2521 /* 2522 * Beyond this point we will be liberal an accept the items 2523 * in any order. 2524 */ 2525 while (1) { 2526 kind = get_token(&ss,&sval); 2527 switch (kind) { 2528 case TK_EOS: 2529 *code = LDAP_SCHERR_NORIGHTPAREN; 2530 *errp = EndOfInput; 2531 ldap_objectclass_free(oc); 2532 return NULL; 2533 case TK_RIGHTPAREN: 2534 return oc; 2535 case TK_BAREWORD: 2536 if ( !strcasecmp(sval,"NAME") ) { 2537 LDAP_FREE(sval); 2538 if ( seen_name ) { 2539 *code = LDAP_SCHERR_DUPOPT; 2540 *errp = ss; 2541 ldap_objectclass_free(oc); 2542 return(NULL); 2543 } 2544 seen_name = 1; 2545 oc->oc_names = parse_qdescrs(&ss,code); 2546 if ( !oc->oc_names ) { 2547 if ( *code != LDAP_SCHERR_OUTOFMEM ) 2548 *code = LDAP_SCHERR_BADNAME; 2549 *errp = ss; 2550 ldap_objectclass_free(oc); 2551 return NULL; 2552 } 2553 } else if ( !strcasecmp(sval,"DESC") ) { 2554 LDAP_FREE(sval); 2555 if ( seen_desc ) { 2556 *code = LDAP_SCHERR_DUPOPT; 2557 *errp = ss; 2558 ldap_objectclass_free(oc); 2559 return(NULL); 2560 } 2561 seen_desc = 1; 2562 parse_whsp(&ss); 2563 kind = get_token(&ss,&sval); 2564 if ( kind != TK_QDSTRING ) { 2565 *code = LDAP_SCHERR_UNEXPTOKEN; 2566 *errp = ss; 2567 LDAP_FREE(sval); 2568 ldap_objectclass_free(oc); 2569 return NULL; 2570 } 2571 oc->oc_desc = sval; 2572 parse_whsp(&ss); 2573 } else if ( !strcasecmp(sval,"OBSOLETE") ) { 2574 LDAP_FREE(sval); 2575 if ( seen_obsolete ) { 2576 *code = LDAP_SCHERR_DUPOPT; 2577 *errp = ss; 2578 ldap_objectclass_free(oc); 2579 return(NULL); 2580 } 2581 seen_obsolete = 1; 2582 oc->oc_obsolete = LDAP_SCHEMA_YES; 2583 parse_whsp(&ss); 2584 } else if ( !strcasecmp(sval,"SUP") ) { 2585 LDAP_FREE(sval); 2586 if ( seen_sup ) { 2587 *code = LDAP_SCHERR_DUPOPT; 2588 *errp = ss; 2589 ldap_objectclass_free(oc); 2590 return(NULL); 2591 } 2592 seen_sup = 1; 2593 oc->oc_sup_oids = parse_oids(&ss, 2594 code, 2595 flags); 2596 if ( !oc->oc_sup_oids && *code != LDAP_SUCCESS ) { 2597 *errp = ss; 2598 ldap_objectclass_free(oc); 2599 return NULL; 2600 } 2601 *code = 0; 2602 } else if ( !strcasecmp(sval,"ABSTRACT") ) { 2603 LDAP_FREE(sval); 2604 if ( seen_kind ) { 2605 *code = LDAP_SCHERR_DUPOPT; 2606 *errp = ss; 2607 ldap_objectclass_free(oc); 2608 return(NULL); 2609 } 2610 seen_kind = 1; 2611 oc->oc_kind = LDAP_SCHEMA_ABSTRACT; 2612 parse_whsp(&ss); 2613 } else if ( !strcasecmp(sval,"STRUCTURAL") ) { 2614 LDAP_FREE(sval); 2615 if ( seen_kind ) { 2616 *code = LDAP_SCHERR_DUPOPT; 2617 *errp = ss; 2618 ldap_objectclass_free(oc); 2619 return(NULL); 2620 } 2621 seen_kind = 1; 2622 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL; 2623 parse_whsp(&ss); 2624 } else if ( !strcasecmp(sval,"AUXILIARY") ) { 2625 LDAP_FREE(sval); 2626 if ( seen_kind ) { 2627 *code = LDAP_SCHERR_DUPOPT; 2628 *errp = ss; 2629 ldap_objectclass_free(oc); 2630 return(NULL); 2631 } 2632 seen_kind = 1; 2633 oc->oc_kind = LDAP_SCHEMA_AUXILIARY; 2634 parse_whsp(&ss); 2635 } else if ( !strcasecmp(sval,"MUST") ) { 2636 LDAP_FREE(sval); 2637 if ( seen_must ) { 2638 *code = LDAP_SCHERR_DUPOPT; 2639 *errp = ss; 2640 ldap_objectclass_free(oc); 2641 return(NULL); 2642 } 2643 seen_must = 1; 2644 oc->oc_at_oids_must = parse_oids(&ss,code,0); 2645 if ( !oc->oc_at_oids_must && *code != LDAP_SUCCESS ) { 2646 *errp = ss; 2647 ldap_objectclass_free(oc); 2648 return NULL; 2649 } 2650 *code = 0; 2651 parse_whsp(&ss); 2652 } else if ( !strcasecmp(sval,"MAY") ) { 2653 LDAP_FREE(sval); 2654 if ( seen_may ) { 2655 *code = LDAP_SCHERR_DUPOPT; 2656 *errp = ss; 2657 ldap_objectclass_free(oc); 2658 return(NULL); 2659 } 2660 seen_may = 1; 2661 oc->oc_at_oids_may = parse_oids(&ss,code,0); 2662 if ( !oc->oc_at_oids_may && *code != LDAP_SUCCESS ) { 2663 *errp = ss; 2664 ldap_objectclass_free(oc); 2665 return NULL; 2666 } 2667 *code = 0; 2668 parse_whsp(&ss); 2669 } else if ( sval[0] == 'X' && sval[1] == '-' ) { 2670 /* Should be parse_qdstrings */ 2671 ext_vals = parse_qdescrs(&ss, code); 2672 *code = 0; 2673 if ( !ext_vals ) { 2674 *errp = ss; 2675 ldap_objectclass_free(oc); 2676 return NULL; 2677 } 2678 if ( add_extension(&oc->oc_extensions, 2679 sval, ext_vals) ) { 2680 *code = LDAP_SCHERR_OUTOFMEM; 2681 *errp = ss; 2682 LDAP_FREE(sval); 2683 ldap_objectclass_free(oc); 2684 return NULL; 2685 } 2686 } else { 2687 *code = LDAP_SCHERR_UNEXPTOKEN; 2688 *errp = ss; 2689 LDAP_FREE(sval); 2690 ldap_objectclass_free(oc); 2691 return NULL; 2692 } 2693 break; 2694 default: 2695 *code = LDAP_SCHERR_UNEXPTOKEN; 2696 *errp = ss; 2697 LDAP_FREE(sval); 2698 ldap_objectclass_free(oc); 2699 return NULL; 2700 } 2701 } 2702 } 2703 2704 void 2705 ldap_contentrule_free(LDAPContentRule * cr) 2706 { 2707 if (!cr) return; 2708 LDAP_FREE(cr->cr_oid); 2709 if (cr->cr_names) LDAP_VFREE(cr->cr_names); 2710 if (cr->cr_desc) LDAP_FREE(cr->cr_desc); 2711 if (cr->cr_oc_oids_aux) LDAP_VFREE(cr->cr_oc_oids_aux); 2712 if (cr->cr_at_oids_must) LDAP_VFREE(cr->cr_at_oids_must); 2713 if (cr->cr_at_oids_may) LDAP_VFREE(cr->cr_at_oids_may); 2714 if (cr->cr_at_oids_not) LDAP_VFREE(cr->cr_at_oids_not); 2715 free_extensions(cr->cr_extensions); 2716 LDAP_FREE(cr); 2717 } 2718 2719 LDAPContentRule * 2720 ldap_str2contentrule( LDAP_CONST char * s, 2721 int * code, 2722 LDAP_CONST char ** errp, 2723 LDAP_CONST unsigned flags ) 2724 { 2725 tk_t kind; 2726 const char * ss = s; 2727 char * sval; 2728 int seen_name = 0; 2729 int seen_desc = 0; 2730 int seen_obsolete = 0; 2731 int seen_aux = 0; 2732 int seen_must = 0; 2733 int seen_may = 0; 2734 int seen_not = 0; 2735 LDAPContentRule * cr; 2736 char ** ext_vals; 2737 const char * savepos; 2738 2739 if ( !s ) { 2740 *code = LDAP_SCHERR_EMPTY; 2741 *errp = ""; 2742 return NULL; 2743 } 2744 2745 *errp = s; 2746 cr = LDAP_CALLOC(1,sizeof(LDAPContentRule)); 2747 2748 if ( !cr ) { 2749 *code = LDAP_SCHERR_OUTOFMEM; 2750 return NULL; 2751 } 2752 2753 kind = get_token(&ss,&sval); 2754 if ( kind != TK_LEFTPAREN ) { 2755 *code = LDAP_SCHERR_NOLEFTPAREN; 2756 LDAP_FREE(sval); 2757 ldap_contentrule_free(cr); 2758 return NULL; 2759 } 2760 2761 /* 2762 * Definitions MUST begin with an OID in the numericoid format. 2763 */ 2764 parse_whsp(&ss); 2765 savepos = ss; 2766 cr->cr_oid = ldap_int_parse_numericoid(&ss,code,0); 2767 if ( !cr->cr_oid ) { 2768 if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) { 2769 /* Backtracking */ 2770 ss = savepos; 2771 kind = get_token(&ss,&sval); 2772 if ( kind == TK_BAREWORD ) { 2773 if ( !strcasecmp(sval, "NAME") || 2774 !strcasecmp(sval, "DESC") || 2775 !strcasecmp(sval, "OBSOLETE") || 2776 !strcasecmp(sval, "AUX") || 2777 !strcasecmp(sval, "MUST") || 2778 !strcasecmp(sval, "MAY") || 2779 !strcasecmp(sval, "NOT") || 2780 !strncasecmp(sval, "X-", 2) ) { 2781 /* Missing OID, backtrack */ 2782 ss = savepos; 2783 } else if ( flags & 2784 LDAP_SCHEMA_ALLOW_OID_MACRO ) { 2785 /* Non-numerical OID, ignore */ 2786 int len = ss-savepos; 2787 cr->cr_oid = LDAP_MALLOC(len+1); 2788 strncpy(cr->cr_oid, savepos, len); 2789 cr->cr_oid[len] = 0; 2790 } 2791 } 2792 LDAP_FREE(sval); 2793 } else { 2794 *errp = ss; 2795 ldap_contentrule_free(cr); 2796 return NULL; 2797 } 2798 } 2799 parse_whsp(&ss); 2800 2801 /* 2802 * Beyond this point we will be liberal an accept the items 2803 * in any order. 2804 */ 2805 while (1) { 2806 kind = get_token(&ss,&sval); 2807 switch (kind) { 2808 case TK_EOS: 2809 *code = LDAP_SCHERR_NORIGHTPAREN; 2810 *errp = EndOfInput; 2811 ldap_contentrule_free(cr); 2812 return NULL; 2813 case TK_RIGHTPAREN: 2814 return cr; 2815 case TK_BAREWORD: 2816 if ( !strcasecmp(sval,"NAME") ) { 2817 LDAP_FREE(sval); 2818 if ( seen_name ) { 2819 *code = LDAP_SCHERR_DUPOPT; 2820 *errp = ss; 2821 ldap_contentrule_free(cr); 2822 return(NULL); 2823 } 2824 seen_name = 1; 2825 cr->cr_names = parse_qdescrs(&ss,code); 2826 if ( !cr->cr_names ) { 2827 if ( *code != LDAP_SCHERR_OUTOFMEM ) 2828 *code = LDAP_SCHERR_BADNAME; 2829 *errp = ss; 2830 ldap_contentrule_free(cr); 2831 return NULL; 2832 } 2833 } else if ( !strcasecmp(sval,"DESC") ) { 2834 LDAP_FREE(sval); 2835 if ( seen_desc ) { 2836 *code = LDAP_SCHERR_DUPOPT; 2837 *errp = ss; 2838 ldap_contentrule_free(cr); 2839 return(NULL); 2840 } 2841 seen_desc = 1; 2842 parse_whsp(&ss); 2843 kind = get_token(&ss,&sval); 2844 if ( kind != TK_QDSTRING ) { 2845 *code = LDAP_SCHERR_UNEXPTOKEN; 2846 *errp = ss; 2847 LDAP_FREE(sval); 2848 ldap_contentrule_free(cr); 2849 return NULL; 2850 } 2851 cr->cr_desc = sval; 2852 parse_whsp(&ss); 2853 } else if ( !strcasecmp(sval,"OBSOLETE") ) { 2854 LDAP_FREE(sval); 2855 if ( seen_obsolete ) { 2856 *code = LDAP_SCHERR_DUPOPT; 2857 *errp = ss; 2858 ldap_contentrule_free(cr); 2859 return(NULL); 2860 } 2861 seen_obsolete = 1; 2862 cr->cr_obsolete = LDAP_SCHEMA_YES; 2863 parse_whsp(&ss); 2864 } else if ( !strcasecmp(sval,"AUX") ) { 2865 LDAP_FREE(sval); 2866 if ( seen_aux ) { 2867 *code = LDAP_SCHERR_DUPOPT; 2868 *errp = ss; 2869 ldap_contentrule_free(cr); 2870 return(NULL); 2871 } 2872 seen_aux = 1; 2873 cr->cr_oc_oids_aux = parse_oids(&ss,code,0); 2874 if ( !cr->cr_oc_oids_aux ) { 2875 *errp = ss; 2876 ldap_contentrule_free(cr); 2877 return NULL; 2878 } 2879 parse_whsp(&ss); 2880 } else if ( !strcasecmp(sval,"MUST") ) { 2881 LDAP_FREE(sval); 2882 if ( seen_must ) { 2883 *code = LDAP_SCHERR_DUPOPT; 2884 *errp = ss; 2885 ldap_contentrule_free(cr); 2886 return(NULL); 2887 } 2888 seen_must = 1; 2889 cr->cr_at_oids_must = parse_oids(&ss,code,0); 2890 if ( !cr->cr_at_oids_must && *code != LDAP_SUCCESS ) { 2891 *errp = ss; 2892 ldap_contentrule_free(cr); 2893 return NULL; 2894 } 2895 parse_whsp(&ss); 2896 } else if ( !strcasecmp(sval,"MAY") ) { 2897 LDAP_FREE(sval); 2898 if ( seen_may ) { 2899 *code = LDAP_SCHERR_DUPOPT; 2900 *errp = ss; 2901 ldap_contentrule_free(cr); 2902 return(NULL); 2903 } 2904 seen_may = 1; 2905 cr->cr_at_oids_may = parse_oids(&ss,code,0); 2906 if ( !cr->cr_at_oids_may && *code != LDAP_SUCCESS ) { 2907 *errp = ss; 2908 ldap_contentrule_free(cr); 2909 return NULL; 2910 } 2911 parse_whsp(&ss); 2912 } else if ( !strcasecmp(sval,"NOT") ) { 2913 LDAP_FREE(sval); 2914 if ( seen_not ) { 2915 *code = LDAP_SCHERR_DUPOPT; 2916 *errp = ss; 2917 ldap_contentrule_free(cr); 2918 return(NULL); 2919 } 2920 seen_not = 1; 2921 cr->cr_at_oids_not = parse_oids(&ss,code,0); 2922 if ( !cr->cr_at_oids_not && *code != LDAP_SUCCESS ) { 2923 *errp = ss; 2924 ldap_contentrule_free(cr); 2925 return NULL; 2926 } 2927 parse_whsp(&ss); 2928 } else if ( sval[0] == 'X' && sval[1] == '-' ) { 2929 /* Should be parse_qdstrings */ 2930 ext_vals = parse_qdescrs(&ss, code); 2931 if ( !ext_vals ) { 2932 *errp = ss; 2933 ldap_contentrule_free(cr); 2934 return NULL; 2935 } 2936 if ( add_extension(&cr->cr_extensions, 2937 sval, ext_vals) ) { 2938 *code = LDAP_SCHERR_OUTOFMEM; 2939 *errp = ss; 2940 LDAP_FREE(sval); 2941 ldap_contentrule_free(cr); 2942 return NULL; 2943 } 2944 } else { 2945 *code = LDAP_SCHERR_UNEXPTOKEN; 2946 *errp = ss; 2947 LDAP_FREE(sval); 2948 ldap_contentrule_free(cr); 2949 return NULL; 2950 } 2951 break; 2952 default: 2953 *code = LDAP_SCHERR_UNEXPTOKEN; 2954 *errp = ss; 2955 LDAP_FREE(sval); 2956 ldap_contentrule_free(cr); 2957 return NULL; 2958 } 2959 } 2960 } 2961 2962 void 2963 ldap_structurerule_free(LDAPStructureRule * sr) 2964 { 2965 if (!sr) return; 2966 if (sr->sr_names) LDAP_VFREE(sr->sr_names); 2967 if (sr->sr_desc) LDAP_FREE(sr->sr_desc); 2968 if (sr->sr_nameform) LDAP_FREE(sr->sr_nameform); 2969 if (sr->sr_sup_ruleids) LDAP_FREE(sr->sr_sup_ruleids); 2970 free_extensions(sr->sr_extensions); 2971 LDAP_FREE(sr); 2972 } 2973 2974 LDAPStructureRule * 2975 ldap_str2structurerule( LDAP_CONST char * s, 2976 int * code, 2977 LDAP_CONST char ** errp, 2978 LDAP_CONST unsigned flags ) 2979 { 2980 tk_t kind; 2981 int ret; 2982 const char * ss = s; 2983 char * sval; 2984 int seen_name = 0; 2985 int seen_desc = 0; 2986 int seen_obsolete = 0; 2987 int seen_nameform = 0; 2988 LDAPStructureRule * sr; 2989 char ** ext_vals; 2990 const char * savepos; 2991 2992 if ( !s ) { 2993 *code = LDAP_SCHERR_EMPTY; 2994 *errp = ""; 2995 return NULL; 2996 } 2997 2998 *errp = s; 2999 sr = LDAP_CALLOC(1,sizeof(LDAPStructureRule)); 3000 3001 if ( !sr ) { 3002 *code = LDAP_SCHERR_OUTOFMEM; 3003 return NULL; 3004 } 3005 3006 kind = get_token(&ss,&sval); 3007 if ( kind != TK_LEFTPAREN ) { 3008 *code = LDAP_SCHERR_NOLEFTPAREN; 3009 LDAP_FREE(sval); 3010 ldap_structurerule_free(sr); 3011 return NULL; 3012 } 3013 3014 /* 3015 * Definitions MUST begin with a ruleid. 3016 */ 3017 parse_whsp(&ss); 3018 savepos = ss; 3019 ret = ldap_int_parse_ruleid(&ss,code,0,&sr->sr_ruleid); 3020 if ( ret ) { 3021 *errp = ss; 3022 ldap_structurerule_free(sr); 3023 return NULL; 3024 } 3025 parse_whsp(&ss); 3026 3027 /* 3028 * Beyond this point we will be liberal an accept the items 3029 * in any order. 3030 */ 3031 while (1) { 3032 kind = get_token(&ss,&sval); 3033 switch (kind) { 3034 case TK_EOS: 3035 *code = LDAP_SCHERR_NORIGHTPAREN; 3036 *errp = EndOfInput; 3037 ldap_structurerule_free(sr); 3038 return NULL; 3039 case TK_RIGHTPAREN: 3040 if( !seen_nameform ) { 3041 *code = LDAP_SCHERR_MISSING; 3042 ldap_structurerule_free(sr); 3043 return NULL; 3044 } 3045 return sr; 3046 case TK_BAREWORD: 3047 if ( !strcasecmp(sval,"NAME") ) { 3048 LDAP_FREE(sval); 3049 if ( seen_name ) { 3050 *code = LDAP_SCHERR_DUPOPT; 3051 *errp = ss; 3052 ldap_structurerule_free(sr); 3053 return(NULL); 3054 } 3055 seen_name = 1; 3056 sr->sr_names = parse_qdescrs(&ss,code); 3057 if ( !sr->sr_names ) { 3058 if ( *code != LDAP_SCHERR_OUTOFMEM ) 3059 *code = LDAP_SCHERR_BADNAME; 3060 *errp = ss; 3061 ldap_structurerule_free(sr); 3062 return NULL; 3063 } 3064 } else if ( !strcasecmp(sval,"DESC") ) { 3065 LDAP_FREE(sval); 3066 if ( seen_desc ) { 3067 *code = LDAP_SCHERR_DUPOPT; 3068 *errp = ss; 3069 ldap_structurerule_free(sr); 3070 return(NULL); 3071 } 3072 seen_desc = 1; 3073 parse_whsp(&ss); 3074 kind = get_token(&ss,&sval); 3075 if ( kind != TK_QDSTRING ) { 3076 *code = LDAP_SCHERR_UNEXPTOKEN; 3077 *errp = ss; 3078 LDAP_FREE(sval); 3079 ldap_structurerule_free(sr); 3080 return NULL; 3081 } 3082 sr->sr_desc = sval; 3083 parse_whsp(&ss); 3084 } else if ( !strcasecmp(sval,"OBSOLETE") ) { 3085 LDAP_FREE(sval); 3086 if ( seen_obsolete ) { 3087 *code = LDAP_SCHERR_DUPOPT; 3088 *errp = ss; 3089 ldap_structurerule_free(sr); 3090 return(NULL); 3091 } 3092 seen_obsolete = 1; 3093 sr->sr_obsolete = LDAP_SCHEMA_YES; 3094 parse_whsp(&ss); 3095 } else if ( !strcasecmp(sval,"FORM") ) { 3096 LDAP_FREE(sval); 3097 if ( seen_nameform ) { 3098 *code = LDAP_SCHERR_DUPOPT; 3099 *errp = ss; 3100 ldap_structurerule_free(sr); 3101 return(NULL); 3102 } 3103 seen_nameform = 1; 3104 sr->sr_nameform = parse_woid(&ss,code); 3105 if ( !sr->sr_nameform ) { 3106 *errp = ss; 3107 ldap_structurerule_free(sr); 3108 return NULL; 3109 } 3110 parse_whsp(&ss); 3111 } else if ( sval[0] == 'X' && sval[1] == '-' ) { 3112 /* Should be parse_qdstrings */ 3113 ext_vals = parse_qdescrs(&ss, code); 3114 if ( !ext_vals ) { 3115 *errp = ss; 3116 ldap_structurerule_free(sr); 3117 return NULL; 3118 } 3119 if ( add_extension(&sr->sr_extensions, 3120 sval, ext_vals) ) { 3121 *code = LDAP_SCHERR_OUTOFMEM; 3122 *errp = ss; 3123 LDAP_FREE(sval); 3124 ldap_structurerule_free(sr); 3125 return NULL; 3126 } 3127 } else { 3128 *code = LDAP_SCHERR_UNEXPTOKEN; 3129 *errp = ss; 3130 LDAP_FREE(sval); 3131 ldap_structurerule_free(sr); 3132 return NULL; 3133 } 3134 break; 3135 default: 3136 *code = LDAP_SCHERR_UNEXPTOKEN; 3137 *errp = ss; 3138 LDAP_FREE(sval); 3139 ldap_structurerule_free(sr); 3140 return NULL; 3141 } 3142 } 3143 } 3144 3145 void 3146 ldap_nameform_free(LDAPNameForm * nf) 3147 { 3148 if (!nf) return; 3149 LDAP_FREE(nf->nf_oid); 3150 if (nf->nf_names) LDAP_VFREE(nf->nf_names); 3151 if (nf->nf_desc) LDAP_FREE(nf->nf_desc); 3152 if (nf->nf_objectclass) LDAP_FREE(nf->nf_objectclass); 3153 if (nf->nf_at_oids_must) LDAP_VFREE(nf->nf_at_oids_must); 3154 if (nf->nf_at_oids_may) LDAP_VFREE(nf->nf_at_oids_may); 3155 free_extensions(nf->nf_extensions); 3156 LDAP_FREE(nf); 3157 } 3158 3159 LDAPNameForm * 3160 ldap_str2nameform( LDAP_CONST char * s, 3161 int * code, 3162 LDAP_CONST char ** errp, 3163 LDAP_CONST unsigned flags ) 3164 { 3165 tk_t kind; 3166 const char * ss = s; 3167 char * sval; 3168 int seen_name = 0; 3169 int seen_desc = 0; 3170 int seen_obsolete = 0; 3171 int seen_class = 0; 3172 int seen_must = 0; 3173 int seen_may = 0; 3174 LDAPNameForm * nf; 3175 char ** ext_vals; 3176 const char * savepos; 3177 3178 if ( !s ) { 3179 *code = LDAP_SCHERR_EMPTY; 3180 *errp = ""; 3181 return NULL; 3182 } 3183 3184 *errp = s; 3185 nf = LDAP_CALLOC(1,sizeof(LDAPNameForm)); 3186 3187 if ( !nf ) { 3188 *code = LDAP_SCHERR_OUTOFMEM; 3189 return NULL; 3190 } 3191 3192 kind = get_token(&ss,&sval); 3193 if ( kind != TK_LEFTPAREN ) { 3194 *code = LDAP_SCHERR_NOLEFTPAREN; 3195 LDAP_FREE(sval); 3196 ldap_nameform_free(nf); 3197 return NULL; 3198 } 3199 3200 /* 3201 * Definitions MUST begin with an OID in the numericoid format. 3202 * However, this routine is used by clients to parse the response 3203 * from servers and very well known servers will provide an OID 3204 * in the wrong format or even no OID at all. We do our best to 3205 * extract info from those servers. 3206 */ 3207 parse_whsp(&ss); 3208 savepos = ss; 3209 nf->nf_oid = ldap_int_parse_numericoid(&ss,code,0); 3210 if ( !nf->nf_oid ) { 3211 *errp = ss; 3212 ldap_nameform_free(nf); 3213 return NULL; 3214 } 3215 parse_whsp(&ss); 3216 3217 /* 3218 * Beyond this point we will be liberal an accept the items 3219 * in any order. 3220 */ 3221 while (1) { 3222 kind = get_token(&ss,&sval); 3223 switch (kind) { 3224 case TK_EOS: 3225 *code = LDAP_SCHERR_NORIGHTPAREN; 3226 *errp = EndOfInput; 3227 ldap_nameform_free(nf); 3228 return NULL; 3229 case TK_RIGHTPAREN: 3230 if( !seen_class || !seen_must ) { 3231 *code = LDAP_SCHERR_MISSING; 3232 ldap_nameform_free(nf); 3233 return NULL; 3234 } 3235 return nf; 3236 case TK_BAREWORD: 3237 if ( !strcasecmp(sval,"NAME") ) { 3238 LDAP_FREE(sval); 3239 if ( seen_name ) { 3240 *code = LDAP_SCHERR_DUPOPT; 3241 *errp = ss; 3242 ldap_nameform_free(nf); 3243 return(NULL); 3244 } 3245 seen_name = 1; 3246 nf->nf_names = parse_qdescrs(&ss,code); 3247 if ( !nf->nf_names ) { 3248 if ( *code != LDAP_SCHERR_OUTOFMEM ) 3249 *code = LDAP_SCHERR_BADNAME; 3250 *errp = ss; 3251 ldap_nameform_free(nf); 3252 return NULL; 3253 } 3254 } else if ( !strcasecmp(sval,"DESC") ) { 3255 LDAP_FREE(sval); 3256 if ( seen_desc ) { 3257 *code = LDAP_SCHERR_DUPOPT; 3258 *errp = ss; 3259 ldap_nameform_free(nf); 3260 return(NULL); 3261 } 3262 seen_desc = 1; 3263 parse_whsp(&ss); 3264 kind = get_token(&ss,&sval); 3265 if ( kind != TK_QDSTRING ) { 3266 *code = LDAP_SCHERR_UNEXPTOKEN; 3267 *errp = ss; 3268 LDAP_FREE(sval); 3269 ldap_nameform_free(nf); 3270 return NULL; 3271 } 3272 nf->nf_desc = sval; 3273 parse_whsp(&ss); 3274 } else if ( !strcasecmp(sval,"OBSOLETE") ) { 3275 LDAP_FREE(sval); 3276 if ( seen_obsolete ) { 3277 *code = LDAP_SCHERR_DUPOPT; 3278 *errp = ss; 3279 ldap_nameform_free(nf); 3280 return(NULL); 3281 } 3282 seen_obsolete = 1; 3283 nf->nf_obsolete = LDAP_SCHEMA_YES; 3284 parse_whsp(&ss); 3285 } else if ( !strcasecmp(sval,"OC") ) { 3286 LDAP_FREE(sval); 3287 if ( seen_class ) { 3288 *code = LDAP_SCHERR_DUPOPT; 3289 *errp = ss; 3290 ldap_nameform_free(nf); 3291 return(NULL); 3292 } 3293 seen_class = 1; 3294 nf->nf_objectclass = parse_woid(&ss,code); 3295 if ( !nf->nf_objectclass ) { 3296 *errp = ss; 3297 ldap_nameform_free(nf); 3298 return NULL; 3299 } 3300 } else if ( !strcasecmp(sval,"MUST") ) { 3301 LDAP_FREE(sval); 3302 if ( seen_must ) { 3303 *code = LDAP_SCHERR_DUPOPT; 3304 *errp = ss; 3305 ldap_nameform_free(nf); 3306 return(NULL); 3307 } 3308 seen_must = 1; 3309 nf->nf_at_oids_must = parse_oids(&ss,code,0); 3310 if ( !nf->nf_at_oids_must && *code != LDAP_SUCCESS ) { 3311 *errp = ss; 3312 ldap_nameform_free(nf); 3313 return NULL; 3314 } 3315 parse_whsp(&ss); 3316 } else if ( !strcasecmp(sval,"MAY") ) { 3317 LDAP_FREE(sval); 3318 if ( seen_may ) { 3319 *code = LDAP_SCHERR_DUPOPT; 3320 *errp = ss; 3321 ldap_nameform_free(nf); 3322 return(NULL); 3323 } 3324 seen_may = 1; 3325 nf->nf_at_oids_may = parse_oids(&ss,code,0); 3326 if ( !nf->nf_at_oids_may && *code != LDAP_SUCCESS ) { 3327 *errp = ss; 3328 ldap_nameform_free(nf); 3329 return NULL; 3330 } 3331 parse_whsp(&ss); 3332 } else if ( sval[0] == 'X' && sval[1] == '-' ) { 3333 /* Should be parse_qdstrings */ 3334 ext_vals = parse_qdescrs(&ss, code); 3335 if ( !ext_vals ) { 3336 *errp = ss; 3337 ldap_nameform_free(nf); 3338 return NULL; 3339 } 3340 if ( add_extension(&nf->nf_extensions, 3341 sval, ext_vals) ) { 3342 *code = LDAP_SCHERR_OUTOFMEM; 3343 *errp = ss; 3344 LDAP_FREE(sval); 3345 ldap_nameform_free(nf); 3346 return NULL; 3347 } 3348 } else { 3349 *code = LDAP_SCHERR_UNEXPTOKEN; 3350 *errp = ss; 3351 LDAP_FREE(sval); 3352 ldap_nameform_free(nf); 3353 return NULL; 3354 } 3355 break; 3356 default: 3357 *code = LDAP_SCHERR_UNEXPTOKEN; 3358 *errp = ss; 3359 LDAP_FREE(sval); 3360 ldap_nameform_free(nf); 3361 return NULL; 3362 } 3363 } 3364 } 3365 3366 static char *const err2text[] = { 3367 N_("Success"), 3368 N_("Out of memory"), 3369 N_("Unexpected token"), 3370 N_("Missing opening parenthesis"), 3371 N_("Missing closing parenthesis"), 3372 N_("Expecting digit"), 3373 N_("Expecting a name"), 3374 N_("Bad description"), 3375 N_("Bad superiors"), 3376 N_("Duplicate option"), 3377 N_("Unexpected end of data"), 3378 N_("Missing required field"), 3379 N_("Out of order field") 3380 }; 3381 3382 char * 3383 ldap_scherr2str(int code) 3384 { 3385 if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) { 3386 return _("Unknown error"); 3387 } else { 3388 return _(err2text[code]); 3389 } 3390 } 3391