From 63e7c9e796723d186cabfff498613246dfed1763 Mon Sep 17 00:00:00 2001 From: Kurt Zeilenga Date: Sun, 13 Oct 2002 01:36:58 +0000 Subject: [PATCH] first cut at ditStructureRule and nameForm routines --- include/ldap_schema.h | 123 +++++-- libraries/libldap/schema.c | 653 ++++++++++++++++++++++++++++++++++--- 2 files changed, 705 insertions(+), 71 deletions(-) diff --git a/include/ldap_schema.h b/include/ldap_schema.h index d72c801c46..49078d832c 100644 --- a/include/ldap_schema.h +++ b/include/ldap_schema.h @@ -28,12 +28,14 @@ LDAP_BEGIN_DECL #define LDAP_SCHERR_UNEXPTOKEN 2 #define LDAP_SCHERR_NOLEFTPAREN 3 #define LDAP_SCHERR_NORIGHTPAREN 4 -#define LDAP_SCHERR_NODIGIT 5 -#define LDAP_SCHERR_BADNAME 6 -#define LDAP_SCHERR_BADDESC 7 -#define LDAP_SCHERR_BADSUP 8 -#define LDAP_SCHERR_DUPOPT 9 -#define LDAP_SCHERR_EMPTY 10 +#define LDAP_SCHERR_NODIGIT 5 +#define LDAP_SCHERR_BADNAME 6 +#define LDAP_SCHERR_BADDESC 7 +#define LDAP_SCHERR_BADSUP 8 +#define LDAP_SCHERR_DUPOPT 9 +#define LDAP_SCHERR_EMPTY 10 +#define LDAP_SCHERR_MISSING 11 +#define LDAP_SCHERR_OUT_OF_ORDER 12 typedef struct ldap_schema_extension_item { char *lsei_name; @@ -109,6 +111,27 @@ typedef struct ldap_contentrule { LDAPSchemaExtensionItem **cr_extensions; /* OPTIONAL */ } LDAPContentRule; +typedef struct ldap_nameform { + char *nf_oid; /* REQUIRED */ + char **nf_names; /* OPTIONAL */ + char *nf_desc; /* OPTIONAL */ + int nf_obsolete; /* 0=no, 1=yes */ + char *nf_objectclass; /* REQUIRED */ + char **nf_at_oids_must; /* REQUIRED */ + char **nf_at_oids_may; /* OPTIONAL */ + LDAPSchemaExtensionItem **nf_extensions; /* OPTIONAL */ +} LDAPNameForm; + +typedef struct ldap_structurerule { + int sr_ruleid; /* REQUIRED */ + char **sr_names; /* OPTIONAL */ + char *sr_desc; /* OPTIONAL */ + int sr_obsolete; /* 0=no, 1=yes */ + char *sr_nameform; /* REQUIRED */ + int sr_nsup_ruleids;/* number of sr_sup_ruleids */ + int *sr_sup_ruleids;/* OPTIONAL */ + LDAPSchemaExtensionItem **sr_extensions; /* OPTIONAL */ +} LDAPStructureRule; /* * Misc macros @@ -129,14 +152,16 @@ typedef struct ldap_contentrule { /* * Flags that control how liberal the parsing routines are. */ -#define LDAP_SCHEMA_ALLOW_NONE 0x00 /* Strict parsing */ -#define LDAP_SCHEMA_ALLOW_NO_OID 0x01 /* Allow missing oid */ -#define LDAP_SCHEMA_ALLOW_QUOTED 0x02 /* Allow bogus extra quotes */ -#define LDAP_SCHEMA_ALLOW_DESCR 0x04 /* Allow descr instead of OID */ -#define LDAP_SCHEMA_ALLOW_DESCR_PREFIX 0x08 /* Allow descr as OID prefix */ -#define LDAP_SCHEMA_ALLOW_OID_MACRO 0x10 /* Allow OID macros in slapd */ -#define LDAP_SCHEMA_ALLOW_ALL 0x1f /* Be very liberal in parsing */ -#define LDAP_SCHEMA_SKIP 0x80 /* Don't malloc any result */ +#define LDAP_SCHEMA_ALLOW_NONE 0x00U /* Strict parsing */ +#define LDAP_SCHEMA_ALLOW_NO_OID 0x01U /* Allow missing oid */ +#define LDAP_SCHEMA_ALLOW_QUOTED 0x02U /* Allow bogus extra quotes */ +#define LDAP_SCHEMA_ALLOW_DESCR 0x04U /* Allow descr instead of OID */ +#define LDAP_SCHEMA_ALLOW_DESCR_PREFIX 0x08U /* Allow descr as OID prefix */ +#define LDAP_SCHEMA_ALLOW_OID_MACRO 0x10U /* Allow OID macros in slapd */ +#define LDAP_SCHEMA_ALLOW_OUT_OF_ORDER_FIELDS 0x20U /* Allow fields in most any order */ +#define LDAP_SCHEMA_ALLOW_ALL 0x3fU /* Be very liberal in parsing */ +#define LDAP_SCHEMA_SKIP 0x80U /* Don't malloc any result */ + LDAP_F( LDAP_CONST char * ) ldap_syntax2name LDAP_P(( @@ -162,6 +187,14 @@ LDAP_F( LDAP_CONST char * ) ldap_contentrule2name LDAP_P(( LDAPContentRule * cr )); +LDAP_F( LDAP_CONST char * ) +ldap_nameform2name LDAP_P(( + LDAPNameForm * nf )); + +LDAP_F( LDAP_CONST char * ) +ldap_structurerule2name LDAP_P(( + LDAPStructureRule * sr )); + LDAP_F( void ) ldap_syntax_free LDAP_P(( LDAPSyntax * syn )); @@ -186,55 +219,85 @@ LDAP_F( void ) ldap_contentrule_free LDAP_P(( LDAPContentRule * cr )); -LDAP_F( LDAPObjectClass * ) -ldap_str2objectclass LDAP_P(( +LDAP_F( void ) +ldap_nameform_free LDAP_P(( + LDAPNameForm * nf )); + +LDAP_F( void ) +ldap_structurerule_free LDAP_P(( + LDAPStructureRule * sr )); + +LDAP_F( LDAPStructureRule * ) +ldap_str2structurerule LDAP_P(( + LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags )); + +LDAP_F( LDAPNameForm * ) +ldap_str2nameform LDAP_P(( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags )); + LDAP_CONST unsigned flags )); LDAP_F( LDAPContentRule * ) ldap_str2contentrule LDAP_P(( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags )); + LDAP_CONST unsigned flags )); + +LDAP_F( LDAPObjectClass * ) +ldap_str2objectclass LDAP_P(( + LDAP_CONST char * s, + int * code, + LDAP_CONST char ** errp, + LDAP_CONST unsigned flags )); LDAP_F( LDAPAttributeType * ) ldap_str2attributetype LDAP_P(( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags )); + LDAP_CONST unsigned flags )); LDAP_F( LDAPSyntax * ) ldap_str2syntax LDAP_P(( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags )); + LDAP_CONST unsigned flags )); LDAP_F( LDAPMatchingRule * ) ldap_str2matchingrule LDAP_P(( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags )); + LDAP_CONST unsigned flags )); LDAP_F( LDAPMatchingRuleUse * ) ldap_str2matchingruleuse LDAP_P(( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags )); + LDAP_CONST unsigned flags )); LDAP_F( char * ) -ldap_objectclass2str LDAP_P(( - LDAPObjectClass * oc )); +ldap_structurerule2str LDAP_P(( + LDAPStructureRule * sr )); LDAP_F( struct berval * ) -ldap_objectclass2bv LDAP_P(( - LDAPObjectClass * oc, struct berval *bv )); +ldap_structurerule2bv LDAP_P(( + LDAPStructureRule * sr, struct berval *bv )); + +LDAP_F( char * ) +ldap_nameform2str LDAP_P(( + LDAPNameForm * nf )); + +LDAP_F( struct berval * ) +ldap_nameform2bv LDAP_P(( + LDAPNameForm * nf, struct berval *bv )); LDAP_F( char * ) ldap_contentrule2str LDAP_P(( @@ -244,6 +307,14 @@ LDAP_F( struct berval * ) ldap_contentrule2bv LDAP_P(( LDAPContentRule * cr, struct berval *bv )); +LDAP_F( char * ) +ldap_objectclass2str LDAP_P(( + LDAPObjectClass * oc )); + +LDAP_F( struct berval * ) +ldap_objectclass2bv LDAP_P(( + LDAPObjectClass * oc, struct berval *bv )); + LDAP_F( char * ) ldap_attributetype2str LDAP_P(( LDAPAttributeType * at )); diff --git a/libraries/libldap/schema.c b/libraries/libldap/schema.c index 417b4bdba6..2cfe8d46d1 100644 --- a/libraries/libldap/schema.c +++ b/libraries/libldap/schema.c @@ -23,7 +23,7 @@ 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 * @@ -62,12 +62,24 @@ 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. * Since checking for overflow, realloc'ing and checking if no error - * is extremely boring, we will use a protection layer that will let - * us blissfully ignore the error until the end. This layer is - * implemented with the help of the next type. + * is extremely boring, we error until the end. This layer is + * implemented with the he will use a protection layer that will let + * us blissfully ignore thlp of the next type. */ typedef struct safe_string { @@ -292,6 +304,34 @@ print_noidlen(safe_string *ss, char *s, int l) 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; isr_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(bv); +} + char * ldap_attributetype2str( LDAPAttributeType * at ) { @@ -937,6 +1110,28 @@ ldap_int_parse_numericoid(const char **sp, int *code, const int flags) 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) @@ -1234,7 +1429,7 @@ LDAPSyntax * ldap_str2syntax( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags ) + LDAP_CONST unsigned flags ) { int kind; const char * ss = s; @@ -1376,7 +1571,7 @@ LDAPMatchingRule * ldap_str2matchingrule( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags ) + LDAP_CONST unsigned flags ) { int kind; const char * ss = s; @@ -1453,6 +1648,11 @@ ldap_str2matchingrule( LDAP_CONST char * s, 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") ) { @@ -1570,7 +1770,7 @@ LDAPMatchingRuleUse * ldap_str2matchingruleuse( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags ) + LDAP_CONST unsigned flags ) { int kind; const char * ss = s; @@ -1647,6 +1847,11 @@ ldap_str2matchingruleuse( LDAP_CONST char * s, 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 ( !strcmp(sval,"NAME") ) { @@ -1767,7 +1972,7 @@ LDAPAttributeType * ldap_str2attributetype( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags ) + LDAP_CONST unsigned flags ) { int kind; const char * ss = s; @@ -2145,7 +2350,7 @@ LDAPObjectClass * ldap_str2objectclass( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags ) + LDAP_CONST unsigned flags ) { int kind; const char * ss = s; @@ -2427,7 +2632,7 @@ LDAPContentRule * ldap_str2contentrule( LDAP_CONST char * s, int * code, LDAP_CONST char ** errp, - LDAP_CONST int flags ) + LDAP_CONST unsigned flags ) { int kind; const char * ss = s; @@ -2467,45 +2672,14 @@ ldap_str2contentrule( LDAP_CONST char * s, /* * 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; 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 ( !strcmp(sval, "NAME") || - !strcmp(sval, "DESC") || - !strcmp(sval, "OBSOLETE") || - !strcmp(sval, "AUX") || - !strcmp(sval, "MUST") || - !strcmp(sval, "MAY") || - !strcmp(sval, "NOT") || - !strncmp(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; - } + *errp = ss; + ldap_contentrule_free(cr); + return NULL; } parse_whsp(&ss); @@ -2670,6 +2844,393 @@ ldap_str2contentrule( LDAP_CONST char * s, } } +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 ) +{ + int kind, ret; + const char * ss = s; + char * sval; + int seen_name = 0; + int seen_desc = 0; + int seen_obsolete = 0; + int seen_nameform = 0; + int seen_ruleids = 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 ( !strcmp(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 ( !strcmp(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 ( !strcmp(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 ( !strcmp(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 ) +{ + int 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 ( !strcmp(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 ( !strcmp(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 ( !strcmp(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 ( !strcmp(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 ) { + *errp = ss; + ldap_nameform_free(nf); + return NULL; + } + parse_whsp(&ss); + } else if ( !strcmp(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 ) { + *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[] = { "Success", "Out of memory", @@ -2681,7 +3242,9 @@ static char *const err2text[] = { "Bad description", "Bad superiors", "Duplicate option", - "Unexpected end of data" + "Unexpected end of data", + "Missing required field", + "Out of order field" }; char * -- 2.39.5