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