X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fschema.c;h=86f26e638828c28f3ecc4980e37e3796454960c7;hb=de01a6e3d791d3458549d2ceeccf4d7e0477ff78;hp=d3fb9a836cd3bf9b94054746440359856fc0008f;hpb=4a5e2febed6fdffa1e10ce3ae15340f35aa4742e;p=openldap diff --git a/libraries/libldap/schema.c b/libraries/libldap/schema.c index d3fb9a836c..86f26e6388 100644 --- a/libraries/libldap/schema.c +++ b/libraries/libldap/schema.c @@ -1,7 +1,18 @@ -/* - * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved. - * COPYING RESTRICTIONS APPLY, see COPYRIGHT file +/* $OpenLDAP$ */ +/* This work is part of OpenLDAP Software . + * + * Copyright 1998-2007 The OpenLDAP Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted only as authorized by the OpenLDAP + * Public License. + * + * A copy of this license is available in the file LICENSE in the + * top-level directory of the distribution or, alternatively, at + * . */ + /* * schema.c: parsing routines used by servers and clients to process * schema definitions @@ -12,7 +23,6 @@ #include #include -#include #include #include @@ -20,37 +30,59 @@ #include - -static LDAP_CONST char * -choose_name( char *names[], LDAP_CONST char *fallback ) +static const char * +choose_name( char *names[], const char *fallback ) { - return( (names != NULL && names[0] != NULL) ? names[0] : fallback ); + return (names != NULL && names[0] != NULL) ? names[0] : fallback; } LDAP_CONST char * -ldap_syntax2name( LDAP_SYNTAX * syn ) +ldap_syntax2name( LDAPSyntax * syn ) { return( syn->syn_oid ); } LDAP_CONST char * -ldap_matchingrule2name( LDAP_MATCHING_RULE * mr ) +ldap_matchingrule2name( LDAPMatchingRule * mr ) { return( choose_name( mr->mr_names, mr->mr_oid ) ); } LDAP_CONST char * -ldap_attributetype2name( LDAP_ATTRIBUTE_TYPE * at ) +ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru ) +{ + return( choose_name( mru->mru_names, mru->mru_oid ) ); +} + +LDAP_CONST char * +ldap_attributetype2name( LDAPAttributeType * at ) { return( choose_name( at->at_names, at->at_oid ) ); } LDAP_CONST char * -ldap_objectclass2name( LDAP_OBJECT_CLASS * oc ) +ldap_objectclass2name( LDAPObjectClass * oc ) { return( choose_name( oc->oc_names, oc->oc_oid ) ); } +LDAP_CONST char * +ldap_contentrule2name( LDAPContentRule * cr ) +{ + return( choose_name( cr->cr_names, cr->cr_oid ) ); +} + +LDAP_CONST char * +ldap_nameform2name( LDAPNameForm * nf ) +{ + return( choose_name( nf->nf_names, nf->nf_oid ) ); +} + +LDAP_CONST char * +ldap_structurerule2name( LDAPStructureRule * sr ) +{ + return( choose_name( sr->sr_names, NULL ) ); +} /* * When pretty printing the entities we will be appending to a buffer. @@ -98,12 +130,25 @@ safe_string_free(safe_string * ss) LDAP_FREE(ss); } +#if 0 /* unused */ static char * safe_string_val(safe_string * ss) { ss->val[ss->pos] = '\0'; return(ss->val); } +#endif + +static char * +safe_strdup(safe_string * ss) +{ + char *ret = LDAP_MALLOC(ss->pos+1); + if (!ret) + return NULL; + AC_MEMCPY(ret, ss->val, ss->pos); + ret[ss->pos] = '\0'; + return ret; +} static int append_to_safe_string(safe_string * ss, char * s) @@ -121,6 +166,10 @@ append_to_safe_string(safe_string * ss, char * s) /* We always make sure there is at least one position available */ if ( ss->pos + l >= ss->size-1 ) { ss->size *= 2; + if ( ss->pos + l >= ss->size-1 ) { + ss->size = ss->pos + l + 1; + } + temp = LDAP_REALLOC(ss->val, ss->size); if ( !temp ) { /* Trouble, out of memory */ @@ -131,7 +180,7 @@ append_to_safe_string(safe_string * ss, char * s) } strncpy(&ss->val[ss->pos], s, l); ss->pos += l; - if ( ss->pos > 0 && isspace(ss->val[ss->pos-1]) ) + if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) ) ss->at_whsp = 1; else ss->at_whsp = 0; @@ -211,9 +260,9 @@ print_qdescrs(safe_string *ss, char **sa) */ if ( !sa[0] || ( sa[0] && sa[1] ) ) { print_whsp(ss); - print_literal(ss,"("); + print_literal(ss,"("/*)*/); print_qdescrlist(ss,sa); - print_literal(ss,")"); + print_literal(ss,/*(*/")"); return(print_whsp(ss)); } else { return(print_qdescr(ss,*sa)); @@ -244,10 +293,10 @@ static int print_oids(safe_string *ss, char **sa) { if ( sa[0] && sa[1] ) { - print_literal(ss,"("); + print_literal(ss,"("/*)*/); print_oidlist(ss,sa); print_whsp(ss); - return(print_literal(ss,")")); + return(print_literal(ss,/*(*/")")); } else { return(print_woid(ss,*sa)); } @@ -261,23 +310,79 @@ print_noidlen(safe_string *ss, char *s, int l) ret = print_numericoid(ss,s); if ( l ) { - sprintf(buf,"{%d}",l); + snprintf(buf, sizeof buf, "{%d}",l); ret = print_literal(ss,buf); } return(ret); } +static int +print_ruleid(safe_string *ss, int rid) +{ + char buf[64]; + snprintf(buf, sizeof buf, "%d", rid); + return print_literal(ss,buf); +} + +static int +print_ruleids(safe_string *ss, int n, int *rids) +{ + int i; + + if( n == 1 ) { + print_ruleid(ss,rids[0]); + return print_whsp(ss); + } else { + print_literal(ss,"("/*)*/); + for( i=0; ilsei_name); + print_whsp(ss); + /* Should be print_qdstrings */ + print_qdescrs(ss, (*ext)->lsei_values); + print_whsp(ss); + } + } + + return 0; +} + char * -ldap_syntax2str( const LDAP_SYNTAX * syn ) +ldap_syntax2str( LDAPSyntax * syn ) +{ + struct berval bv; + if (ldap_syntax2bv( syn, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv ) { safe_string * ss; - char * retstring; ss = new_safe_string(256); if ( !ss ) return NULL; - print_literal(ss,"("); + print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, syn->syn_oid); @@ -289,24 +394,37 @@ ldap_syntax2str( const LDAP_SYNTAX * syn ) } print_whsp(ss); - print_literal(ss,")"); - retstring = LDAP_STRDUP(safe_string_val(ss)); + print_extensions(ss, syn->syn_extensions); + + print_literal(ss,/*(*/ ")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; safe_string_free(ss); - return(retstring); + return(bv); } char * -ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr ) +ldap_matchingrule2str( LDAPMatchingRule * mr ) +{ + struct berval bv; + if (ldap_matchingrule2bv( mr, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv ) { safe_string * ss; - char * retstring; ss = new_safe_string(256); if ( !ss ) return NULL; - print_literal(ss,"("); + print_literal(ss,"(" /*)*/); print_whsp(ss); print_numericoid(ss, mr->mr_oid); @@ -322,7 +440,7 @@ ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr ) print_qdstring(ss,mr->mr_desc); } - if ( mr->mr_obsolete == LDAP_SCHEMA_YES ) { + if ( mr->mr_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } @@ -335,24 +453,96 @@ ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr ) } print_whsp(ss); - print_literal(ss,")"); - retstring = LDAP_STRDUP(safe_string_val(ss)); + print_extensions(ss, mr->mr_extensions); + + print_literal(ss,/*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + +char * +ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru ) +{ + struct berval bv; + if (ldap_matchingruleuse2bv( mru, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"(" /*)*/); + print_whsp(ss); + + print_numericoid(ss, mru->mru_oid); + print_whsp(ss); + + if ( mru->mru_names ) { + print_literal(ss,"NAME"); + print_qdescrs(ss,mru->mru_names); + } + + if ( mru->mru_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,mru->mru_desc); + } + + if ( mru->mru_obsolete ) { + print_literal(ss, "OBSOLETE"); + print_whsp(ss); + } + + if ( mru->mru_applies_oids ) { + print_literal(ss,"APPLIES"); + print_whsp(ss); + print_oids(ss, mru->mru_applies_oids); + print_whsp(ss); + } + + print_whsp(ss); + + print_extensions(ss, mru->mru_extensions); + + print_literal(ss,/*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; safe_string_free(ss); - return(retstring); + return(bv); } char * -ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc ) +ldap_objectclass2str( LDAPObjectClass * oc ) +{ + struct berval bv; + if (ldap_objectclass2bv( oc, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv ) { safe_string * ss; - char * retstring; ss = new_safe_string(256); if ( !ss ) return NULL; - print_literal(ss,"("); + print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, oc->oc_oid); @@ -368,7 +558,7 @@ ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc ) print_qdstring(ss,oc->oc_desc); } - if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) { + if ( oc->oc_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } @@ -411,24 +601,249 @@ ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc ) } print_whsp(ss); - print_literal(ss,")"); - retstring = LDAP_STRDUP(safe_string_val(ss)); + print_extensions(ss, oc->oc_extensions); + + print_literal(ss, /*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + +char * +ldap_contentrule2str( LDAPContentRule * cr ) +{ + struct berval bv; + if (ldap_contentrule2bv( cr, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"("/*)*/); + print_whsp(ss); + + print_numericoid(ss, cr->cr_oid); + print_whsp(ss); + + if ( cr->cr_names ) { + print_literal(ss,"NAME"); + print_qdescrs(ss,cr->cr_names); + } + + if ( cr->cr_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,cr->cr_desc); + } + + if ( cr->cr_obsolete ) { + print_literal(ss, "OBSOLETE"); + print_whsp(ss); + } + + if ( cr->cr_oc_oids_aux ) { + print_literal(ss,"AUX"); + print_whsp(ss); + print_oids(ss,cr->cr_oc_oids_aux); + print_whsp(ss); + } + + if ( cr->cr_at_oids_must ) { + print_literal(ss,"MUST"); + print_whsp(ss); + print_oids(ss,cr->cr_at_oids_must); + print_whsp(ss); + } + + if ( cr->cr_at_oids_may ) { + print_literal(ss,"MAY"); + print_whsp(ss); + print_oids(ss,cr->cr_at_oids_may); + print_whsp(ss); + } + + if ( cr->cr_at_oids_not ) { + print_literal(ss,"NOT"); + print_whsp(ss); + print_oids(ss,cr->cr_at_oids_not); + print_whsp(ss); + } + + print_whsp(ss); + print_extensions(ss, cr->cr_extensions); + + print_literal(ss, /*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + +char * +ldap_structurerule2str( LDAPStructureRule * sr ) +{ + struct berval bv; + if (ldap_structurerule2bv( sr, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_structurerule2bv( LDAPStructureRule * sr, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"("/*)*/); + print_whsp(ss); + + print_ruleid(ss, sr->sr_ruleid); + print_whsp(ss); + + if ( sr->sr_names ) { + print_literal(ss,"NAME"); + print_qdescrs(ss,sr->sr_names); + } + + if ( sr->sr_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,sr->sr_desc); + } + + if ( sr->sr_obsolete ) { + print_literal(ss, "OBSOLETE"); + print_whsp(ss); + } + + print_literal(ss,"FORM"); + print_whsp(ss); + print_woid(ss,sr->sr_nameform); + print_whsp(ss); + + if ( sr->sr_nsup_ruleids ) { + print_literal(ss,"SUP"); + print_whsp(ss); + print_ruleids(ss,sr->sr_nsup_ruleids,sr->sr_sup_ruleids); + print_whsp(ss); + } + + print_whsp(ss); + print_extensions(ss, sr->sr_extensions); + + print_literal(ss, /*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); +} + + +char * +ldap_nameform2str( LDAPNameForm * nf ) +{ + struct berval bv; + if (ldap_nameform2bv( nf, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_nameform2bv( LDAPNameForm * nf, struct berval *bv ) +{ + safe_string * ss; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"("/*)*/); + print_whsp(ss); + + print_numericoid(ss, nf->nf_oid); + print_whsp(ss); + + if ( nf->nf_names ) { + print_literal(ss,"NAME"); + print_qdescrs(ss,nf->nf_names); + } + + if ( nf->nf_desc ) { + print_literal(ss,"DESC"); + print_qdstring(ss,nf->nf_desc); + } + + if ( nf->nf_obsolete ) { + print_literal(ss, "OBSOLETE"); + print_whsp(ss); + } + + print_literal(ss,"OC"); + print_whsp(ss); + print_woid(ss,nf->nf_objectclass); + print_whsp(ss); + + print_literal(ss,"MUST"); + print_whsp(ss); + print_oids(ss,nf->nf_at_oids_must); + print_whsp(ss); + + + if ( nf->nf_at_oids_may ) { + print_literal(ss,"MAY"); + print_whsp(ss); + print_oids(ss,nf->nf_at_oids_may); + print_whsp(ss); + } + + print_whsp(ss); + print_extensions(ss, nf->nf_extensions); + + print_literal(ss, /*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; safe_string_free(ss); - return(retstring); + return(bv); } char * -ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at ) +ldap_attributetype2str( LDAPAttributeType * at ) +{ + struct berval bv; + if (ldap_attributetype2bv( at, &bv )) + return(bv.bv_val); + else + return NULL; +} + +struct berval * +ldap_attributetype2bv( LDAPAttributeType * at, struct berval *bv ) { safe_string * ss; - char * retstring; ss = new_safe_string(256); if ( !ss ) return NULL; - print_literal(ss,"("); + print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, at->at_oid); @@ -444,7 +859,7 @@ ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at ) print_qdstring(ss,at->at_desc); } - if ( at->at_obsolete == LDAP_SCHEMA_YES ) { + if ( at->at_obsolete ) { print_literal(ss, "OBSOLETE"); print_whsp(ss); } @@ -511,11 +926,15 @@ ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at ) } print_whsp(ss); - print_literal(ss,")"); - retstring = LDAP_STRDUP(safe_string_val(ss)); - safe_string_free(ss); - return(retstring); + print_extensions(ss, at->at_extensions); + + print_literal(ss,/*(*/")"); + + bv->bv_val = safe_strdup(ss); + bv->bv_len = ss->pos; + safe_string_free(ss); + return(bv); } /* @@ -540,26 +959,23 @@ ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at ) * interpretation of the specs). */ -#define TK_NOENDQUOTE -2 -#define TK_OUTOFMEM -1 -#define TK_EOS 0 -#define TK_UNEXPCHAR 1 -#define TK_BAREWORD 2 -#define TK_QDSTRING 3 -#define TK_LEFTPAREN 4 -#define TK_RIGHTPAREN 5 -#define TK_DOLLAR 6 -#define TK_QDESCR TK_QDSTRING - -struct token { - int type; - char *sval; -}; - -static int -get_token(const char ** sp, char ** token_val) +typedef enum tk_t { + TK_NOENDQUOTE = -2, + TK_OUTOFMEM = -1, + TK_EOS = 0, + TK_UNEXPCHAR = 1, + TK_BAREWORD = 2, + TK_QDSTRING = 3, + TK_LEFTPAREN = 4, + TK_RIGHTPAREN = 5, + TK_DOLLAR = 6, + TK_QDESCR = TK_QDSTRING +} tk_t; + +static tk_t +get_token( const char ** sp, char ** token_val ) { - int kind; + tk_t kind; const char * p; const char * q; char * res; @@ -606,11 +1022,14 @@ get_token(const char ** sp, char ** token_val) default: kind = TK_BAREWORD; p = *sp; - while ( !isspace(**sp) && + while ( !LDAP_SPACE(**sp) && **sp != '(' && **sp != ')' && **sp != '$' && **sp != '\'' && + /* for suggested minimum upper bound on the number + * of characters (RFC 4517) */ + **sp != '{' && **sp != '\0' ) (*sp)++; q = *sp; @@ -634,7 +1053,7 @@ get_token(const char ** sp, char ** token_val) static void parse_whsp(const char **sp) { - while (isspace(**sp)) + while (LDAP_SPACE(**sp)) (*sp)++; } @@ -647,23 +1066,23 @@ parse_whsp(const char **sp) */ /* Parse a sequence of dot-separated decimal strings */ -static char * -parse_numericoid(const char **sp, int *code, const int allow_quoted) +char * +ldap_int_parse_numericoid(const char **sp, int *code, const int flags) { - char * res; + char * res = NULL; const char * start = *sp; int len; int quoted = 0; /* Netscape puts the SYNTAX value in quotes (incorrectly) */ - if ( allow_quoted && **sp == '\'' ) { + if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) { quoted = 1; (*sp)++; start++; } /* Each iteration of this loop gets one decimal string */ while (**sp) { - if ( !isdigit(**sp) ) { + if ( !LDAP_DIGIT(**sp) ) { /* * Initial char is not a digit or char after dot is * not a digit @@ -672,7 +1091,7 @@ parse_numericoid(const char **sp, int *code, const int allow_quoted) return NULL; } (*sp)++; - while ( isdigit(**sp) ) + while ( LDAP_DIGIT(**sp) ) (*sp)++; if ( **sp != '.' ) break; @@ -681,32 +1100,57 @@ parse_numericoid(const char **sp, int *code, const int allow_quoted) } /* Now *sp points at the char past the numericoid. Perfect. */ len = *sp - start; - res = LDAP_MALLOC(len+1); - if (!res) { - *code = LDAP_SCHERR_OUTOFMEM; - return(NULL); - } - strncpy(res,start,len); - res[len] = '\0'; - if ( allow_quoted && quoted ) { + if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) { if ( **sp == '\'' ) { (*sp)++; } else { *code = LDAP_SCHERR_UNEXPTOKEN; - LDAP_FREE(res); return NULL; } } + if (flags & LDAP_SCHEMA_SKIP) { + res = (char *)start; + } else { + res = LDAP_MALLOC(len+1); + if (!res) { + *code = LDAP_SCHERR_OUTOFMEM; + return(NULL); + } + strncpy(res,start,len); + res[len] = '\0'; + } return(res); } +/* Parse a sequence of dot-separated decimal strings */ +int +ldap_int_parse_ruleid(const char **sp, int *code, const int flags, int *ruleid) +{ + *ruleid=0; + + if ( !LDAP_DIGIT(**sp) ) { + *code = LDAP_SCHERR_NODIGIT; + return -1; + } + *ruleid = (**sp) - '0'; + (*sp)++; + + while ( LDAP_DIGIT(**sp) ) { + *ruleid *= 10; + *ruleid += (**sp) - '0'; + (*sp)++; + } + + return 0; +} + /* Parse a qdescr or a list of them enclosed in () */ static char ** parse_qdescrs(const char **sp, int *code) { char ** res; char ** res1; - int kind; + tk_t kind; char * sval; int size; int pos; @@ -739,8 +1183,8 @@ parse_qdescrs(const char **sp, int *code) } res = res1; } - res[pos] = sval; - pos++; + res[pos++] = sval; + res[pos] = NULL; parse_whsp(sp); } else { LDAP_VFREE(res); @@ -749,7 +1193,6 @@ parse_qdescrs(const char **sp, int *code) return(NULL); } } - res[pos] = NULL; parse_whsp(sp); return(res); } else if ( kind == TK_QDESCR ) { @@ -774,7 +1217,7 @@ static char * parse_woid(const char **sp, int *code) { char * sval; - int kind; + tk_t kind; parse_whsp(sp); kind = get_token(sp, &sval); @@ -789,10 +1232,13 @@ parse_woid(const char **sp, int *code) /* Parse a noidlen */ static char * -parse_noidlen(const char **sp, int *code, int *len, int allow_quoted) +parse_noidlen(const char **sp, int *code, int *len, int flags) { char * sval; + const char *savepos; int quoted = 0; + int allow_quoted = ( flags & LDAP_SCHEMA_ALLOW_QUOTED ); + int allow_oidmacro = ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ); *len = 0; /* Netscape puts the SYNTAX value in quotes (incorrectly) */ @@ -800,16 +1246,29 @@ parse_noidlen(const char **sp, int *code, int *len, int allow_quoted) quoted = 1; (*sp)++; } - sval = parse_numericoid(sp, code, 0); + savepos = *sp; + sval = ldap_int_parse_numericoid(sp, code, 0); if ( !sval ) { - return NULL; + if ( allow_oidmacro + && *sp == savepos + && *code == LDAP_SCHERR_NODIGIT ) + { + if ( get_token(sp, &sval) != TK_BAREWORD ) { + if ( sval != NULL ) { + LDAP_FREE(sval); + } + return NULL; + } + } else { + return NULL; + } } - if ( **sp == '{' ) { + if ( **sp == '{' /*}*/ ) { (*sp)++; *len = atoi(*sp); - while ( isdigit(**sp) ) + while ( LDAP_DIGIT(**sp) ) (*sp)++; - if ( **sp != '}' ) { + if ( **sp != /*{*/ '}' ) { *code = LDAP_SCHERR_UNEXPTOKEN; LDAP_FREE(sval); return NULL; @@ -841,7 +1300,7 @@ parse_oids(const char **sp, int *code, const int allow_quoted) { char ** res; char ** res1; - int kind; + tk_t kind; char * sval; int size; int pos; @@ -867,8 +1326,13 @@ parse_oids(const char **sp, int *code, const int allow_quoted) kind = get_token(sp,&sval); if ( kind == TK_BAREWORD || ( allow_quoted && kind == TK_QDSTRING ) ) { - res[pos] = sval; - pos++; + res[pos++] = sval; + res[pos] = NULL; + } else if ( kind == TK_RIGHTPAREN ) { + /* FIXME: be liberal in what we accept... */ + parse_whsp(sp); + LDAP_FREE(res); + return NULL; } else { *code = LDAP_SCHERR_UNEXPTOKEN; LDAP_FREE(sval); @@ -897,8 +1361,8 @@ parse_oids(const char **sp, int *code, const int allow_quoted) } res = res1; } - res[pos] = sval; - pos++; + res[pos++] = sval; + res[pos] = NULL; } else { *code = LDAP_SCHERR_UNEXPTOKEN; LDAP_FREE(sval); @@ -913,7 +1377,6 @@ parse_oids(const char **sp, int *code, const int allow_quoted) return NULL; } } - res[pos] = NULL; parse_whsp(sp); return(res); } else if ( kind == TK_BAREWORD || @@ -935,23 +1398,81 @@ parse_oids(const char **sp, int *code, const int allow_quoted) } } +static int +add_extension(LDAPSchemaExtensionItem ***extensions, + char * name, char ** values) +{ + int n; + LDAPSchemaExtensionItem **tmp, *ext; + + ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem)); + if ( !ext ) + return 1; + ext->lsei_name = name; + ext->lsei_values = values; + + if ( !*extensions ) { + *extensions = + LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *)); + if ( !*extensions ) { + LDAP_FREE( ext ); + return 1; + } + n = 0; + } else { + for ( n=0; (*extensions)[n] != NULL; n++ ) + ; + tmp = LDAP_REALLOC(*extensions, + (n+2)*sizeof(LDAPSchemaExtensionItem *)); + if ( !tmp ) { + LDAP_FREE( ext ); + return 1; + } + *extensions = tmp; + } + (*extensions)[n] = ext; + (*extensions)[n+1] = NULL; + return 0; +} + +static void +free_extensions(LDAPSchemaExtensionItem **extensions) +{ + LDAPSchemaExtensionItem **ext; + + if ( extensions ) { + for ( ext = extensions; *ext != NULL; ext++ ) { + LDAP_FREE((*ext)->lsei_name); + LDAP_VFREE((*ext)->lsei_values); + LDAP_FREE(*ext); + } + LDAP_FREE(extensions); + } +} + void -ldap_syntax_free( LDAP_SYNTAX * syn ) +ldap_syntax_free( LDAPSyntax * syn ) { LDAP_FREE(syn->syn_oid); - LDAP_FREE(syn->syn_desc); + if (syn->syn_names) LDAP_VFREE(syn->syn_names); + if (syn->syn_desc) LDAP_FREE(syn->syn_desc); + free_extensions(syn->syn_extensions); LDAP_FREE(syn); } -LDAP_SYNTAX * -ldap_str2syntax( const char * s, int * code, const char ** errp ) +LDAPSyntax * +ldap_str2syntax( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags ) { - int kind; + tk_t kind; const char * ss = s; char * sval; + int seen_name = 0; int seen_desc = 0; - LDAP_SYNTAX * syn; - char ** ssdummy; + LDAPSyntax * syn; + char ** ext_vals; if ( !s ) { *code = LDAP_SCHERR_EMPTY; @@ -960,7 +1481,7 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) } *errp = s; - syn = LDAP_CALLOC(1,sizeof(LDAP_SYNTAX)); + syn = LDAP_CALLOC(1,sizeof(LDAPSyntax)); if ( !syn ) { *code = LDAP_SCHERR_OUTOFMEM; @@ -976,7 +1497,7 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) } parse_whsp(&ss); - syn->syn_oid = parse_numericoid(&ss,code,0); + syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0); if ( !syn->syn_oid ) { *errp = ss; ldap_syntax_free(syn); @@ -999,7 +1520,24 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) case TK_RIGHTPAREN: return syn; case TK_BAREWORD: - if ( !strcmp(sval,"DESC") ) { + if ( !strcasecmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_syntax_free(syn); + return(NULL); + } + seen_name = 1; + syn->syn_names = parse_qdescrs(&ss,code); + if ( !syn->syn_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_syntax_free(syn); + return NULL; + } + } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; @@ -1020,11 +1558,18 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) syn->syn_desc = sval; parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { - LDAP_FREE(sval); /* Should be parse_qdstrings */ - ssdummy = parse_qdescrs(&ss, code); - if ( !ssdummy ) { + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_syntax_free(syn); + return NULL; + } + if ( add_extension(&syn->syn_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; + LDAP_FREE(sval); ldap_syntax_free(syn); return NULL; } @@ -1047,28 +1592,31 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) } void -ldap_matchingrule_free( LDAP_MATCHING_RULE * mr ) +ldap_matchingrule_free( LDAPMatchingRule * mr ) { LDAP_FREE(mr->mr_oid); - LDAP_VFREE(mr->mr_names); - LDAP_FREE(mr->mr_desc); - LDAP_FREE(mr->mr_syntax_oid); + if (mr->mr_names) LDAP_VFREE(mr->mr_names); + if (mr->mr_desc) LDAP_FREE(mr->mr_desc); + if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid); + free_extensions(mr->mr_extensions); LDAP_FREE(mr); } -LDAP_MATCHING_RULE * -ldap_str2matchingrule( const char * s, int * code, const char ** errp ) +LDAPMatchingRule * +ldap_str2matchingrule( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags ) { - int kind; + tk_t kind; const char * ss = s; char * sval; - int be_liberal = 1; /* Future additional argument */ int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; int seen_syntax = 0; - LDAP_MATCHING_RULE * mr; - char ** ssdummy; + LDAPMatchingRule * mr; + char ** ext_vals; const char * savepos; if ( !s ) { @@ -1078,7 +1626,7 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) } *errp = s; - mr = LDAP_CALLOC(1,sizeof(LDAP_MATCHING_RULE)); + mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule)); if ( !mr ) { *code = LDAP_SCHERR_OUTOFMEM; @@ -1095,18 +1643,18 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) parse_whsp(&ss); savepos = ss; - mr->mr_oid = parse_numericoid(&ss,code,be_liberal); + mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags); if ( !mr->mr_oid ) { - if ( be_liberal ) { + if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) { /* Backtracking */ ss = savepos; kind = get_token(&ss,&sval); if ( kind == TK_BAREWORD ) { - if ( !strcmp(sval, "NAME") || - !strcmp(sval, "DESC") || - !strcmp(sval, "OBSOLETE") || - !strcmp(sval, "SYNTAX") || - !strncmp(sval, "X-", 2) ) { + if ( !strcasecmp(sval, "NAME") || + !strcasecmp(sval, "DESC") || + !strcasecmp(sval, "OBSOLETE") || + !strcasecmp(sval, "SYNTAX") || + !strncasecmp(sval, "X-", 2) ) { /* Missing OID, backtrack */ ss = savepos; } else { @@ -1135,9 +1683,14 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) ldap_matchingrule_free(mr); return NULL; case TK_RIGHTPAREN: + if( !seen_syntax ) { + *code = LDAP_SCHERR_MISSING; + ldap_matchingrule_free(mr); + return NULL; + } return mr; case TK_BAREWORD: - if ( !strcmp(sval,"NAME") ) { + if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; @@ -1154,7 +1707,7 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) ldap_matchingrule_free(mr); return NULL; } - } else if ( !strcmp(sval,"DESC") ) { + } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; @@ -1174,7 +1727,7 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) } mr->mr_desc = sval; parse_whsp(&ss); - } else if ( !strcmp(sval,"OBSOLETE") ) { + } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; @@ -1185,7 +1738,7 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) seen_obsolete = 1; mr->mr_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); - } else if ( !strcmp(sval,"SYNTAX") ) { + } else if ( !strcasecmp(sval,"SYNTAX") ) { LDAP_FREE(sval); if ( seen_syntax ) { *code = LDAP_SCHERR_DUPOPT; @@ -1196,7 +1749,7 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) seen_syntax = 1; parse_whsp(&ss); mr->mr_syntax_oid = - parse_numericoid(&ss,code,be_liberal); + ldap_int_parse_numericoid(&ss,code,flags); if ( !mr->mr_syntax_oid ) { *errp = ss; ldap_matchingrule_free(mr); @@ -1204,11 +1757,18 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) } parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { - LDAP_FREE(sval); /* Should be parse_qdstrings */ - ssdummy = parse_qdescrs(&ss, code); - if ( !ssdummy ) { + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_matchingrule_free(mr); + return NULL; + } + if ( add_extension(&mr->mr_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; + LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } @@ -1231,26 +1791,227 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) } void -ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at) +ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru ) +{ + LDAP_FREE(mru->mru_oid); + if (mru->mru_names) LDAP_VFREE(mru->mru_names); + if (mru->mru_desc) LDAP_FREE(mru->mru_desc); + if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids); + free_extensions(mru->mru_extensions); + LDAP_FREE(mru); +} + +LDAPMatchingRuleUse * +ldap_str2matchingruleuse( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags ) +{ + tk_t kind; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_applies = 0; + LDAPMatchingRuleUse * mru; + char ** ext_vals; + const char * savepos; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse)); + + if ( !mru ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + + parse_whsp(&ss); + savepos = ss; + mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags); + if ( !mru->mru_oid ) { + if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) { + /* Backtracking */ + ss = savepos; + kind = get_token(&ss,&sval); + if ( kind == TK_BAREWORD ) { + if ( !strcasecmp(sval, "NAME") || + !strcasecmp(sval, "DESC") || + !strcasecmp(sval, "OBSOLETE") || + !strcasecmp(sval, "APPLIES") || + !strncasecmp(sval, "X-", 2) ) { + /* Missing OID, backtrack */ + ss = savepos; + } else { + /* Non-numerical OID, ignore */ + } + } + LDAP_FREE(sval); + } else { + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + } + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal and accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + case TK_RIGHTPAREN: + if( !seen_applies ) { + *code = LDAP_SCHERR_MISSING; + ldap_matchingruleuse_free(mru); + return NULL; + } + return mru; + case TK_BAREWORD: + if ( !strcasecmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingruleuse_free(mru); + return(NULL); + } + seen_name = 1; + mru->mru_names = parse_qdescrs(&ss,code); + if ( !mru->mru_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + } + } else if ( !strcasecmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingruleuse_free(mru); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + mru->mru_desc = sval; + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); + if ( seen_obsolete ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingruleuse_free(mru); + return(NULL); + } + seen_obsolete = 1; + mru->mru_obsolete = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"APPLIES") ) { + LDAP_FREE(sval); + if ( seen_applies ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_matchingruleuse_free(mru); + return(NULL); + } + seen_applies = 1; + mru->mru_applies_oids = parse_oids(&ss, + code, + flags); + if ( !mru->mru_applies_oids && *code != LDAP_SUCCESS ) { + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + } + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_matchingruleuse_free(mru); + return NULL; + } + if ( add_extension(&mru->mru_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_matchingruleuse_free(mru); + return NULL; + } + } +} + +void +ldap_attributetype_free(LDAPAttributeType * at) { LDAP_FREE(at->at_oid); - LDAP_VFREE(at->at_names); - LDAP_FREE(at->at_desc); - LDAP_FREE(at->at_sup_oid); - LDAP_FREE(at->at_equality_oid); - LDAP_FREE(at->at_ordering_oid); - LDAP_FREE(at->at_substr_oid); - LDAP_FREE(at->at_syntax_oid); + if (at->at_names) LDAP_VFREE(at->at_names); + if (at->at_desc) LDAP_FREE(at->at_desc); + if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid); + if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid); + if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid); + if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid); + if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid); + free_extensions(at->at_extensions); LDAP_FREE(at); } -LDAP_ATTRIBUTE_TYPE * -ldap_str2attributetype( const char * s, int * code, const char ** errp ) +LDAPAttributeType * +ldap_str2attributetype( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags ) { - int kind; + tk_t kind; const char * ss = s; char * sval; - int be_liberal = 1; /* Future additional argument */ int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; @@ -1260,8 +2021,8 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) int seen_substr = 0; int seen_syntax = 0; int seen_usage = 0; - LDAP_ATTRIBUTE_TYPE * at; - char ** ssdummy; + LDAPAttributeType * at; + char ** ext_vals; const char * savepos; if ( !s ) { @@ -1271,7 +2032,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) } *errp = s; - at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE)); + at = LDAP_CALLOC(1,sizeof(LDAPAttributeType)); if ( !at ) { *code = LDAP_SCHERR_OUTOFMEM; @@ -1295,30 +2056,40 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) */ parse_whsp(&ss); savepos = ss; - at->at_oid = parse_numericoid(&ss,code,0); + at->at_oid = ldap_int_parse_numericoid(&ss,code,0); if ( !at->at_oid ) { - if ( be_liberal ) { + if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID + | LDAP_SCHEMA_ALLOW_OID_MACRO ) ) + && (ss == savepos) ) + { /* Backtracking */ ss = savepos; kind = get_token(&ss,&sval); if ( kind == TK_BAREWORD ) { - if ( !strcmp(sval, "NAME") || - !strcmp(sval, "DESC") || - !strcmp(sval, "OBSOLETE") || - !strcmp(sval, "SUP") || - !strcmp(sval, "EQUALITY") || - !strcmp(sval, "ORDERING") || - !strcmp(sval, "SUBSTR") || - !strcmp(sval, "SYNTAX") || - !strcmp(sval, "SINGLE-VALUE") || - !strcmp(sval, "COLLECTIVE") || - !strcmp(sval, "NO-USER-MODIFICATION") || - !strcmp(sval, "USAGE") || - !strncmp(sval, "X-", 2) ) { + if ( !strcasecmp(sval, "NAME") || + !strcasecmp(sval, "DESC") || + !strcasecmp(sval, "OBSOLETE") || + !strcasecmp(sval, "SUP") || + !strcasecmp(sval, "EQUALITY") || + !strcasecmp(sval, "ORDERING") || + !strcasecmp(sval, "SUBSTR") || + !strcasecmp(sval, "SYNTAX") || + !strcasecmp(sval, "SINGLE-VALUE") || + !strcasecmp(sval, "COLLECTIVE") || + !strcasecmp(sval, "NO-USER-MODIFICATION") || + !strcasecmp(sval, "USAGE") || + !strncasecmp(sval, "X-", 2) ) + { /* Missing OID, backtrack */ ss = savepos; - } else { - /* Non-numerical OID, ignore */ + } else if ( flags + & LDAP_SCHEMA_ALLOW_OID_MACRO) + { + /* Non-numerical OID ... */ + int len = ss-savepos; + at->at_oid = LDAP_MALLOC(len+1); + strncpy(at->at_oid, savepos, len); + at->at_oid[len] = 0; } } LDAP_FREE(sval); @@ -1345,7 +2116,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) case TK_RIGHTPAREN: return at; case TK_BAREWORD: - if ( !strcmp(sval,"NAME") ) { + if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; @@ -1362,7 +2133,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) ldap_attributetype_free(at); return NULL; } - } else if ( !strcmp(sval,"DESC") ) { + } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; @@ -1382,7 +2153,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) } at->at_desc = sval; parse_whsp(&ss); - } else if ( !strcmp(sval,"OBSOLETE") ) { + } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; @@ -1393,7 +2164,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) seen_obsolete = 1; at->at_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); - } else if ( !strcmp(sval,"SUP") ) { + } else if ( !strcasecmp(sval,"SUP") ) { LDAP_FREE(sval); if ( seen_sup ) { *code = LDAP_SCHERR_DUPOPT; @@ -1408,7 +2179,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) ldap_attributetype_free(at); return NULL; } - } else if ( !strcmp(sval,"EQUALITY") ) { + } else if ( !strcasecmp(sval,"EQUALITY") ) { LDAP_FREE(sval); if ( seen_equality ) { *code = LDAP_SCHERR_DUPOPT; @@ -1423,7 +2194,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) ldap_attributetype_free(at); return NULL; } - } else if ( !strcmp(sval,"ORDERING") ) { + } else if ( !strcasecmp(sval,"ORDERING") ) { LDAP_FREE(sval); if ( seen_ordering ) { *code = LDAP_SCHERR_DUPOPT; @@ -1438,7 +2209,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) ldap_attributetype_free(at); return NULL; } - } else if ( !strcmp(sval,"SUBSTR") ) { + } else if ( !strcasecmp(sval,"SUBSTR") ) { LDAP_FREE(sval); if ( seen_substr ) { *code = LDAP_SCHERR_DUPOPT; @@ -1453,7 +2224,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) ldap_attributetype_free(at); return NULL; } - } else if ( !strcmp(sval,"SYNTAX") ) { + } else if ( !strcasecmp(sval,"SYNTAX") ) { LDAP_FREE(sval); if ( seen_syntax ) { *code = LDAP_SCHERR_DUPOPT; @@ -1463,18 +2234,41 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) } seen_syntax = 1; parse_whsp(&ss); + savepos = ss; at->at_syntax_oid = parse_noidlen(&ss, code, &at->at_syntax_len, - be_liberal); + flags); if ( !at->at_syntax_oid ) { + if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) { + kind = get_token(&ss,&sval); + if (kind == TK_BAREWORD) + { + char *sp = strchr(sval, '{'); + at->at_syntax_oid = sval; + if (sp) + { + *sp++ = 0; + at->at_syntax_len = atoi(sp); + while ( LDAP_DIGIT(*sp) ) + sp++; + if ( *sp != '}' ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + } + } + } else { *errp = ss; ldap_attributetype_free(at); return NULL; + } } parse_whsp(&ss); - } else if ( !strcmp(sval,"SINGLE-VALUE") ) { + } else if ( !strcasecmp(sval,"SINGLE-VALUE") ) { LDAP_FREE(sval); if ( at->at_single_value ) { *code = LDAP_SCHERR_DUPOPT; @@ -1484,7 +2278,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) } at->at_single_value = LDAP_SCHEMA_YES; parse_whsp(&ss); - } else if ( !strcmp(sval,"COLLECTIVE") ) { + } else if ( !strcasecmp(sval,"COLLECTIVE") ) { LDAP_FREE(sval); if ( at->at_collective ) { *code = LDAP_SCHERR_DUPOPT; @@ -1494,7 +2288,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) } at->at_collective = LDAP_SCHEMA_YES; parse_whsp(&ss); - } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) { + } else if ( !strcasecmp(sval,"NO-USER-MODIFICATION") ) { LDAP_FREE(sval); if ( at->at_no_user_mod ) { *code = LDAP_SCHERR_DUPOPT; @@ -1504,7 +2298,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) } at->at_no_user_mod = LDAP_SCHEMA_YES; parse_whsp(&ss); - } else if ( !strcmp(sval,"USAGE") ) { + } else if ( !strcasecmp(sval,"USAGE") ) { LDAP_FREE(sval); if ( seen_usage ) { *code = LDAP_SCHERR_DUPOPT; @@ -1544,11 +2338,18 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) LDAP_FREE(sval); parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { - LDAP_FREE(sval); /* Should be parse_qdstrings */ - ssdummy = parse_qdescrs(&ss, code); - if ( !ssdummy ) { + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_attributetype_free(at); + return NULL; + } + if ( add_extension(&at->at_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; + LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } @@ -1571,24 +2372,27 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) } void -ldap_objectclass_free(LDAP_OBJECT_CLASS * oc) +ldap_objectclass_free(LDAPObjectClass * oc) { LDAP_FREE(oc->oc_oid); - LDAP_VFREE(oc->oc_names); - LDAP_FREE(oc->oc_desc); - LDAP_VFREE(oc->oc_sup_oids); - LDAP_VFREE(oc->oc_at_oids_must); - LDAP_VFREE(oc->oc_at_oids_may); + if (oc->oc_names) LDAP_VFREE(oc->oc_names); + if (oc->oc_desc) LDAP_FREE(oc->oc_desc); + if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids); + if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must); + if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may); + free_extensions(oc->oc_extensions); LDAP_FREE(oc); } -LDAP_OBJECT_CLASS * -ldap_str2objectclass( const char * s, int * code, const char ** errp ) +LDAPObjectClass * +ldap_str2objectclass( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags ) { - int kind; + tk_t kind; const char * ss = s; char * sval; - int be_liberal = 1; /* Future additional argument */ int seen_name = 0; int seen_desc = 0; int seen_obsolete = 0; @@ -1596,8 +2400,8 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) int seen_kind = 0; int seen_must = 0; int seen_may = 0; - LDAP_OBJECT_CLASS * oc; - char ** ssdummy; + LDAPObjectClass * oc; + char ** ext_vals; const char * savepos; if ( !s ) { @@ -1607,12 +2411,13 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) } *errp = s; - oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS)); + oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass)); if ( !oc ) { *code = LDAP_SCHERR_OUTOFMEM; return NULL; } + oc->oc_kind = LDAP_SCHEMA_STRUCTURAL; kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { @@ -1631,29 +2436,36 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) */ parse_whsp(&ss); savepos = ss; - oc->oc_oid = parse_numericoid(&ss,code,0); + oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0); if ( !oc->oc_oid ) { - if ( be_liberal ) { + if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) { /* Backtracking */ ss = savepos; kind = get_token(&ss,&sval); if ( kind == TK_BAREWORD ) { - if ( !strcmp(sval, "NAME") || - !strcmp(sval, "DESC") || - !strcmp(sval, "OBSOLETE") || - !strcmp(sval, "SUP") || - !strcmp(sval, "ABSTRACT") || - !strcmp(sval, "STRUCTURAL") || - !strcmp(sval, "AUXILIARY") || - !strcmp(sval, "MUST") || - !strncmp(sval, "X-", 2) ) { + if ( !strcasecmp(sval, "NAME") || + !strcasecmp(sval, "DESC") || + !strcasecmp(sval, "OBSOLETE") || + !strcasecmp(sval, "SUP") || + !strcasecmp(sval, "ABSTRACT") || + !strcasecmp(sval, "STRUCTURAL") || + !strcasecmp(sval, "AUXILIARY") || + !strcasecmp(sval, "MUST") || + !strcasecmp(sval, "MAY") || + !strncasecmp(sval, "X-", 2) ) { /* Missing OID, backtrack */ ss = savepos; - } else { + } else if ( flags & + LDAP_SCHEMA_ALLOW_OID_MACRO ) { /* Non-numerical OID, ignore */ + int len = ss-savepos; + oc->oc_oid = LDAP_MALLOC(len+1); + strncpy(oc->oc_oid, savepos, len); + oc->oc_oid[len] = 0; } } LDAP_FREE(sval); + *code = 0; } else { *errp = ss; ldap_objectclass_free(oc); @@ -1677,7 +2489,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) case TK_RIGHTPAREN: return oc; case TK_BAREWORD: - if ( !strcmp(sval,"NAME") ) { + if ( !strcasecmp(sval,"NAME") ) { LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; @@ -1694,7 +2506,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) ldap_objectclass_free(oc); return NULL; } - } else if ( !strcmp(sval,"DESC") ) { + } else if ( !strcasecmp(sval,"DESC") ) { LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; @@ -1714,7 +2526,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) } oc->oc_desc = sval; parse_whsp(&ss); - } else if ( !strcmp(sval,"OBSOLETE") ) { + } else if ( !strcasecmp(sval,"OBSOLETE") ) { LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; @@ -1725,7 +2537,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) seen_obsolete = 1; oc->oc_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); - } else if ( !strcmp(sval,"SUP") ) { + } else if ( !strcasecmp(sval,"SUP") ) { LDAP_FREE(sval); if ( seen_sup ) { *code = LDAP_SCHERR_DUPOPT; @@ -1736,13 +2548,14 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) seen_sup = 1; oc->oc_sup_oids = parse_oids(&ss, code, - be_liberal); - if ( !oc->oc_sup_oids ) { + flags); + if ( !oc->oc_sup_oids && *code != LDAP_SUCCESS ) { *errp = ss; ldap_objectclass_free(oc); return NULL; } - } else if ( !strcmp(sval,"ABSTRACT") ) { + *code = 0; + } else if ( !strcasecmp(sval,"ABSTRACT") ) { LDAP_FREE(sval); if ( seen_kind ) { *code = LDAP_SCHERR_DUPOPT; @@ -1753,7 +2566,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) seen_kind = 1; oc->oc_kind = LDAP_SCHEMA_ABSTRACT; parse_whsp(&ss); - } else if ( !strcmp(sval,"STRUCTURAL") ) { + } else if ( !strcasecmp(sval,"STRUCTURAL") ) { LDAP_FREE(sval); if ( seen_kind ) { *code = LDAP_SCHERR_DUPOPT; @@ -1764,7 +2577,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) seen_kind = 1; oc->oc_kind = LDAP_SCHEMA_STRUCTURAL; parse_whsp(&ss); - } else if ( !strcmp(sval,"AUXILIARY") ) { + } else if ( !strcasecmp(sval,"AUXILIARY") ) { LDAP_FREE(sval); if ( seen_kind ) { *code = LDAP_SCHERR_DUPOPT; @@ -1775,7 +2588,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) seen_kind = 1; oc->oc_kind = LDAP_SCHEMA_AUXILIARY; parse_whsp(&ss); - } else if ( !strcmp(sval,"MUST") ) { + } else if ( !strcasecmp(sval,"MUST") ) { LDAP_FREE(sval); if ( seen_must ) { *code = LDAP_SCHERR_DUPOPT; @@ -1785,13 +2598,14 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) } seen_must = 1; oc->oc_at_oids_must = parse_oids(&ss,code,0); - if ( !oc->oc_at_oids_must ) { + if ( !oc->oc_at_oids_must && *code != LDAP_SUCCESS ) { *errp = ss; ldap_objectclass_free(oc); return NULL; } + *code = 0; parse_whsp(&ss); - } else if ( !strcmp(sval,"MAY") ) { + } else if ( !strcasecmp(sval,"MAY") ) { LDAP_FREE(sval); if ( seen_may ) { *code = LDAP_SCHERR_DUPOPT; @@ -1801,18 +2615,27 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) } seen_may = 1; oc->oc_at_oids_may = parse_oids(&ss,code,0); - if ( !oc->oc_at_oids_may ) { + if ( !oc->oc_at_oids_may && *code != LDAP_SUCCESS ) { *errp = ss; ldap_objectclass_free(oc); return NULL; } + *code = 0; parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { - LDAP_FREE(sval); /* Should be parse_qdstrings */ - ssdummy = parse_qdescrs(&ss, code); - if ( !ssdummy ) { + ext_vals = parse_qdescrs(&ss, code); + *code = 0; + if ( !ext_vals ) { + *errp = ss; + ldap_objectclass_free(oc); + return NULL; + } + if ( add_extension(&oc->oc_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; *errp = ss; + LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } @@ -1834,26 +2657,687 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) } } +void +ldap_contentrule_free(LDAPContentRule * cr) +{ + LDAP_FREE(cr->cr_oid); + if (cr->cr_names) LDAP_VFREE(cr->cr_names); + if (cr->cr_desc) LDAP_FREE(cr->cr_desc); + if (cr->cr_oc_oids_aux) LDAP_VFREE(cr->cr_oc_oids_aux); + if (cr->cr_at_oids_must) LDAP_VFREE(cr->cr_at_oids_must); + if (cr->cr_at_oids_may) LDAP_VFREE(cr->cr_at_oids_may); + if (cr->cr_at_oids_not) LDAP_VFREE(cr->cr_at_oids_not); + free_extensions(cr->cr_extensions); + LDAP_FREE(cr); +} + +LDAPContentRule * +ldap_str2contentrule( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags ) +{ + tk_t kind; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_aux = 0; + int seen_must = 0; + int seen_may = 0; + int seen_not = 0; + LDAPContentRule * cr; + char ** ext_vals; + const char * savepos; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + cr = LDAP_CALLOC(1,sizeof(LDAPContentRule)); + + if ( !cr ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + + /* + * Definitions MUST begin with an OID in the numericoid format. + */ + parse_whsp(&ss); + savepos = ss; + cr->cr_oid = ldap_int_parse_numericoid(&ss,code,0); + if ( !cr->cr_oid ) { + if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) { + /* Backtracking */ + ss = savepos; + kind = get_token(&ss,&sval); + if ( kind == TK_BAREWORD ) { + if ( !strcasecmp(sval, "NAME") || + !strcasecmp(sval, "DESC") || + !strcasecmp(sval, "OBSOLETE") || + !strcasecmp(sval, "AUX") || + !strcasecmp(sval, "MUST") || + !strcasecmp(sval, "MAY") || + !strcasecmp(sval, "NOT") || + !strncasecmp(sval, "X-", 2) ) { + /* Missing OID, backtrack */ + ss = savepos; + } else if ( flags & + LDAP_SCHEMA_ALLOW_OID_MACRO ) { + /* Non-numerical OID, ignore */ + int len = ss-savepos; + cr->cr_oid = LDAP_MALLOC(len+1); + strncpy(cr->cr_oid, savepos, len); + cr->cr_oid[len] = 0; + } + } + LDAP_FREE(sval); + } else { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal an accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + case TK_RIGHTPAREN: + return cr; + case TK_BAREWORD: + if ( !strcasecmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_name = 1; + cr->cr_names = parse_qdescrs(&ss,code); + if ( !cr->cr_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + } else if ( !strcasecmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + cr->cr_desc = sval; + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); + if ( seen_obsolete ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_obsolete = 1; + cr->cr_obsolete = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"AUX") ) { + LDAP_FREE(sval); + if ( seen_aux ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_aux = 1; + cr->cr_oc_oids_aux = parse_oids(&ss,code,0); + if ( !cr->cr_oc_oids_aux ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"MUST") ) { + LDAP_FREE(sval); + if ( seen_must ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_must = 1; + cr->cr_at_oids_must = parse_oids(&ss,code,0); + if ( !cr->cr_at_oids_must && *code != LDAP_SUCCESS ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"MAY") ) { + LDAP_FREE(sval); + if ( seen_may ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_may = 1; + cr->cr_at_oids_may = parse_oids(&ss,code,0); + if ( !cr->cr_at_oids_may && *code != LDAP_SUCCESS ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"NOT") ) { + LDAP_FREE(sval); + if ( seen_not ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_contentrule_free(cr); + return(NULL); + } + seen_not = 1; + cr->cr_at_oids_not = parse_oids(&ss,code,0); + if ( !cr->cr_at_oids_not && *code != LDAP_SUCCESS ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + parse_whsp(&ss); + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_contentrule_free(cr); + return NULL; + } + if ( add_extension(&cr->cr_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_contentrule_free(cr); + return NULL; + } + } +} + +void +ldap_structurerule_free(LDAPStructureRule * sr) +{ + if (sr->sr_names) LDAP_VFREE(sr->sr_names); + if (sr->sr_desc) LDAP_FREE(sr->sr_desc); + if (sr->sr_nameform) LDAP_FREE(sr->sr_nameform); + if (sr->sr_sup_ruleids) LDAP_FREE(sr->sr_sup_ruleids); + free_extensions(sr->sr_extensions); + LDAP_FREE(sr); +} + +LDAPStructureRule * +ldap_str2structurerule( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags ) +{ + tk_t kind; + int ret; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_nameform = 0; + LDAPStructureRule * sr; + char ** ext_vals; + const char * savepos; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + sr = LDAP_CALLOC(1,sizeof(LDAPStructureRule)); + + if ( !sr ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); + ldap_structurerule_free(sr); + return NULL; + } + + /* + * Definitions MUST begin with a ruleid. + */ + parse_whsp(&ss); + savepos = ss; + ret = ldap_int_parse_ruleid(&ss,code,0,&sr->sr_ruleid); + if ( ret ) { + *errp = ss; + ldap_structurerule_free(sr); + return NULL; + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal an accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_structurerule_free(sr); + return NULL; + case TK_RIGHTPAREN: + if( !seen_nameform ) { + *code = LDAP_SCHERR_MISSING; + ldap_structurerule_free(sr); + return NULL; + } + return sr; + case TK_BAREWORD: + if ( !strcasecmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_structurerule_free(sr); + return(NULL); + } + seen_name = 1; + sr->sr_names = parse_qdescrs(&ss,code); + if ( !sr->sr_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_structurerule_free(sr); + return NULL; + } + } else if ( !strcasecmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_structurerule_free(sr); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_structurerule_free(sr); + return NULL; + } + sr->sr_desc = sval; + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); + if ( seen_obsolete ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_structurerule_free(sr); + return(NULL); + } + seen_obsolete = 1; + sr->sr_obsolete = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"FORM") ) { + LDAP_FREE(sval); + if ( seen_nameform ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_structurerule_free(sr); + return(NULL); + } + seen_nameform = 1; + sr->sr_nameform = parse_woid(&ss,code); + if ( !sr->sr_nameform ) { + *errp = ss; + ldap_structurerule_free(sr); + return NULL; + } + parse_whsp(&ss); + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_structurerule_free(sr); + return NULL; + } + if ( add_extension(&sr->sr_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_structurerule_free(sr); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_structurerule_free(sr); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_structurerule_free(sr); + return NULL; + } + } +} + +void +ldap_nameform_free(LDAPNameForm * nf) +{ + LDAP_FREE(nf->nf_oid); + if (nf->nf_names) LDAP_VFREE(nf->nf_names); + if (nf->nf_desc) LDAP_FREE(nf->nf_desc); + if (nf->nf_objectclass) LDAP_FREE(nf->nf_objectclass); + if (nf->nf_at_oids_must) LDAP_VFREE(nf->nf_at_oids_must); + if (nf->nf_at_oids_may) LDAP_VFREE(nf->nf_at_oids_may); + free_extensions(nf->nf_extensions); + LDAP_FREE(nf); +} + +LDAPNameForm * +ldap_str2nameform( LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags ) +{ + tk_t kind; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_class = 0; + int seen_must = 0; + int seen_may = 0; + LDAPNameForm * nf; + char ** ext_vals; + const char * savepos; + + if ( !s ) { + *code = LDAP_SCHERR_EMPTY; + *errp = ""; + return NULL; + } + + *errp = s; + nf = LDAP_CALLOC(1,sizeof(LDAPNameForm)); + + if ( !nf ) { + *code = LDAP_SCHERR_OUTOFMEM; + return NULL; + } + + kind = get_token(&ss,&sval); + if ( kind != TK_LEFTPAREN ) { + *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); + ldap_nameform_free(nf); + return NULL; + } + + /* + * Definitions MUST begin with an OID in the numericoid format. + * However, this routine is used by clients to parse the response + * from servers and very well known servers will provide an OID + * in the wrong format or even no OID at all. We do our best to + * extract info from those servers. + */ + parse_whsp(&ss); + savepos = ss; + nf->nf_oid = ldap_int_parse_numericoid(&ss,code,0); + if ( !nf->nf_oid ) { + *errp = ss; + ldap_nameform_free(nf); + return NULL; + } + parse_whsp(&ss); + + /* + * Beyond this point we will be liberal an accept the items + * in any order. + */ + while (1) { + kind = get_token(&ss,&sval); + switch (kind) { + case TK_EOS: + *code = LDAP_SCHERR_NORIGHTPAREN; + *errp = ss; + ldap_nameform_free(nf); + return NULL; + case TK_RIGHTPAREN: + if( !seen_class || !seen_must ) { + *code = LDAP_SCHERR_MISSING; + ldap_nameform_free(nf); + return NULL; + } + return nf; + case TK_BAREWORD: + if ( !strcasecmp(sval,"NAME") ) { + LDAP_FREE(sval); + if ( seen_name ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_nameform_free(nf); + return(NULL); + } + seen_name = 1; + nf->nf_names = parse_qdescrs(&ss,code); + if ( !nf->nf_names ) { + if ( *code != LDAP_SCHERR_OUTOFMEM ) + *code = LDAP_SCHERR_BADNAME; + *errp = ss; + ldap_nameform_free(nf); + return NULL; + } + } else if ( !strcasecmp(sval,"DESC") ) { + LDAP_FREE(sval); + if ( seen_desc ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_nameform_free(nf); + return(NULL); + } + seen_desc = 1; + parse_whsp(&ss); + kind = get_token(&ss,&sval); + if ( kind != TK_QDSTRING ) { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_nameform_free(nf); + return NULL; + } + nf->nf_desc = sval; + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); + if ( seen_obsolete ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_nameform_free(nf); + return(NULL); + } + seen_obsolete = 1; + nf->nf_obsolete = LDAP_SCHEMA_YES; + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"OC") ) { + LDAP_FREE(sval); + if ( seen_class ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_nameform_free(nf); + return(NULL); + } + seen_class = 1; + nf->nf_objectclass = parse_woid(&ss,code); + if ( !nf->nf_objectclass ) { + *errp = ss; + ldap_nameform_free(nf); + return NULL; + } + } else if ( !strcasecmp(sval,"MUST") ) { + LDAP_FREE(sval); + if ( seen_must ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_nameform_free(nf); + return(NULL); + } + seen_must = 1; + nf->nf_at_oids_must = parse_oids(&ss,code,0); + if ( !nf->nf_at_oids_must && *code != LDAP_SUCCESS ) { + *errp = ss; + ldap_nameform_free(nf); + return NULL; + } + parse_whsp(&ss); + } else if ( !strcasecmp(sval,"MAY") ) { + LDAP_FREE(sval); + if ( seen_may ) { + *code = LDAP_SCHERR_DUPOPT; + *errp = ss; + ldap_nameform_free(nf); + return(NULL); + } + seen_may = 1; + nf->nf_at_oids_may = parse_oids(&ss,code,0); + if ( !nf->nf_at_oids_may && *code != LDAP_SUCCESS ) { + *errp = ss; + ldap_nameform_free(nf); + return NULL; + } + parse_whsp(&ss); + } else if ( sval[0] == 'X' && sval[1] == '-' ) { + /* Should be parse_qdstrings */ + ext_vals = parse_qdescrs(&ss, code); + if ( !ext_vals ) { + *errp = ss; + ldap_nameform_free(nf); + return NULL; + } + if ( add_extension(&nf->nf_extensions, + sval, ext_vals) ) { + *code = LDAP_SCHERR_OUTOFMEM; + *errp = ss; + LDAP_FREE(sval); + ldap_nameform_free(nf); + return NULL; + } + } else { + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_nameform_free(nf); + return NULL; + } + break; + default: + *code = LDAP_SCHERR_UNEXPTOKEN; + *errp = ss; + LDAP_FREE(sval); + ldap_nameform_free(nf); + return NULL; + } + } +} + static char *const err2text[] = { - "", - "Out of memory", - "Unexpected token", - "Missing opening parenthesis", - "Missing closing parenthesis", - "Expecting digit", - "Expecting a name", - "Bad description", - "Bad superiors", - "Duplicate option", - "Unexpected end of data" + N_("Success"), + N_("Out of memory"), + N_("Unexpected token"), + N_("Missing opening parenthesis"), + N_("Missing closing parenthesis"), + N_("Expecting digit"), + N_("Expecting a name"), + N_("Bad description"), + N_("Bad superiors"), + N_("Duplicate option"), + N_("Unexpected end of data"), + N_("Missing required field"), + N_("Out of order field") }; char * ldap_scherr2str(int code) { - if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) { - return "Unknown error"; + if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) { + return _("Unknown error"); } else { - return err2text[code]; + return _(err2text[code]); } }