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