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