Home | History | Annotate | Line # | Download | only in libldap
      1 /*	$NetBSD: schema.c,v 1.4 2025/09/05 21:16:21 christos Exp $	*/
      2 
      3 /* $OpenLDAP$ */
      4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      5  *
      6  * Copyright 1998-2024 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.4 2025/09/05 21:16:21 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 
     38 static const char EndOfInput[] = "end of input";
     39 
     40 static const char *
     41 choose_name( char *names[], const char *fallback )
     42 {
     43 	return (names != NULL && names[0] != NULL) ? names[0] : fallback;
     44 }
     45 
     46 LDAP_CONST char *
     47 ldap_syntax2name( LDAPSyntax * syn )
     48 {
     49 	if (!syn) return NULL;
     50 	return( syn->syn_oid );
     51 }
     52 
     53 LDAP_CONST char *
     54 ldap_matchingrule2name( LDAPMatchingRule * mr )
     55 {
     56 	if (!mr) return NULL;
     57 	return( choose_name( mr->mr_names, mr->mr_oid ) );
     58 }
     59 
     60 LDAP_CONST char *
     61 ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru )
     62 {
     63 	if (!mru) return NULL;
     64 	return( choose_name( mru->mru_names, mru->mru_oid ) );
     65 }
     66 
     67 LDAP_CONST char *
     68 ldap_attributetype2name( LDAPAttributeType * at )
     69 {
     70 	if (!at) return NULL;
     71 	return( choose_name( at->at_names, at->at_oid ) );
     72 }
     73 
     74 LDAP_CONST char *
     75 ldap_objectclass2name( LDAPObjectClass * oc )
     76 {
     77 	if (!oc) return NULL;
     78 	return( choose_name( oc->oc_names, oc->oc_oid ) );
     79 }
     80 
     81 LDAP_CONST char *
     82 ldap_contentrule2name( LDAPContentRule * cr )
     83 {
     84 	if (!cr) return NULL;
     85 	return( choose_name( cr->cr_names, cr->cr_oid ) );
     86 }
     87 
     88 LDAP_CONST char *
     89 ldap_nameform2name( LDAPNameForm * nf )
     90 {
     91 	if (!nf) return NULL;
     92 	return( choose_name( nf->nf_names, nf->nf_oid ) );
     93 }
     94 
     95 LDAP_CONST char *
     96 ldap_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 
    110 typedef struct safe_string {
    111 	char * val;
    112 	ber_len_t size;
    113 	ber_len_t pos;
    114 	int at_whsp;
    115 } safe_string;
    116 
    117 static safe_string *
    118 new_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 
    139 static void
    140 safe_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 */
    149 static char *
    150 safe_string_val(safe_string * ss)
    151 {
    152 	ss->val[ss->pos] = '\0';
    153 	return(ss->val);
    154 }
    155 #endif
    156 
    157 static char *
    158 safe_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 
    168 static int
    169 append_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 
    206 static int
    207 print_literal(safe_string *ss, char *s)
    208 {
    209 	return(append_to_safe_string(ss,s));
    210 }
    211 
    212 static int
    213 print_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 
    221 static int
    222 print_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 */
    231 static int
    232 print_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 
    241 static int
    242 print_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 
    251 static int
    252 print_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 
    267 static int
    268 print_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 
    287 static int
    288 print_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 
    295 static int
    296 print_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 
    307 static int
    308 print_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 
    320 static int
    321 print_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 
    334 static int
    335 print_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 
    342 static int
    343 print_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 
    362 static int
    363 print_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 
    381 char *
    382 ldap_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 
    391 struct berval *
    392 ldap_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 
    426 char *
    427 ldap_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 
    436 struct berval *
    437 ldap_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 
    488 char *
    489 ldap_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 
    498 struct berval *
    499 ldap_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 
    550 char *
    551 ldap_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 
    560 struct berval *
    561 ldap_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 
    642 char *
    643 ldap_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 
    652 struct berval *
    653 ldap_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 
    724 char *
    725 ldap_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 
    734 struct berval *
    735 ldap_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 
    791 char *
    792 ldap_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 
    801 struct berval *
    802 ldap_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 
    863 char *
    864 ldap_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 
    873 struct berval *
    874 ldap_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 
   1001 typedef 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 
   1014 static tk_t
   1015 get_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 */
   1092 static void
   1093 parse_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 */
   1108 char *
   1109 ldap_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 */
   1165 int
   1166 ldap_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 () */
   1187 static char **
   1188 parse_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 */
   1255 static char *
   1256 parse_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 */
   1273 static char *
   1274 parse_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 () */
   1337 static char **
   1338 parse_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 
   1440 static int
   1441 add_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 
   1477 static void
   1478 free_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 
   1492 void
   1493 ldap_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 
   1503 LDAPSyntax *
   1504 ldap_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 
   1634 void
   1635 ldap_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 
   1646 LDAPMatchingRule *
   1647 ldap_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 
   1834 void
   1835 ldap_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 
   1846 LDAPMatchingRuleUse *
   1847 ldap_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 
   2033 void
   2034 ldap_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 
   2049 LDAPAttributeType *
   2050 ldap_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 
   2422 void
   2423 ldap_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 
   2436 LDAPObjectClass *
   2437 ldap_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 
   2714 void
   2715 ldap_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 
   2729 LDAPContentRule *
   2730 ldap_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 
   2977 void
   2978 ldap_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 
   2989 LDAPStructureRule *
   2990 ldap_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 
   3160 void
   3161 ldap_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 
   3174 LDAPNameForm *
   3175 ldap_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 
   3381 static 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 
   3397 char *
   3398 ldap_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