X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=libraries%2Flibldap%2Fschema.c;h=cf7a9923c47c807cfeae7a0a51dde41c51c3f5b0;hb=c1a257a83f3d8b9565238b5f9b8cad39a6194f63;hp=d5bc4e8bc404e8fb173be25deead14b687109bbc;hpb=669b8f4047c03d4583a44ed8287d0d5920d15373;p=openldap diff --git a/libraries/libldap/schema.c b/libraries/libldap/schema.c index d5bc4e8bc4..cf7a9923c4 100644 --- a/libraries/libldap/schema.c +++ b/libraries/libldap/schema.c @@ -1,7 +1,9 @@ +/* $OpenLDAP$ */ /* - * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved. + * Copyright 1999-2000 The OpenLDAP Foundation, All Rights Reserved. * COPYING RESTRICTIONS APPLY, see COPYRIGHT file - * + */ +/* * schema.c: parsing routines used by servers and clients to process * schema definitions */ @@ -11,7 +13,6 @@ #include #include -#include #include #include @@ -19,6 +20,43 @@ #include +static LDAP_CONST char * +choose_name( char *names[], LDAP_CONST char *fallback ) +{ + return( (names != NULL && names[0] != NULL) ? names[0] : fallback ); +} + +LDAP_CONST char * +ldap_syntax2name( LDAPSyntax * syn ) +{ + return( syn->syn_oid ); +} + +LDAP_CONST char * +ldap_matchingrule2name( LDAPMatchingRule * mr ) +{ + return( choose_name( mr->mr_names, mr->mr_oid ) ); +} + +LDAP_CONST char * +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( LDAPObjectClass * oc ) +{ + return( choose_name( oc->oc_names, oc->oc_oid ) ); +} + + /* * When pretty printing the entities we will be appending to a buffer. * Since checking for overflow, realloc'ing and checking if no error @@ -88,6 +126,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 */ @@ -98,7 +140,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; @@ -178,9 +220,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)); @@ -211,10 +253,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)); } @@ -234,8 +276,27 @@ print_noidlen(safe_string *ss, char *s, int l) return(ret); } +static int +print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions) +{ + LDAPSchemaExtensionItem **ext; + + if ( extensions ) { + print_whsp(ss); + for ( ext = extensions; *ext != NULL; ext++ ) { + print_literal(ss, (*ext)->lsei_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( const LDAPSyntax * syn ) { safe_string * ss; char * retstring; @@ -244,7 +305,7 @@ ldap_syntax2str( const LDAP_SYNTAX * syn ) if ( !ss ) return NULL; - print_literal(ss,"("); + print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, syn->syn_oid); @@ -256,7 +317,10 @@ ldap_syntax2str( const LDAP_SYNTAX * syn ) } print_whsp(ss); - print_literal(ss,")"); + + print_extensions(ss, syn->syn_extensions); + + print_literal(ss,/*(*/ ")"); retstring = LDAP_STRDUP(safe_string_val(ss)); safe_string_free(ss); @@ -264,7 +328,7 @@ ldap_syntax2str( const LDAP_SYNTAX * syn ) } char * -ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr ) +ldap_matchingrule2str( const LDAPMatchingRule * mr ) { safe_string * ss; char * retstring; @@ -273,7 +337,7 @@ ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr ) if ( !ss ) return NULL; - print_literal(ss,"("); + print_literal(ss,"(" /*)*/); print_whsp(ss); print_numericoid(ss, mr->mr_oid); @@ -302,7 +366,10 @@ ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr ) } print_whsp(ss); - print_literal(ss,")"); + + print_extensions(ss, mr->mr_extensions); + + print_literal(ss,/*(*/")"); retstring = LDAP_STRDUP(safe_string_val(ss)); safe_string_free(ss); @@ -310,7 +377,7 @@ ldap_matchingrule2str( const LDAP_MATCHING_RULE * mr ) } char * -ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc ) +ldap_matchingruleuse2str( const LDAPMatchingRuleUse * mru ) { safe_string * ss; char * retstring; @@ -319,7 +386,56 @@ ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc ) if ( !ss ) return NULL; - print_literal(ss,"("); + 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 == LDAP_SCHEMA_YES ) { + 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,/*(*/")"); + + retstring = LDAP_STRDUP(safe_string_val(ss)); + safe_string_free(ss); + return(retstring); +} + +char * +ldap_objectclass2str( const LDAPObjectClass * oc ) +{ + safe_string * ss; + char * retstring; + + ss = new_safe_string(256); + if ( !ss ) + return NULL; + + print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, oc->oc_oid); @@ -378,7 +494,10 @@ ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc ) } print_whsp(ss); - print_literal(ss,")"); + + print_extensions(ss, oc->oc_extensions); + + print_literal(ss, /*(*/")"); retstring = LDAP_STRDUP(safe_string_val(ss)); safe_string_free(ss); @@ -386,7 +505,7 @@ ldap_objectclass2str( const LDAP_OBJECT_CLASS * oc ) } char * -ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at ) +ldap_attributetype2str( const LDAPAttributeType * at ) { safe_string * ss; char * retstring; @@ -395,7 +514,7 @@ ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at ) if ( !ss ) return NULL; - print_literal(ss,"("); + print_literal(ss,"("/*)*/); print_whsp(ss); print_numericoid(ss, at->at_oid); @@ -478,7 +597,10 @@ ldap_attributetype2str( const LDAP_ATTRIBUTE_TYPE * at ) } print_whsp(ss); - print_literal(ss,")"); + + print_extensions(ss, at->at_extensions); + + print_literal(ss,/*(*/")"); retstring = LDAP_STRDUP(safe_string_val(ss)); safe_string_free(ss); @@ -531,6 +653,7 @@ get_token(const char ** sp, char ** token_val) const char * q; char * res; + *token_val = NULL; switch (**sp) { case '\0': kind = TK_EOS; @@ -572,7 +695,12 @@ get_token(const char ** sp, char ** token_val) default: kind = TK_BAREWORD; p = *sp; - while ( !isspace(**sp) && **sp != '\0' ) + while ( !LDAP_SPACE(**sp) && + **sp != '(' && + **sp != ')' && + **sp != '$' && + **sp != '\'' && + **sp != '\0' ) (*sp)++; q = *sp; res = LDAP_MALLOC(q-p+1); @@ -595,7 +723,7 @@ get_token(const char ** sp, char ** token_val) static void parse_whsp(const char **sp) { - while (isspace(**sp)) + while (LDAP_SPACE(**sp)) (*sp)++; } @@ -608,8 +736,8 @@ 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 * +parse_numericoid(const char **sp, int *code, const int flags) { char * res; const char * start = *sp; @@ -617,14 +745,14 @@ parse_numericoid(const char **sp, int *code, const int allow_quoted) 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 @@ -633,7 +761,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; @@ -649,7 +777,7 @@ parse_numericoid(const char **sp, int *code, const int allow_quoted) } strncpy(res,start,len); res[len] = '\0'; - if ( allow_quoted && quoted ) { + if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) { if ( **sp == '\'' ) { (*sp)++; } else { @@ -694,6 +822,7 @@ parse_qdescrs(const char **sp, int *code) res1 = LDAP_REALLOC(res,size*sizeof(char *)); if ( !res1 ) { LDAP_VFREE(res); + LDAP_FREE(sval); *code = LDAP_SCHERR_OUTOFMEM; return(NULL); } @@ -704,6 +833,7 @@ parse_qdescrs(const char **sp, int *code) parse_whsp(sp); } else { LDAP_VFREE(res); + LDAP_FREE(sval); *code = LDAP_SCHERR_UNEXPTOKEN; return(NULL); } @@ -722,6 +852,7 @@ parse_qdescrs(const char **sp, int *code) parse_whsp(sp); return res; } else { + LDAP_FREE(sval); *code = LDAP_SCHERR_BADNAME; return NULL; } @@ -737,6 +868,7 @@ parse_woid(const char **sp, int *code) parse_whsp(sp); kind = get_token(sp, &sval); if ( kind != TK_BAREWORD ) { + LDAP_FREE(sval); *code = LDAP_SCHERR_UNEXPTOKEN; return NULL; } @@ -761,12 +893,12 @@ parse_noidlen(const char **sp, int *code, int *len, int allow_quoted) if ( !sval ) { 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; @@ -828,6 +960,7 @@ parse_oids(const char **sp, int *code, const int allow_quoted) pos++; } else { *code = LDAP_SCHERR_UNEXPTOKEN; + LDAP_FREE(sval); LDAP_VFREE(res); return NULL; } @@ -846,9 +979,10 @@ parse_oids(const char **sp, int *code, const int allow_quoted) size++; res1 = LDAP_REALLOC(res,size*sizeof(char *)); if ( !res1 ) { - LDAP_VFREE(res); - *code = LDAP_SCHERR_OUTOFMEM; - return(NULL); + LDAP_FREE(sval); + LDAP_VFREE(res); + *code = LDAP_SCHERR_OUTOFMEM; + return(NULL); } res = res1; } @@ -856,12 +990,14 @@ parse_oids(const char **sp, int *code, const int allow_quoted) pos++; } else { *code = LDAP_SCHERR_UNEXPTOKEN; + LDAP_FREE(sval); LDAP_VFREE(res); return NULL; } parse_whsp(sp); } else { *code = LDAP_SCHERR_UNEXPTOKEN; + LDAP_FREE(sval); LDAP_VFREE(res); return NULL; } @@ -873,6 +1009,7 @@ parse_oids(const char **sp, int *code, const int allow_quoted) ( allow_quoted && kind == TK_QDSTRING ) ) { res = LDAP_CALLOC(2,sizeof(char *)); if ( !res ) { + LDAP_FREE(sval); *code = LDAP_SCHERR_OUTOFMEM; return NULL; } @@ -881,28 +1018,80 @@ parse_oids(const char **sp, int *code, const int allow_quoted) parse_whsp(sp); return res; } else { + LDAP_FREE(sval); *code = LDAP_SCHERR_BADNAME; return NULL; } } +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 ) + return 1; + n = 0; + } else { + for ( n=0; (*extensions)[n] != NULL; n++ ) + ; + tmp = LDAP_REALLOC(*extensions, + (n+2)*sizeof(LDAPSchemaExtensionItem *)); + if ( !tmp ) + 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_VFREE(syn->syn_names); 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( const char * s, int * code, const char ** errp, const int flags ) { int 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; @@ -911,7 +1100,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; @@ -920,6 +1109,7 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { + LDAP_FREE(sval); *code = LDAP_SCHERR_NOLEFTPAREN; ldap_syntax_free(syn); return NULL; @@ -949,7 +1139,25 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) case TK_RIGHTPAREN: return syn; case TK_BAREWORD: - if ( !strcmp(sval,"DESC") ) { + if ( !strcmp(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 ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -962,6 +1170,7 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_syntax_free(syn); return NULL; } @@ -969,15 +1178,24 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* 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; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_syntax_free(syn); return NULL; } @@ -985,6 +1203,7 @@ ldap_str2syntax( const char * s, int * code, const char ** errp ) default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_syntax_free(syn); return NULL; } @@ -992,28 +1211,28 @@ 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); + free_extensions(mr->mr_extensions); LDAP_FREE(mr); } -LDAP_MATCHING_RULE * -ldap_str2matchingrule( const char * s, int * code, const char ** errp ) +LDAPMatchingRule * +ldap_str2matchingrule( const char * s, int * code, const char ** errp, const int flags ) { int 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 ) { @@ -1023,7 +1242,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; @@ -1033,15 +1252,16 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } parse_whsp(&ss); savepos = ss; - mr->mr_oid = parse_numericoid(&ss,code,be_liberal); + mr->mr_oid = 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); @@ -1056,7 +1276,8 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) } else { /* Non-numerical OID, ignore */ } - } + } + LDAP_FREE(sval); } else { *errp = ss; ldap_matchingrule_free(mr); @@ -1081,6 +1302,7 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) return mr; case TK_BAREWORD: if ( !strcmp(sval,"NAME") ) { + LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1097,6 +1319,7 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) return NULL; } } else if ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1109,12 +1332,14 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } mr->mr_desc = sval; parse_whsp(&ss); } else if ( !strcmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1125,6 +1350,7 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) mr->mr_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcmp(sval,"SYNTAX") ) { + LDAP_FREE(sval); if ( seen_syntax ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1134,7 +1360,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); + parse_numericoid(&ss,code,flags); if ( !mr->mr_syntax_oid ) { *errp = ss; ldap_matchingrule_free(mr); @@ -1143,15 +1369,24 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* 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; + } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } @@ -1159,6 +1394,7 @@ ldap_str2matchingrule( const char * s, int * code, const char ** errp ) default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_matchingrule_free(mr); return NULL; } @@ -1166,7 +1402,197 @@ 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); + LDAP_VFREE(mru->mru_names); + LDAP_FREE(mru->mru_desc); + LDAP_VFREE(mru->mru_applies_oids); + free_extensions(mru->mru_extensions); + LDAP_FREE(mru); +} + +LDAPMatchingRuleUse * +ldap_str2matchingruleuse( const char * s, int * code, const char ** errp, const int flags ) +{ + int 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 = 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 ( !strcmp(sval, "NAME") || + !strcmp(sval, "DESC") || + !strcmp(sval, "OBSOLETE") || + !strcmp(sval, "APPLIES") || + !strncmp(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: + return mru; + case TK_BAREWORD: + if ( !strcmp(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 ( !strcmp(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 ( !strcmp(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 ( !strcmp(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 ) { + *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); @@ -1176,16 +1602,16 @@ ldap_attributetype_free(LDAP_ATTRIBUTE_TYPE * at) LDAP_FREE(at->at_ordering_oid); LDAP_FREE(at->at_substr_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( const char * s, int * code, const char ** errp, const int flags ) { int 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; @@ -1195,11 +1621,8 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) int seen_substr = 0; int seen_syntax = 0; int seen_usage = 0; - int seen_kind = 0; - int seen_must = 0; - int seen_may = 0; - LDAP_ATTRIBUTE_TYPE * at; - char ** ssdummy; + LDAPAttributeType * at; + char ** ext_vals; const char * savepos; if ( !s ) { @@ -1209,7 +1632,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; @@ -1219,6 +1642,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) kind = get_token(&ss,&sval); if ( kind != TK_LEFTPAREN ) { *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } @@ -1234,7 +1658,9 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) savepos = ss; at->at_oid = 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); @@ -1254,10 +1680,16 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) !strncmp(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); } else { *errp = ss; ldap_attributetype_free(at); @@ -1282,6 +1714,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) return at; case TK_BAREWORD: if ( !strcmp(sval,"NAME") ) { + LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1298,6 +1731,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) return NULL; } } else if ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1310,12 +1744,14 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } at->at_desc = sval; parse_whsp(&ss); } else if ( !strcmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1326,6 +1762,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) at->at_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcmp(sval,"SUP") ) { + LDAP_FREE(sval); if ( seen_sup ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1340,6 +1777,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) return NULL; } } else if ( !strcmp(sval,"EQUALITY") ) { + LDAP_FREE(sval); if ( seen_equality ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1354,6 +1792,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) return NULL; } } else if ( !strcmp(sval,"ORDERING") ) { + LDAP_FREE(sval); if ( seen_ordering ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1368,6 +1807,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) return NULL; } } else if ( !strcmp(sval,"SUBSTR") ) { + LDAP_FREE(sval); if ( seen_substr ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1382,6 +1822,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) return NULL; } } else if ( !strcmp(sval,"SYNTAX") ) { + LDAP_FREE(sval); if ( seen_syntax ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1390,18 +1831,42 @@ 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") ) { + LDAP_FREE(sval); if ( at->at_single_value ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1411,6 +1876,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") ) { + LDAP_FREE(sval); if ( at->at_collective ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1420,6 +1886,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") ) { + LDAP_FREE(sval); if ( at->at_no_user_mod ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1429,6 +1896,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") ) { + LDAP_FREE(sval); if ( seen_usage ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1441,6 +1909,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) if ( kind != TK_BAREWORD ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } @@ -1459,21 +1928,32 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } + LDAP_FREE(sval); parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* 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; + } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } @@ -1481,6 +1961,7 @@ ldap_str2attributetype( const char * s, int * code, const char ** errp ) default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_attributetype_free(at); return NULL; } @@ -1488,7 +1969,7 @@ 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); @@ -1496,16 +1977,16 @@ ldap_objectclass_free(LDAP_OBJECT_CLASS * oc) LDAP_VFREE(oc->oc_sup_oids); LDAP_VFREE(oc->oc_at_oids_must); 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( const char * s, int * code, const char ** errp, const int flags ) { int 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; @@ -1513,8 +1994,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 ) { @@ -1524,16 +2005,18 @@ 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 ) { *code = LDAP_SCHERR_NOLEFTPAREN; + LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } @@ -1549,7 +2032,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) savepos = ss; oc->oc_oid = 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); @@ -1565,10 +2048,16 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) !strncmp(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); } else { *errp = ss; ldap_objectclass_free(oc); @@ -1593,6 +2082,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) return oc; case TK_BAREWORD: if ( !strcmp(sval,"NAME") ) { + LDAP_FREE(sval); if ( seen_name ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1609,6 +2099,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) return NULL; } } else if ( !strcmp(sval,"DESC") ) { + LDAP_FREE(sval); if ( seen_desc ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1621,12 +2112,14 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) if ( kind != TK_QDSTRING ) { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } oc->oc_desc = sval; parse_whsp(&ss); } else if ( !strcmp(sval,"OBSOLETE") ) { + LDAP_FREE(sval); if ( seen_obsolete ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1637,6 +2130,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) oc->oc_obsolete = LDAP_SCHEMA_YES; parse_whsp(&ss); } else if ( !strcmp(sval,"SUP") ) { + LDAP_FREE(sval); if ( seen_sup ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1646,13 +2140,14 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) seen_sup = 1; oc->oc_sup_oids = parse_oids(&ss, code, - be_liberal); + flags); if ( !oc->oc_sup_oids ) { *errp = ss; ldap_objectclass_free(oc); return NULL; } } else if ( !strcmp(sval,"ABSTRACT") ) { + LDAP_FREE(sval); if ( seen_kind ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1663,6 +2158,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) oc->oc_kind = LDAP_SCHEMA_ABSTRACT; parse_whsp(&ss); } else if ( !strcmp(sval,"STRUCTURAL") ) { + LDAP_FREE(sval); if ( seen_kind ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1673,6 +2169,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) oc->oc_kind = LDAP_SCHEMA_STRUCTURAL; parse_whsp(&ss); } else if ( !strcmp(sval,"AUXILIARY") ) { + LDAP_FREE(sval); if ( seen_kind ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1683,6 +2180,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) oc->oc_kind = LDAP_SCHEMA_AUXILIARY; parse_whsp(&ss); } else if ( !strcmp(sval,"MUST") ) { + LDAP_FREE(sval); if ( seen_must ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1698,6 +2196,7 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) } parse_whsp(&ss); } else if ( !strcmp(sval,"MAY") ) { + LDAP_FREE(sval); if ( seen_may ) { *code = LDAP_SCHERR_DUPOPT; *errp = ss; @@ -1714,15 +2213,24 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) parse_whsp(&ss); } else if ( sval[0] == 'X' && sval[1] == '-' ) { /* Should be parse_qdstrings */ - ssdummy = parse_qdescrs(&ss, code); - if ( !ssdummy ) { + ext_vals = parse_qdescrs(&ss, code); + 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; } } else { *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } @@ -1730,14 +2238,15 @@ ldap_str2objectclass( const char * s, int * code, const char ** errp ) default: *code = LDAP_SCHERR_UNEXPTOKEN; *errp = ss; + LDAP_FREE(sval); ldap_objectclass_free(oc); return NULL; } } } -static char *err2text[] = { - "", +static char *const err2text[] = { + "Success", "Out of memory", "Unexpected token", "Missing opening parenthesis", @@ -1753,7 +2262,7 @@ static char *err2text[] = { char * ldap_scherr2str(int code) { - if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) { + if ( code < 0 || code >= (sizeof(err2text)/sizeof(char *)) ) { return "Unknown error"; } else { return err2text[code];