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