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