Back to index

openldap  2.4.31
schema.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 
00016 /*
00017  * schema.c:  parsing routines used by servers and clients to process
00018  *     schema definitions
00019  */
00020 
00021 #include "portable.h"
00022 
00023 #include <stdio.h>
00024 #include <ac/stdlib.h>
00025 
00026 #include <ac/string.h>
00027 #include <ac/time.h>
00028 
00029 #include "ldap-int.h"
00030 
00031 #include <ldap_schema.h>
00032 
00033 static const char EndOfInput[] = "end of input";
00034 
00035 static const char *
00036 choose_name( char *names[], const char *fallback )
00037 {
00038        return (names != NULL && names[0] != NULL) ? names[0] : fallback;
00039 }
00040 
00041 LDAP_CONST char *
00042 ldap_syntax2name( LDAPSyntax * syn )
00043 {
00044        if (!syn) return NULL;
00045        return( syn->syn_oid );
00046 }
00047 
00048 LDAP_CONST char *
00049 ldap_matchingrule2name( LDAPMatchingRule * mr )
00050 {
00051        if (!mr) return NULL;
00052        return( choose_name( mr->mr_names, mr->mr_oid ) );
00053 }
00054 
00055 LDAP_CONST char *
00056 ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru )
00057 {
00058        if (!mru) return NULL;
00059        return( choose_name( mru->mru_names, mru->mru_oid ) );
00060 }
00061 
00062 LDAP_CONST char *
00063 ldap_attributetype2name( LDAPAttributeType * at )
00064 {
00065        if (!at) return NULL;
00066        return( choose_name( at->at_names, at->at_oid ) );
00067 }
00068 
00069 LDAP_CONST char *
00070 ldap_objectclass2name( LDAPObjectClass * oc )
00071 {
00072        if (!oc) return NULL;
00073        return( choose_name( oc->oc_names, oc->oc_oid ) );
00074 }
00075 
00076 LDAP_CONST char *
00077 ldap_contentrule2name( LDAPContentRule * cr )
00078 {
00079        if (!cr) return NULL;
00080        return( choose_name( cr->cr_names, cr->cr_oid ) );
00081 }
00082 
00083 LDAP_CONST char *
00084 ldap_nameform2name( LDAPNameForm * nf )
00085 {
00086        if (!nf) return NULL;
00087        return( choose_name( nf->nf_names, nf->nf_oid ) );
00088 }
00089 
00090 LDAP_CONST char *
00091 ldap_structurerule2name( LDAPStructureRule * sr )
00092 {
00093        if (!sr) return NULL;
00094        return( choose_name( sr->sr_names, NULL ) );
00095 }
00096 
00097 /*
00098  * When pretty printing the entities we will be appending to a buffer.
00099  * Since checking for overflow, realloc'ing and checking if no error
00100  * is extremely boring, we will use a protection layer that will let
00101  * us blissfully ignore the error until the end.  This layer is
00102  * implemented with the help of the next type.
00103  */
00104 
00105 typedef struct safe_string {
00106        char * val;
00107        ber_len_t size;
00108        ber_len_t pos;
00109        int at_whsp;
00110 } safe_string;
00111 
00112 static safe_string *
00113 new_safe_string(int size)
00114 {
00115        safe_string * ss;
00116        
00117        ss = LDAP_MALLOC(sizeof(safe_string));
00118        if ( !ss )
00119               return(NULL);
00120 
00121        ss->val = LDAP_MALLOC(size);
00122        if ( !ss->val ) {
00123               LDAP_FREE(ss);
00124               return(NULL);
00125        }
00126 
00127        ss->size = size;
00128        ss->pos = 0;
00129        ss->at_whsp = 0;
00130 
00131        return ss;
00132 }
00133 
00134 static void
00135 safe_string_free(safe_string * ss)
00136 {
00137        if ( !ss )
00138               return;
00139        LDAP_FREE(ss->val);
00140        LDAP_FREE(ss);
00141 }
00142 
00143 #if 0  /* unused */
00144 static char *
00145 safe_string_val(safe_string * ss)
00146 {
00147        ss->val[ss->pos] = '\0';
00148        return(ss->val);
00149 }
00150 #endif
00151 
00152 static char *
00153 safe_strdup(safe_string * ss)
00154 {
00155        char *ret = LDAP_MALLOC(ss->pos+1);
00156        if (!ret)
00157               return NULL;
00158        AC_MEMCPY(ret, ss->val, ss->pos);
00159        ret[ss->pos] = '\0';
00160        return ret;
00161 }
00162 
00163 static int
00164 append_to_safe_string(safe_string * ss, char * s)
00165 {
00166        int l = strlen(s);
00167        char * temp;
00168 
00169        /*
00170         * Some runaway process is trying to append to a string that
00171         * overflowed and we could not extend.
00172         */
00173        if ( !ss->val )
00174               return -1;
00175 
00176        /* We always make sure there is at least one position available */
00177        if ( ss->pos + l >= ss->size-1 ) {
00178               ss->size *= 2;
00179               if ( ss->pos + l >= ss->size-1 ) {
00180                      ss->size = ss->pos + l + 1;
00181               }
00182 
00183               temp = LDAP_REALLOC(ss->val, ss->size);
00184               if ( !temp ) {
00185                      /* Trouble, out of memory */
00186                      LDAP_FREE(ss->val);
00187                      return -1;
00188               }
00189               ss->val = temp;
00190        }
00191        strncpy(&ss->val[ss->pos], s, l);
00192        ss->pos += l;
00193        if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
00194               ss->at_whsp = 1;
00195        else
00196               ss->at_whsp = 0;
00197 
00198        return 0;
00199 }
00200 
00201 static int
00202 print_literal(safe_string *ss, char *s)
00203 {
00204        return(append_to_safe_string(ss,s));
00205 }
00206 
00207 static int
00208 print_whsp(safe_string *ss)
00209 {
00210        if ( ss->at_whsp )
00211               return(append_to_safe_string(ss,""));
00212        else
00213               return(append_to_safe_string(ss," "));
00214 }
00215 
00216 static int
00217 print_numericoid(safe_string *ss, char *s)
00218 {
00219        if ( s )
00220               return(append_to_safe_string(ss,s));
00221        else
00222               return(append_to_safe_string(ss,""));
00223 }
00224 
00225 /* This one is identical to print_qdescr */
00226 static int
00227 print_qdstring(safe_string *ss, char *s)
00228 {
00229        print_whsp(ss);
00230        print_literal(ss,"'");
00231        append_to_safe_string(ss,s);
00232        print_literal(ss,"'");
00233        return(print_whsp(ss));
00234 }
00235 
00236 static int
00237 print_qdescr(safe_string *ss, char *s)
00238 {
00239        print_whsp(ss);
00240        print_literal(ss,"'");
00241        append_to_safe_string(ss,s);
00242        print_literal(ss,"'");
00243        return(print_whsp(ss));
00244 }
00245 
00246 static int
00247 print_qdescrlist(safe_string *ss, char **sa)
00248 {
00249        char **sp;
00250        int ret = 0;
00251        
00252        for (sp=sa; *sp; sp++) {
00253               ret = print_qdescr(ss,*sp);
00254        }
00255        /* If the list was empty, we return zero that is potentially
00256         * incorrect, but since we will be still appending things, the
00257         * overflow will be detected later.  Maybe FIX.
00258         */
00259        return(ret);
00260 }
00261 
00262 static int
00263 print_qdescrs(safe_string *ss, char **sa)
00264 {
00265        /* The only way to represent an empty list is as a qdescrlist
00266         * so, if the list is empty we treat it as a long list.
00267         * Really, this is what the syntax mandates.  We should not
00268         * be here if the list was empty, but if it happens, a label
00269         * has already been output and we cannot undo it.
00270         */
00271        if ( !sa[0] || ( sa[0] && sa[1] ) ) {
00272               print_whsp(ss);
00273               print_literal(ss,"("/*)*/);
00274               print_qdescrlist(ss,sa);
00275               print_literal(ss,/*(*/")");
00276               return(print_whsp(ss));
00277        } else {
00278          return(print_qdescr(ss,*sa));
00279        }
00280 }
00281 
00282 static int
00283 print_woid(safe_string *ss, char *s)
00284 {
00285        print_whsp(ss);
00286        append_to_safe_string(ss,s);
00287        return print_whsp(ss);
00288 }
00289 
00290 static int
00291 print_oidlist(safe_string *ss, char **sa)
00292 {
00293        char **sp;
00294 
00295        for (sp=sa; *(sp+1); sp++) {
00296               print_woid(ss,*sp);
00297               print_literal(ss,"$");
00298        }
00299        return(print_woid(ss,*sp));
00300 }
00301 
00302 static int
00303 print_oids(safe_string *ss, char **sa)
00304 {
00305        if ( sa[0] && sa[1] ) {
00306               print_literal(ss,"("/*)*/);
00307               print_oidlist(ss,sa);
00308               print_whsp(ss);
00309               return(print_literal(ss,/*(*/")"));
00310        } else {
00311               return(print_woid(ss,*sa));
00312        }
00313 }
00314 
00315 static int
00316 print_noidlen(safe_string *ss, char *s, int l)
00317 {
00318        char buf[64];
00319        int ret;
00320 
00321        ret = print_numericoid(ss,s);
00322        if ( l ) {
00323               snprintf(buf, sizeof buf, "{%d}",l);
00324               ret = print_literal(ss,buf);
00325        }
00326        return(ret);
00327 }
00328 
00329 static int
00330 print_ruleid(safe_string *ss, int rid)
00331 {
00332        char buf[64];
00333        snprintf(buf, sizeof buf, "%d", rid);
00334        return print_literal(ss,buf);
00335 }
00336 
00337 static int
00338 print_ruleids(safe_string *ss, int n, int *rids)
00339 {
00340        int i;
00341 
00342        if( n == 1 ) {
00343               print_ruleid(ss,rids[0]);
00344               return print_whsp(ss);
00345        } else {
00346               print_literal(ss,"("/*)*/);
00347               for( i=0; i<n; i++ ) {
00348                      print_whsp(ss);
00349                      print_ruleid(ss,rids[i]);
00350               }
00351               print_whsp(ss);
00352               return print_literal(ss,/*(*/")");
00353        }
00354 }
00355 
00356 
00357 static int
00358 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
00359 {
00360        LDAPSchemaExtensionItem **ext;
00361 
00362        if ( extensions ) {
00363               print_whsp(ss);
00364               for ( ext = extensions; *ext != NULL; ext++ ) {
00365                      print_literal(ss, (*ext)->lsei_name);
00366                      print_whsp(ss);
00367                      /* Should be print_qdstrings */
00368                      print_qdescrs(ss, (*ext)->lsei_values);
00369                      print_whsp(ss);
00370               }
00371        }
00372 
00373        return 0;
00374 }
00375 
00376 char *
00377 ldap_syntax2str( LDAPSyntax * syn )
00378 {
00379        struct berval bv;
00380        if (ldap_syntax2bv( syn, &bv ))
00381               return(bv.bv_val);
00382        else
00383               return NULL;
00384 }
00385 
00386 struct berval *
00387 ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv )
00388 {
00389        safe_string * ss;
00390 
00391        if ( !syn || !bv )
00392               return NULL;
00393 
00394        ss = new_safe_string(256);
00395        if ( !ss )
00396               return NULL;
00397 
00398        print_literal(ss,"("/*)*/);
00399        print_whsp(ss);
00400 
00401        print_numericoid(ss, syn->syn_oid);
00402        print_whsp(ss);
00403 
00404        if ( syn->syn_desc ) {
00405               print_literal(ss,"DESC");
00406               print_qdstring(ss,syn->syn_desc);
00407        }
00408 
00409        print_whsp(ss);
00410 
00411        print_extensions(ss, syn->syn_extensions);
00412 
00413        print_literal(ss,/*(*/ ")");
00414 
00415        bv->bv_val = safe_strdup(ss);
00416        bv->bv_len = ss->pos;
00417        safe_string_free(ss);
00418        return(bv);
00419 }
00420 
00421 char *
00422 ldap_matchingrule2str( LDAPMatchingRule * mr )
00423 {
00424        struct berval bv;
00425        if (ldap_matchingrule2bv( mr, &bv ))
00426               return(bv.bv_val);
00427        else
00428               return NULL;
00429 }
00430 
00431 struct berval *
00432 ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv )
00433 {
00434        safe_string * ss;
00435 
00436        if ( !mr || !bv )
00437               return NULL;
00438 
00439        ss = new_safe_string(256);
00440        if ( !ss )
00441               return NULL;
00442 
00443        print_literal(ss,"(" /*)*/);
00444        print_whsp(ss);
00445 
00446        print_numericoid(ss, mr->mr_oid);
00447        print_whsp(ss);
00448 
00449        if ( mr->mr_names ) {
00450               print_literal(ss,"NAME");
00451               print_qdescrs(ss,mr->mr_names);
00452        }
00453 
00454        if ( mr->mr_desc ) {
00455               print_literal(ss,"DESC");
00456               print_qdstring(ss,mr->mr_desc);
00457        }
00458 
00459        if ( mr->mr_obsolete ) {
00460               print_literal(ss, "OBSOLETE");
00461               print_whsp(ss);
00462        }
00463 
00464        if ( mr->mr_syntax_oid ) {
00465               print_literal(ss,"SYNTAX");
00466               print_whsp(ss);
00467               print_literal(ss, mr->mr_syntax_oid);
00468               print_whsp(ss);
00469        }
00470 
00471        print_whsp(ss);
00472 
00473        print_extensions(ss, mr->mr_extensions);
00474 
00475        print_literal(ss,/*(*/")");
00476 
00477        bv->bv_val = safe_strdup(ss);
00478        bv->bv_len = ss->pos;
00479        safe_string_free(ss);
00480        return(bv);
00481 }
00482 
00483 char *
00484 ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru )
00485 {
00486        struct berval bv;
00487        if (ldap_matchingruleuse2bv( mru, &bv ))
00488               return(bv.bv_val);
00489        else
00490               return NULL;
00491 }
00492 
00493 struct berval *
00494 ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv )
00495 {
00496        safe_string * ss;
00497 
00498        if ( !mru || !bv )
00499               return NULL;
00500 
00501        ss = new_safe_string(256);
00502        if ( !ss )
00503               return NULL;
00504 
00505        print_literal(ss,"(" /*)*/);
00506        print_whsp(ss);
00507 
00508        print_numericoid(ss, mru->mru_oid);
00509        print_whsp(ss);
00510 
00511        if ( mru->mru_names ) {
00512               print_literal(ss,"NAME");
00513               print_qdescrs(ss,mru->mru_names);
00514        }
00515 
00516        if ( mru->mru_desc ) {
00517               print_literal(ss,"DESC");
00518               print_qdstring(ss,mru->mru_desc);
00519        }
00520 
00521        if ( mru->mru_obsolete ) {
00522               print_literal(ss, "OBSOLETE");
00523               print_whsp(ss);
00524        }
00525 
00526        if ( mru->mru_applies_oids ) {
00527               print_literal(ss,"APPLIES");
00528               print_whsp(ss);
00529               print_oids(ss, mru->mru_applies_oids);
00530               print_whsp(ss);
00531        }
00532 
00533        print_whsp(ss);
00534 
00535        print_extensions(ss, mru->mru_extensions);
00536 
00537        print_literal(ss,/*(*/")");
00538 
00539        bv->bv_val = safe_strdup(ss);
00540        bv->bv_len = ss->pos;
00541        safe_string_free(ss);
00542        return(bv);
00543 }
00544 
00545 char *
00546 ldap_objectclass2str( LDAPObjectClass * oc )
00547 {
00548        struct berval bv;
00549        if (ldap_objectclass2bv( oc, &bv ))
00550               return(bv.bv_val);
00551        else
00552               return NULL;
00553 }
00554 
00555 struct berval *
00556 ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv )
00557 {
00558        safe_string * ss;
00559 
00560        if ( !oc || !bv )
00561               return NULL;
00562 
00563        ss = new_safe_string(256);
00564        if ( !ss )
00565               return NULL;
00566 
00567        print_literal(ss,"("/*)*/);
00568        print_whsp(ss);
00569 
00570        print_numericoid(ss, oc->oc_oid);
00571        print_whsp(ss);
00572 
00573        if ( oc->oc_names ) {
00574               print_literal(ss,"NAME");
00575               print_qdescrs(ss,oc->oc_names);
00576        }
00577 
00578        if ( oc->oc_desc ) {
00579               print_literal(ss,"DESC");
00580               print_qdstring(ss,oc->oc_desc);
00581        }
00582 
00583        if ( oc->oc_obsolete ) {
00584               print_literal(ss, "OBSOLETE");
00585               print_whsp(ss);
00586        }
00587 
00588        if ( oc->oc_sup_oids ) {
00589               print_literal(ss,"SUP");
00590               print_whsp(ss);
00591               print_oids(ss,oc->oc_sup_oids);
00592               print_whsp(ss);
00593        }
00594 
00595        switch (oc->oc_kind) {
00596        case LDAP_SCHEMA_ABSTRACT:
00597               print_literal(ss,"ABSTRACT");
00598               break;
00599        case LDAP_SCHEMA_STRUCTURAL:
00600               print_literal(ss,"STRUCTURAL");
00601               break;
00602        case LDAP_SCHEMA_AUXILIARY:
00603               print_literal(ss,"AUXILIARY");
00604               break;
00605        default:
00606               print_literal(ss,"KIND-UNKNOWN");
00607               break;
00608        }
00609        print_whsp(ss);
00610        
00611        if ( oc->oc_at_oids_must ) {
00612               print_literal(ss,"MUST");
00613               print_whsp(ss);
00614               print_oids(ss,oc->oc_at_oids_must);
00615               print_whsp(ss);
00616        }
00617 
00618        if ( oc->oc_at_oids_may ) {
00619               print_literal(ss,"MAY");
00620               print_whsp(ss);
00621               print_oids(ss,oc->oc_at_oids_may);
00622               print_whsp(ss);
00623        }
00624 
00625        print_whsp(ss);
00626 
00627        print_extensions(ss, oc->oc_extensions);
00628 
00629        print_literal(ss, /*(*/")");
00630 
00631        bv->bv_val = safe_strdup(ss);
00632        bv->bv_len = ss->pos;
00633        safe_string_free(ss);
00634        return(bv);
00635 }
00636 
00637 char *
00638 ldap_contentrule2str( LDAPContentRule * cr )
00639 {
00640        struct berval bv;
00641        if (ldap_contentrule2bv( cr, &bv ))
00642               return(bv.bv_val);
00643        else
00644               return NULL;
00645 }
00646 
00647 struct berval *
00648 ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv )
00649 {
00650        safe_string * ss;
00651 
00652        if ( !cr || !bv )
00653               return NULL;
00654 
00655        ss = new_safe_string(256);
00656        if ( !ss )
00657               return NULL;
00658 
00659        print_literal(ss,"("/*)*/);
00660        print_whsp(ss);
00661 
00662        print_numericoid(ss, cr->cr_oid);
00663        print_whsp(ss);
00664 
00665        if ( cr->cr_names ) {
00666               print_literal(ss,"NAME");
00667               print_qdescrs(ss,cr->cr_names);
00668        }
00669 
00670        if ( cr->cr_desc ) {
00671               print_literal(ss,"DESC");
00672               print_qdstring(ss,cr->cr_desc);
00673        }
00674 
00675        if ( cr->cr_obsolete ) {
00676               print_literal(ss, "OBSOLETE");
00677               print_whsp(ss);
00678        }
00679 
00680        if ( cr->cr_oc_oids_aux ) {
00681               print_literal(ss,"AUX");
00682               print_whsp(ss);
00683               print_oids(ss,cr->cr_oc_oids_aux);
00684               print_whsp(ss);
00685        }
00686 
00687        if ( cr->cr_at_oids_must ) {
00688               print_literal(ss,"MUST");
00689               print_whsp(ss);
00690               print_oids(ss,cr->cr_at_oids_must);
00691               print_whsp(ss);
00692        }
00693 
00694        if ( cr->cr_at_oids_may ) {
00695               print_literal(ss,"MAY");
00696               print_whsp(ss);
00697               print_oids(ss,cr->cr_at_oids_may);
00698               print_whsp(ss);
00699        }
00700 
00701        if ( cr->cr_at_oids_not ) {
00702               print_literal(ss,"NOT");
00703               print_whsp(ss);
00704               print_oids(ss,cr->cr_at_oids_not);
00705               print_whsp(ss);
00706        }
00707 
00708        print_whsp(ss);
00709        print_extensions(ss, cr->cr_extensions);
00710 
00711        print_literal(ss, /*(*/")");
00712 
00713        bv->bv_val = safe_strdup(ss);
00714        bv->bv_len = ss->pos;
00715        safe_string_free(ss);
00716        return(bv);
00717 }
00718 
00719 char *
00720 ldap_structurerule2str( LDAPStructureRule * sr )
00721 {
00722        struct berval bv;
00723        if (ldap_structurerule2bv( sr, &bv ))
00724               return(bv.bv_val);
00725        else
00726               return NULL;
00727 }
00728 
00729 struct berval *
00730 ldap_structurerule2bv( LDAPStructureRule * sr, struct berval *bv )
00731 {
00732        safe_string * ss;
00733 
00734        if ( !sr || !bv )
00735               return NULL;
00736 
00737        ss = new_safe_string(256);
00738        if ( !ss )
00739               return NULL;
00740 
00741        print_literal(ss,"("/*)*/);
00742        print_whsp(ss);
00743 
00744        print_ruleid(ss, sr->sr_ruleid);
00745        print_whsp(ss);
00746 
00747        if ( sr->sr_names ) {
00748               print_literal(ss,"NAME");
00749               print_qdescrs(ss,sr->sr_names);
00750        }
00751 
00752        if ( sr->sr_desc ) {
00753               print_literal(ss,"DESC");
00754               print_qdstring(ss,sr->sr_desc);
00755        }
00756 
00757        if ( sr->sr_obsolete ) {
00758               print_literal(ss, "OBSOLETE");
00759               print_whsp(ss);
00760        }
00761 
00762        print_literal(ss,"FORM");
00763        print_whsp(ss);
00764        print_woid(ss,sr->sr_nameform);
00765        print_whsp(ss);
00766 
00767        if ( sr->sr_nsup_ruleids ) {
00768               print_literal(ss,"SUP");
00769               print_whsp(ss);
00770               print_ruleids(ss,sr->sr_nsup_ruleids,sr->sr_sup_ruleids);
00771               print_whsp(ss);
00772        }
00773 
00774        print_whsp(ss);
00775        print_extensions(ss, sr->sr_extensions);
00776 
00777        print_literal(ss, /*(*/")");
00778 
00779        bv->bv_val = safe_strdup(ss);
00780        bv->bv_len = ss->pos;
00781        safe_string_free(ss);
00782        return(bv);
00783 }
00784 
00785 
00786 char *
00787 ldap_nameform2str( LDAPNameForm * nf )
00788 {
00789        struct berval bv;
00790        if (ldap_nameform2bv( nf, &bv ))
00791               return(bv.bv_val);
00792        else
00793               return NULL;
00794 }
00795 
00796 struct berval *
00797 ldap_nameform2bv( LDAPNameForm * nf, struct berval *bv )
00798 {
00799        safe_string * ss;
00800 
00801        if ( !nf || !bv )
00802               return NULL;
00803 
00804        ss = new_safe_string(256);
00805        if ( !ss )
00806               return NULL;
00807 
00808        print_literal(ss,"("/*)*/);
00809        print_whsp(ss);
00810 
00811        print_numericoid(ss, nf->nf_oid);
00812        print_whsp(ss);
00813 
00814        if ( nf->nf_names ) {
00815               print_literal(ss,"NAME");
00816               print_qdescrs(ss,nf->nf_names);
00817        }
00818 
00819        if ( nf->nf_desc ) {
00820               print_literal(ss,"DESC");
00821               print_qdstring(ss,nf->nf_desc);
00822        }
00823 
00824        if ( nf->nf_obsolete ) {
00825               print_literal(ss, "OBSOLETE");
00826               print_whsp(ss);
00827        }
00828 
00829        print_literal(ss,"OC");
00830        print_whsp(ss);
00831        print_woid(ss,nf->nf_objectclass);
00832        print_whsp(ss);
00833 
00834        print_literal(ss,"MUST");
00835        print_whsp(ss);
00836        print_oids(ss,nf->nf_at_oids_must);
00837        print_whsp(ss);
00838 
00839 
00840        if ( nf->nf_at_oids_may ) {
00841               print_literal(ss,"MAY");
00842               print_whsp(ss);
00843               print_oids(ss,nf->nf_at_oids_may);
00844               print_whsp(ss);
00845        }
00846 
00847        print_whsp(ss);
00848        print_extensions(ss, nf->nf_extensions);
00849 
00850        print_literal(ss, /*(*/")");
00851 
00852        bv->bv_val = safe_strdup(ss);
00853        bv->bv_len = ss->pos;
00854        safe_string_free(ss);
00855        return(bv);
00856 }
00857 
00858 char *
00859 ldap_attributetype2str( LDAPAttributeType * at )
00860 {
00861        struct berval bv;
00862        if (ldap_attributetype2bv( at, &bv ))
00863               return(bv.bv_val);
00864        else
00865               return NULL;
00866 }
00867 
00868 struct berval *
00869 ldap_attributetype2bv(  LDAPAttributeType * at, struct berval *bv )
00870 {
00871        safe_string * ss;
00872 
00873        if ( !at || !bv )
00874               return NULL;
00875 
00876        ss = new_safe_string(256);
00877        if ( !ss )
00878               return NULL;
00879 
00880        print_literal(ss,"("/*)*/);
00881        print_whsp(ss);
00882 
00883        print_numericoid(ss, at->at_oid);
00884        print_whsp(ss);
00885 
00886        if ( at->at_names ) {
00887               print_literal(ss,"NAME");
00888               print_qdescrs(ss,at->at_names);
00889        }
00890 
00891        if ( at->at_desc ) {
00892               print_literal(ss,"DESC");
00893               print_qdstring(ss,at->at_desc);
00894        }
00895 
00896        if ( at->at_obsolete ) {
00897               print_literal(ss, "OBSOLETE");
00898               print_whsp(ss);
00899        }
00900 
00901        if ( at->at_sup_oid ) {
00902               print_literal(ss,"SUP");
00903               print_woid(ss,at->at_sup_oid);
00904        }
00905 
00906        if ( at->at_equality_oid ) {
00907               print_literal(ss,"EQUALITY");
00908               print_woid(ss,at->at_equality_oid);
00909        }
00910 
00911        if ( at->at_ordering_oid ) {
00912               print_literal(ss,"ORDERING");
00913               print_woid(ss,at->at_ordering_oid);
00914        }
00915 
00916        if ( at->at_substr_oid ) {
00917               print_literal(ss,"SUBSTR");
00918               print_woid(ss,at->at_substr_oid);
00919        }
00920 
00921        if ( at->at_syntax_oid ) {
00922               print_literal(ss,"SYNTAX");
00923               print_whsp(ss);
00924               print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
00925               print_whsp(ss);
00926        }
00927 
00928        if ( at->at_single_value == LDAP_SCHEMA_YES ) {
00929               print_literal(ss,"SINGLE-VALUE");
00930               print_whsp(ss);
00931        }
00932 
00933        if ( at->at_collective == LDAP_SCHEMA_YES ) {
00934               print_literal(ss,"COLLECTIVE");
00935               print_whsp(ss);
00936        }
00937 
00938        if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
00939               print_literal(ss,"NO-USER-MODIFICATION");
00940               print_whsp(ss);
00941        }
00942 
00943        if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
00944               print_literal(ss,"USAGE");
00945               print_whsp(ss);
00946               switch (at->at_usage) {
00947               case LDAP_SCHEMA_DIRECTORY_OPERATION:
00948                      print_literal(ss,"directoryOperation");
00949                      break;
00950               case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
00951                      print_literal(ss,"distributedOperation");
00952                      break;
00953               case LDAP_SCHEMA_DSA_OPERATION:
00954                      print_literal(ss,"dSAOperation");
00955                      break;
00956               default:
00957                      print_literal(ss,"UNKNOWN");
00958                      break;
00959               }
00960        }
00961        
00962        print_whsp(ss);
00963 
00964        print_extensions(ss, at->at_extensions);
00965 
00966        print_literal(ss,/*(*/")");
00967 
00968        bv->bv_val = safe_strdup(ss);
00969        bv->bv_len = ss->pos;
00970        safe_string_free(ss);
00971        return(bv);
00972 }
00973 
00974 /*
00975  * Now come the parsers.  There is one parser for each entity type:
00976  * objectclasses, attributetypes, etc.
00977  *
00978  * Each of them is written as a recursive-descent parser, except that
00979  * none of them is really recursive.  But the idea is kept: there
00980  * is one routine per non-terminal that eithers gobbles lexical tokens
00981  * or calls lower-level routines, etc.
00982  *
00983  * The scanner is implemented in the routine get_token.  Actually,
00984  * get_token is more than a scanner and will return tokens that are
00985  * in fact non-terminals in the grammar.  So you can see the whole
00986  * approach as the combination of a low-level bottom-up recognizer
00987  * combined with a scanner and a number of top-down parsers.  Or just
00988  * consider that the real grammars recognized by the parsers are not
00989  * those of the standards.  As a matter of fact, our parsers are more
00990  * liberal than the spec when there is no ambiguity.
00991  *
00992  * The difference is pretty academic (modulo bugs or incorrect
00993  * interpretation of the specs).
00994  */
00995 
00996 typedef enum tk_t {
00997        TK_NOENDQUOTE = -2,
00998        TK_OUTOFMEM   = -1,
00999        TK_EOS        = 0,
01000        TK_UNEXPCHAR  = 1,
01001        TK_BAREWORD   = 2,
01002        TK_QDSTRING   = 3,
01003        TK_LEFTPAREN  = 4,
01004        TK_RIGHTPAREN = 5,
01005        TK_DOLLAR     = 6,
01006        TK_QDESCR     = TK_QDSTRING
01007 } tk_t;
01008 
01009 static tk_t
01010 get_token( const char ** sp, char ** token_val )
01011 {
01012        tk_t kind;
01013        const char * p;
01014        const char * q;
01015        char * res;
01016 
01017        *token_val = NULL;
01018        switch (**sp) {
01019        case '\0':
01020               kind = TK_EOS;
01021               (*sp)++;
01022               break;
01023        case '(':
01024               kind = TK_LEFTPAREN;
01025               (*sp)++;
01026               break;
01027        case ')':
01028               kind = TK_RIGHTPAREN;
01029               (*sp)++;
01030               break;
01031        case '$':
01032               kind = TK_DOLLAR;
01033               (*sp)++;
01034               break;
01035        case '\'':
01036               kind = TK_QDSTRING;
01037               (*sp)++;
01038               p = *sp;
01039               while ( **sp != '\'' && **sp != '\0' )
01040                      (*sp)++;
01041               if ( **sp == '\'' ) {
01042                      q = *sp;
01043                      res = LDAP_MALLOC(q-p+1);
01044                      if ( !res ) {
01045                             kind = TK_OUTOFMEM;
01046                      } else {
01047                             strncpy(res,p,q-p);
01048                             res[q-p] = '\0';
01049                             *token_val = res;
01050                      }
01051                      (*sp)++;
01052               } else {
01053                      kind = TK_NOENDQUOTE;
01054               }
01055               break;
01056        default:
01057               kind = TK_BAREWORD;
01058               p = *sp;
01059               while ( !LDAP_SPACE(**sp) &&
01060                      **sp != '(' &&
01061                      **sp != ')' &&
01062                      **sp != '$' &&
01063                      **sp != '\'' &&
01064                      /* for suggested minimum upper bound on the number
01065                       * of characters (RFC 4517) */
01066                      **sp != '{' &&
01067                      **sp != '\0' )
01068                      (*sp)++;
01069               q = *sp;
01070               res = LDAP_MALLOC(q-p+1);
01071               if ( !res ) {
01072                      kind = TK_OUTOFMEM;
01073               } else {
01074                      strncpy(res,p,q-p);
01075                      res[q-p] = '\0';
01076                      *token_val = res;
01077               }
01078               break;
01079 /*            kind = TK_UNEXPCHAR; */
01080 /*            break; */
01081        }
01082        
01083        return kind;
01084 }
01085 
01086 /* Gobble optional whitespace */
01087 static void
01088 parse_whsp(const char **sp)
01089 {
01090        while (LDAP_SPACE(**sp))
01091               (*sp)++;
01092 }
01093 
01094 /* TBC:!!
01095  * General note for all parsers: to guarantee the algorithm halts they
01096  * must always advance the pointer even when an error is found.  For
01097  * this one is not that important since an error here is fatal at the
01098  * upper layers, but it is a simple strategy that will not get in
01099  * endless loops.
01100  */
01101 
01102 /* Parse a sequence of dot-separated decimal strings */
01103 char *
01104 ldap_int_parse_numericoid(const char **sp, int *code, const int flags)
01105 {
01106        char * res = NULL;
01107        const char * start = *sp;
01108        int len;
01109        int quoted = 0;
01110 
01111        /* Netscape puts the SYNTAX value in quotes (incorrectly) */
01112        if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
01113               quoted = 1;
01114               (*sp)++;
01115               start++;
01116        }
01117        /* Each iteration of this loop gets one decimal string */
01118        while (**sp) {
01119               if ( !LDAP_DIGIT(**sp) ) {
01120                      /*
01121                       * Initial char is not a digit or char after dot is
01122                       * not a digit
01123                       */
01124                      *code = LDAP_SCHERR_NODIGIT;
01125                      return NULL;
01126               }
01127               (*sp)++;
01128               while ( LDAP_DIGIT(**sp) )
01129                      (*sp)++;
01130               if ( **sp != '.' )
01131                      break;
01132               /* Otherwise, gobble the dot and loop again */
01133               (*sp)++;
01134        }
01135        /* Now *sp points at the char past the numericoid. Perfect. */
01136        len = *sp - start;
01137        if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
01138               if ( **sp == '\'' ) {
01139                      (*sp)++;
01140               } else {
01141                      *code = LDAP_SCHERR_UNEXPTOKEN;
01142                      return NULL;
01143               }
01144        }
01145        if (flags & LDAP_SCHEMA_SKIP) {
01146               res = (char *)start;
01147        } else {
01148               res = LDAP_MALLOC(len+1);
01149               if (!res) {
01150                      *code = LDAP_SCHERR_OUTOFMEM;
01151                      return(NULL);
01152               }
01153               strncpy(res,start,len);
01154               res[len] = '\0';
01155        }
01156        return(res);
01157 }
01158 
01159 /* Parse a sequence of dot-separated decimal strings */
01160 int
01161 ldap_int_parse_ruleid(const char **sp, int *code, const int flags, int *ruleid)
01162 {
01163        *ruleid=0;
01164 
01165        if ( !LDAP_DIGIT(**sp) ) {
01166               *code = LDAP_SCHERR_NODIGIT;
01167               return -1;
01168        }
01169        *ruleid = (**sp) - '0';
01170        (*sp)++;
01171 
01172        while ( LDAP_DIGIT(**sp) ) {
01173               *ruleid *= 10;
01174               *ruleid += (**sp) - '0';
01175               (*sp)++;
01176        }
01177 
01178        return 0;
01179 }
01180 
01181 /* Parse a qdescr or a list of them enclosed in () */
01182 static char **
01183 parse_qdescrs(const char **sp, int *code)
01184 {
01185        char ** res;
01186        char ** res1;
01187        tk_t kind;
01188        char * sval;
01189        int size;
01190        int pos;
01191 
01192        parse_whsp(sp);
01193        kind = get_token(sp,&sval);
01194        if ( kind == TK_LEFTPAREN ) {
01195               /* Let's presume there will be at least 2 entries */
01196               size = 3;
01197               res = LDAP_CALLOC(3,sizeof(char *));
01198               if ( !res ) {
01199                      *code = LDAP_SCHERR_OUTOFMEM;
01200                      return NULL;
01201               }
01202               pos = 0;
01203               while (1) {
01204                      parse_whsp(sp);
01205                      kind = get_token(sp,&sval);
01206                      if ( kind == TK_RIGHTPAREN )
01207                             break;
01208                      if ( kind == TK_QDESCR ) {
01209                             if ( pos == size-2 ) {
01210                                    size++;
01211                                    res1 = LDAP_REALLOC(res,size*sizeof(char *));
01212                                    if ( !res1 ) {
01213                                           LDAP_VFREE(res);
01214                                           LDAP_FREE(sval);
01215                                           *code = LDAP_SCHERR_OUTOFMEM;
01216                                           return(NULL);
01217                                    }
01218                                    res = res1;
01219                             }
01220                             res[pos++] = sval;
01221                             res[pos] = NULL;
01222                             parse_whsp(sp);
01223                      } else {
01224                             LDAP_VFREE(res);
01225                             LDAP_FREE(sval);
01226                             *code = LDAP_SCHERR_UNEXPTOKEN;
01227                             return(NULL);
01228                      }
01229               }
01230               parse_whsp(sp);
01231               return(res);
01232        } else if ( kind == TK_QDESCR ) {
01233               res = LDAP_CALLOC(2,sizeof(char *));
01234               if ( !res ) {
01235                      *code = LDAP_SCHERR_OUTOFMEM;
01236                      return NULL;
01237               }
01238               res[0] = sval;
01239               res[1] = NULL;
01240               parse_whsp(sp);
01241               return res;
01242        } else {
01243               LDAP_FREE(sval);
01244               *code = LDAP_SCHERR_BADNAME;
01245               return NULL;
01246        }
01247 }
01248 
01249 /* Parse a woid */
01250 static char *
01251 parse_woid(const char **sp, int *code)
01252 {
01253        char * sval;
01254        tk_t kind;
01255 
01256        parse_whsp(sp);
01257        kind = get_token(sp, &sval);
01258        if ( kind != TK_BAREWORD ) {
01259               LDAP_FREE(sval);
01260               *code = LDAP_SCHERR_UNEXPTOKEN;
01261               return NULL;
01262        }
01263        parse_whsp(sp);
01264        return sval;
01265 }
01266 
01267 /* Parse a noidlen */
01268 static char *
01269 parse_noidlen(const char **sp, int *code, int *len, int flags)
01270 {
01271        char * sval;
01272        const char *savepos;
01273        int quoted = 0;
01274        int allow_quoted = ( flags & LDAP_SCHEMA_ALLOW_QUOTED );
01275        int allow_oidmacro = ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO );
01276 
01277        *len = 0;
01278        /* Netscape puts the SYNTAX value in quotes (incorrectly) */
01279        if ( allow_quoted && **sp == '\'' ) {
01280               quoted = 1;
01281               (*sp)++;
01282        }
01283        savepos = *sp;
01284        sval = ldap_int_parse_numericoid(sp, code, 0);
01285        if ( !sval ) {
01286               if ( allow_oidmacro
01287                      && *sp == savepos
01288                      && *code == LDAP_SCHERR_NODIGIT )
01289               {
01290                      if ( get_token(sp, &sval) != TK_BAREWORD ) {
01291                             if ( sval != NULL ) {
01292                                    LDAP_FREE(sval);
01293                             }
01294                             return NULL;
01295                      }
01296               } else {
01297                      return NULL;
01298               }
01299        }
01300        if ( **sp == '{' /*}*/ ) {
01301               (*sp)++;
01302               *len = atoi(*sp);
01303               while ( LDAP_DIGIT(**sp) )
01304                      (*sp)++;
01305               if ( **sp != /*{*/ '}' ) {
01306                      *code = LDAP_SCHERR_UNEXPTOKEN;
01307                      LDAP_FREE(sval);
01308                      return NULL;
01309               }
01310               (*sp)++;
01311        }             
01312        if ( allow_quoted && quoted ) {
01313               if ( **sp == '\'' ) {
01314                      (*sp)++;
01315               } else {
01316                      *code = LDAP_SCHERR_UNEXPTOKEN;
01317                      LDAP_FREE(sval);
01318                      return NULL;
01319               }
01320        }
01321        return sval;
01322 }
01323 
01324 /*
01325  * Next routine will accept a qdstring in place of an oid if
01326  * allow_quoted is set.  This is necessary to interoperate with
01327  * Netscape Directory server that will improperly quote each oid (at
01328  * least those of the descr kind) in the SUP clause.
01329  */
01330 
01331 /* Parse a woid or a $-separated list of them enclosed in () */
01332 static char **
01333 parse_oids(const char **sp, int *code, const int allow_quoted)
01334 {
01335        char ** res;
01336        char ** res1;
01337        tk_t kind;
01338        char * sval;
01339        int size;
01340        int pos;
01341 
01342        /*
01343         * Strictly speaking, doing this here accepts whsp before the
01344         * ( at the begining of an oidlist, but this is harmless.  Also,
01345         * we are very liberal in what we accept as an OID.  Maybe
01346         * refine later.
01347         */
01348        parse_whsp(sp);
01349        kind = get_token(sp,&sval);
01350        if ( kind == TK_LEFTPAREN ) {
01351               /* Let's presume there will be at least 2 entries */
01352               size = 3;
01353               res = LDAP_CALLOC(3,sizeof(char *));
01354               if ( !res ) {
01355                      *code = LDAP_SCHERR_OUTOFMEM;
01356                      return NULL;
01357               }
01358               pos = 0;
01359               parse_whsp(sp);
01360               kind = get_token(sp,&sval);
01361               if ( kind == TK_BAREWORD ||
01362                    ( allow_quoted && kind == TK_QDSTRING ) ) {
01363                      res[pos++] = sval;
01364                      res[pos] = NULL;
01365               } else if ( kind == TK_RIGHTPAREN ) {
01366                      /* FIXME: be liberal in what we accept... */
01367                      parse_whsp(sp);
01368                      LDAP_FREE(res);
01369                      return NULL;
01370               } else {
01371                      *code = LDAP_SCHERR_UNEXPTOKEN;
01372                      LDAP_FREE(sval);
01373                      LDAP_VFREE(res);
01374                      return NULL;
01375               }
01376               parse_whsp(sp);
01377               while (1) {
01378                      kind = get_token(sp,&sval);
01379                      if ( kind == TK_RIGHTPAREN )
01380                             break;
01381                      if ( kind == TK_DOLLAR ) {
01382                             parse_whsp(sp);
01383                             kind = get_token(sp,&sval);
01384                             if ( kind == TK_BAREWORD ||
01385                                  ( allow_quoted &&
01386                                    kind == TK_QDSTRING ) ) {
01387                                    if ( pos == size-2 ) {
01388                                           size++;
01389                                           res1 = LDAP_REALLOC(res,size*sizeof(char *));
01390                                           if ( !res1 ) {
01391                                                  LDAP_FREE(sval);
01392                                                  LDAP_VFREE(res);
01393                                                  *code = LDAP_SCHERR_OUTOFMEM;
01394                                                  return(NULL);
01395                                           }
01396                                           res = res1;
01397                                    }
01398                                    res[pos++] = sval;
01399                                    res[pos] = NULL;
01400                             } else {
01401                                    *code = LDAP_SCHERR_UNEXPTOKEN;
01402                                    LDAP_FREE(sval);
01403                                    LDAP_VFREE(res);
01404                                    return NULL;
01405                             }
01406                             parse_whsp(sp);
01407                      } else {
01408                             *code = LDAP_SCHERR_UNEXPTOKEN;
01409                             LDAP_FREE(sval);
01410                             LDAP_VFREE(res);
01411                             return NULL;
01412                      }
01413               }
01414               parse_whsp(sp);
01415               return(res);
01416        } else if ( kind == TK_BAREWORD ||
01417                   ( allow_quoted && kind == TK_QDSTRING ) ) {
01418               res = LDAP_CALLOC(2,sizeof(char *));
01419               if ( !res ) {
01420                      LDAP_FREE(sval);
01421                      *code = LDAP_SCHERR_OUTOFMEM;
01422                      return NULL;
01423               }
01424               res[0] = sval;
01425               res[1] = NULL;
01426               parse_whsp(sp);
01427               return res;
01428        } else {
01429               LDAP_FREE(sval);
01430               *code = LDAP_SCHERR_BADNAME;
01431               return NULL;
01432        }
01433 }
01434 
01435 static int
01436 add_extension(LDAPSchemaExtensionItem ***extensions,
01437              char * name, char ** values)
01438 {
01439        int n;
01440        LDAPSchemaExtensionItem **tmp, *ext;
01441 
01442        ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
01443        if ( !ext )
01444               return 1;
01445        ext->lsei_name = name;
01446        ext->lsei_values = values;
01447 
01448        if ( !*extensions ) {
01449               *extensions =
01450                 LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
01451               if ( !*extensions ) {
01452                      LDAP_FREE( ext );
01453                      return 1;
01454               }
01455               n = 0;
01456        } else {
01457               for ( n=0; (*extensions)[n] != NULL; n++ )
01458                      ;
01459               tmp = LDAP_REALLOC(*extensions,
01460                                (n+2)*sizeof(LDAPSchemaExtensionItem *));
01461               if ( !tmp ) {
01462                      LDAP_FREE( ext );
01463                      return 1;
01464               }
01465               *extensions = tmp;
01466        }
01467        (*extensions)[n] = ext;
01468        (*extensions)[n+1] = NULL;
01469        return 0;
01470 }
01471 
01472 static void
01473 free_extensions(LDAPSchemaExtensionItem **extensions)
01474 {
01475        LDAPSchemaExtensionItem **ext;
01476 
01477        if ( extensions ) {
01478               for ( ext = extensions; *ext != NULL; ext++ ) {
01479                      LDAP_FREE((*ext)->lsei_name);
01480                      LDAP_VFREE((*ext)->lsei_values);
01481                      LDAP_FREE(*ext);
01482               }
01483               LDAP_FREE(extensions);
01484        }
01485 }
01486 
01487 void
01488 ldap_syntax_free( LDAPSyntax * syn )
01489 {
01490        if ( !syn ) return;
01491        LDAP_FREE(syn->syn_oid);
01492        if (syn->syn_names) LDAP_VFREE(syn->syn_names);
01493        if (syn->syn_desc) LDAP_FREE(syn->syn_desc);
01494        free_extensions(syn->syn_extensions);
01495        LDAP_FREE(syn);
01496 }
01497 
01498 LDAPSyntax *
01499 ldap_str2syntax( LDAP_CONST char * s,
01500        int * code,
01501        LDAP_CONST char ** errp,
01502        LDAP_CONST unsigned flags )
01503 {
01504        tk_t kind;
01505        const char * ss = s;
01506        char * sval;
01507        int seen_name = 0;
01508        int seen_desc = 0;
01509        LDAPSyntax * syn;
01510        char ** ext_vals;
01511 
01512        if ( !s ) {
01513               *code = LDAP_SCHERR_EMPTY;
01514               *errp = "";
01515               return NULL;
01516        }
01517 
01518        *errp = s;
01519        syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
01520 
01521        if ( !syn ) {
01522               *code = LDAP_SCHERR_OUTOFMEM;
01523               return NULL;
01524        }
01525 
01526        kind = get_token(&ss,&sval);
01527        if ( kind != TK_LEFTPAREN ) {
01528               LDAP_FREE(sval);
01529               *code = LDAP_SCHERR_NOLEFTPAREN;
01530               ldap_syntax_free(syn);
01531               return NULL;
01532        }
01533 
01534        parse_whsp(&ss);
01535        syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0);
01536        if ( !syn->syn_oid ) {
01537               *errp = ss;
01538               ldap_syntax_free(syn);
01539               return NULL;
01540        }
01541        parse_whsp(&ss);
01542 
01543        /*
01544         * Beyond this point we will be liberal and accept the items
01545         * in any order.
01546         */
01547        while (1) {
01548               kind = get_token(&ss,&sval);
01549               switch (kind) {
01550               case TK_EOS:
01551                      *code = LDAP_SCHERR_NORIGHTPAREN;
01552                      *errp = EndOfInput;
01553                      ldap_syntax_free(syn);
01554                      return NULL;
01555               case TK_RIGHTPAREN:
01556                      return syn;
01557               case TK_BAREWORD:
01558                      if ( !strcasecmp(sval,"NAME") ) {
01559                             LDAP_FREE(sval);
01560                             if ( seen_name ) {
01561                                    *code = LDAP_SCHERR_DUPOPT;
01562                                    *errp = ss;
01563                                    ldap_syntax_free(syn);
01564                                    return(NULL);
01565                             }
01566                             seen_name = 1;
01567                             syn->syn_names = parse_qdescrs(&ss,code);
01568                             if ( !syn->syn_names ) {
01569                                    if ( *code != LDAP_SCHERR_OUTOFMEM )
01570                                           *code = LDAP_SCHERR_BADNAME;
01571                                    *errp = ss;
01572                                    ldap_syntax_free(syn);
01573                                    return NULL;
01574                             }
01575                      } else if ( !strcasecmp(sval,"DESC") ) {
01576                             LDAP_FREE(sval);
01577                             if ( seen_desc ) {
01578                                    *code = LDAP_SCHERR_DUPOPT;
01579                                    *errp = ss;
01580                                    ldap_syntax_free(syn);
01581                                    return(NULL);
01582                             }
01583                             seen_desc = 1;
01584                             parse_whsp(&ss);
01585                             kind = get_token(&ss,&sval);
01586                             if ( kind != TK_QDSTRING ) {
01587                                    *code = LDAP_SCHERR_UNEXPTOKEN;
01588                                    *errp = ss;
01589                                    LDAP_FREE(sval);
01590                                    ldap_syntax_free(syn);
01591                                    return NULL;
01592                             }
01593                             syn->syn_desc = sval;
01594                             parse_whsp(&ss);
01595                      } else if ( sval[0] == 'X' && sval[1] == '-' ) {
01596                             /* Should be parse_qdstrings */
01597                             ext_vals = parse_qdescrs(&ss, code);
01598                             if ( !ext_vals ) {
01599                                    *errp = ss;
01600                                    ldap_syntax_free(syn);
01601                                    return NULL;
01602                             }
01603                             if ( add_extension(&syn->syn_extensions,
01604                                               sval, ext_vals) ) {
01605                                    *code = LDAP_SCHERR_OUTOFMEM;
01606                                    *errp = ss;
01607                                    LDAP_FREE(sval);
01608                                    ldap_syntax_free(syn);
01609                                    return NULL;
01610                             }
01611                      } else {
01612                             *code = LDAP_SCHERR_UNEXPTOKEN;
01613                             *errp = ss;
01614                             LDAP_FREE(sval);
01615                             ldap_syntax_free(syn);
01616                             return NULL;
01617                      }
01618                      break;
01619               default:
01620                      *code = LDAP_SCHERR_UNEXPTOKEN;
01621                      *errp = ss;
01622                      LDAP_FREE(sval);
01623                      ldap_syntax_free(syn);
01624                      return NULL;
01625               }
01626        }
01627 }
01628 
01629 void
01630 ldap_matchingrule_free( LDAPMatchingRule * mr )
01631 {
01632        if (!mr) return;
01633        LDAP_FREE(mr->mr_oid);
01634        if (mr->mr_names) LDAP_VFREE(mr->mr_names);
01635        if (mr->mr_desc) LDAP_FREE(mr->mr_desc);
01636        if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid);
01637        free_extensions(mr->mr_extensions);
01638        LDAP_FREE(mr);
01639 }
01640 
01641 LDAPMatchingRule *
01642 ldap_str2matchingrule( LDAP_CONST char * s,
01643        int * code,
01644        LDAP_CONST char ** errp,
01645        LDAP_CONST unsigned flags )
01646 {
01647        tk_t kind;
01648        const char * ss = s;
01649        char * sval;
01650        int seen_name = 0;
01651        int seen_desc = 0;
01652        int seen_obsolete = 0;
01653        int seen_syntax = 0;
01654        LDAPMatchingRule * mr;
01655        char ** ext_vals;
01656        const char * savepos;
01657 
01658        if ( !s ) {
01659               *code = LDAP_SCHERR_EMPTY;
01660               *errp = "";
01661               return NULL;
01662        }
01663 
01664        *errp = s;
01665        mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
01666 
01667        if ( !mr ) {
01668               *code = LDAP_SCHERR_OUTOFMEM;
01669               return NULL;
01670        }
01671 
01672        kind = get_token(&ss,&sval);
01673        if ( kind != TK_LEFTPAREN ) {
01674               *code = LDAP_SCHERR_NOLEFTPAREN;
01675               LDAP_FREE(sval);
01676               ldap_matchingrule_free(mr);
01677               return NULL;
01678        }
01679 
01680        parse_whsp(&ss);
01681        savepos = ss;
01682        mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags);
01683        if ( !mr->mr_oid ) {
01684               if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
01685                      /* Backtracking */
01686                      ss = savepos;
01687                      kind = get_token(&ss,&sval);
01688                      if ( kind == TK_BAREWORD ) {
01689                             if ( !strcasecmp(sval, "NAME") ||
01690                                  !strcasecmp(sval, "DESC") ||
01691                                  !strcasecmp(sval, "OBSOLETE") ||
01692                                  !strcasecmp(sval, "SYNTAX") ||
01693                                  !strncasecmp(sval, "X-", 2) ) {
01694                                    /* Missing OID, backtrack */
01695                                    ss = savepos;
01696                             } else {
01697                                    /* Non-numerical OID, ignore */
01698                             }
01699                      }
01700                      LDAP_FREE(sval);
01701               } else {
01702                      *errp = ss;
01703                      ldap_matchingrule_free(mr);
01704                      return NULL;
01705               }
01706        }
01707        parse_whsp(&ss);
01708 
01709        /*
01710         * Beyond this point we will be liberal and accept the items
01711         * in any order.
01712         */
01713        while (1) {
01714               kind = get_token(&ss,&sval);
01715               switch (kind) {
01716               case TK_EOS:
01717                      *code = LDAP_SCHERR_NORIGHTPAREN;
01718                      *errp = EndOfInput;
01719                      ldap_matchingrule_free(mr);
01720                      return NULL;
01721               case TK_RIGHTPAREN:
01722                      if( !seen_syntax ) {
01723                             *code = LDAP_SCHERR_MISSING;
01724                             ldap_matchingrule_free(mr);
01725                             return NULL;
01726                      }
01727                      return mr;
01728               case TK_BAREWORD:
01729                      if ( !strcasecmp(sval,"NAME") ) {
01730                             LDAP_FREE(sval);
01731                             if ( seen_name ) {
01732                                    *code = LDAP_SCHERR_DUPOPT;
01733                                    *errp = ss;
01734                                    ldap_matchingrule_free(mr);
01735                                    return(NULL);
01736                             }
01737                             seen_name = 1;
01738                             mr->mr_names = parse_qdescrs(&ss,code);
01739                             if ( !mr->mr_names ) {
01740                                    if ( *code != LDAP_SCHERR_OUTOFMEM )
01741                                           *code = LDAP_SCHERR_BADNAME;
01742                                    *errp = ss;
01743                                    ldap_matchingrule_free(mr);
01744                                    return NULL;
01745                             }
01746                      } else if ( !strcasecmp(sval,"DESC") ) {
01747                             LDAP_FREE(sval);
01748                             if ( seen_desc ) {
01749                                    *code = LDAP_SCHERR_DUPOPT;
01750                                    *errp = ss;
01751                                    ldap_matchingrule_free(mr);
01752                                    return(NULL);
01753                             }
01754                             seen_desc = 1;
01755                             parse_whsp(&ss);
01756                             kind = get_token(&ss,&sval);
01757                             if ( kind != TK_QDSTRING ) {
01758                                    *code = LDAP_SCHERR_UNEXPTOKEN;
01759                                    *errp = ss;
01760                                    LDAP_FREE(sval);
01761                                    ldap_matchingrule_free(mr);
01762                                    return NULL;
01763                             }
01764                             mr->mr_desc = sval;
01765                             parse_whsp(&ss);
01766                      } else if ( !strcasecmp(sval,"OBSOLETE") ) {
01767                             LDAP_FREE(sval);
01768                             if ( seen_obsolete ) {
01769                                    *code = LDAP_SCHERR_DUPOPT;
01770                                    *errp = ss;
01771                                    ldap_matchingrule_free(mr);
01772                                    return(NULL);
01773                             }
01774                             seen_obsolete = 1;
01775                             mr->mr_obsolete = LDAP_SCHEMA_YES;
01776                             parse_whsp(&ss);
01777                      } else if ( !strcasecmp(sval,"SYNTAX") ) {
01778                             LDAP_FREE(sval);
01779                             if ( seen_syntax ) {
01780                                    *code = LDAP_SCHERR_DUPOPT;
01781                                    *errp = ss;
01782                                    ldap_matchingrule_free(mr);
01783                                    return(NULL);
01784                             }
01785                             seen_syntax = 1;
01786                             parse_whsp(&ss);
01787                             mr->mr_syntax_oid =
01788                                    ldap_int_parse_numericoid(&ss,code,flags);
01789                             if ( !mr->mr_syntax_oid ) {
01790                                    *errp = ss;
01791                                    ldap_matchingrule_free(mr);
01792                                    return NULL;
01793                             }
01794                             parse_whsp(&ss);
01795                      } else if ( sval[0] == 'X' && sval[1] == '-' ) {
01796                             /* Should be parse_qdstrings */
01797                             ext_vals = parse_qdescrs(&ss, code);
01798                             if ( !ext_vals ) {
01799                                    *errp = ss;
01800                                    ldap_matchingrule_free(mr);
01801                                    return NULL;
01802                             }
01803                             if ( add_extension(&mr->mr_extensions,
01804                                               sval, ext_vals) ) {
01805                                    *code = LDAP_SCHERR_OUTOFMEM;
01806                                    *errp = ss;
01807                                    LDAP_FREE(sval);
01808                                    ldap_matchingrule_free(mr);
01809                                    return NULL;
01810                             }
01811                      } else {
01812                             *code = LDAP_SCHERR_UNEXPTOKEN;
01813                             *errp = ss;
01814                             LDAP_FREE(sval);
01815                             ldap_matchingrule_free(mr);
01816                             return NULL;
01817                      }
01818                      break;
01819               default:
01820                      *code = LDAP_SCHERR_UNEXPTOKEN;
01821                      *errp = ss;
01822                      LDAP_FREE(sval);
01823                      ldap_matchingrule_free(mr);
01824                      return NULL;
01825               }
01826        }
01827 }
01828 
01829 void
01830 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
01831 {
01832        if (!mru) return;
01833        LDAP_FREE(mru->mru_oid);
01834        if (mru->mru_names) LDAP_VFREE(mru->mru_names);
01835        if (mru->mru_desc) LDAP_FREE(mru->mru_desc);
01836        if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids);
01837        free_extensions(mru->mru_extensions);
01838        LDAP_FREE(mru);
01839 }
01840 
01841 LDAPMatchingRuleUse *
01842 ldap_str2matchingruleuse( LDAP_CONST char * s,
01843        int * code,
01844        LDAP_CONST char ** errp,
01845        LDAP_CONST unsigned flags )
01846 {
01847        tk_t kind;
01848        const char * ss = s;
01849        char * sval;
01850        int seen_name = 0;
01851        int seen_desc = 0;
01852        int seen_obsolete = 0;
01853        int seen_applies = 0;
01854        LDAPMatchingRuleUse * mru;
01855        char ** ext_vals;
01856        const char * savepos;
01857 
01858        if ( !s ) {
01859               *code = LDAP_SCHERR_EMPTY;
01860               *errp = "";
01861               return NULL;
01862        }
01863 
01864        *errp = s;
01865        mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
01866 
01867        if ( !mru ) {
01868               *code = LDAP_SCHERR_OUTOFMEM;
01869               return NULL;
01870        }
01871 
01872        kind = get_token(&ss,&sval);
01873        if ( kind != TK_LEFTPAREN ) {
01874               *code = LDAP_SCHERR_NOLEFTPAREN;
01875               LDAP_FREE(sval);
01876               ldap_matchingruleuse_free(mru);
01877               return NULL;
01878        }
01879 
01880        parse_whsp(&ss);
01881        savepos = ss;
01882        mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags);
01883        if ( !mru->mru_oid ) {
01884               if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
01885                      /* Backtracking */
01886                      ss = savepos;
01887                      kind = get_token(&ss,&sval);
01888                      if ( kind == TK_BAREWORD ) {
01889                             if ( !strcasecmp(sval, "NAME") ||
01890                                  !strcasecmp(sval, "DESC") ||
01891                                  !strcasecmp(sval, "OBSOLETE") ||
01892                                  !strcasecmp(sval, "APPLIES") ||
01893                                  !strncasecmp(sval, "X-", 2) ) {
01894                                    /* Missing OID, backtrack */
01895                                    ss = savepos;
01896                             } else {
01897                                    /* Non-numerical OID, ignore */
01898                             }
01899                      }
01900                      LDAP_FREE(sval);
01901               } else {
01902                      *errp = ss;
01903                      ldap_matchingruleuse_free(mru);
01904                      return NULL;
01905               }
01906        }
01907        parse_whsp(&ss);
01908 
01909        /*
01910         * Beyond this point we will be liberal and accept the items
01911         * in any order.
01912         */
01913        while (1) {
01914               kind = get_token(&ss,&sval);
01915               switch (kind) {
01916               case TK_EOS:
01917                      *code = LDAP_SCHERR_NORIGHTPAREN;
01918                      *errp = EndOfInput;
01919                      ldap_matchingruleuse_free(mru);
01920                      return NULL;
01921               case TK_RIGHTPAREN:
01922                      if( !seen_applies ) {
01923                             *code = LDAP_SCHERR_MISSING;
01924                             ldap_matchingruleuse_free(mru);
01925                             return NULL;
01926                      }
01927                      return mru;
01928               case TK_BAREWORD:
01929                      if ( !strcasecmp(sval,"NAME") ) {
01930                             LDAP_FREE(sval);
01931                             if ( seen_name ) {
01932                                    *code = LDAP_SCHERR_DUPOPT;
01933                                    *errp = ss;
01934                                    ldap_matchingruleuse_free(mru);
01935                                    return(NULL);
01936                             }
01937                             seen_name = 1;
01938                             mru->mru_names = parse_qdescrs(&ss,code);
01939                             if ( !mru->mru_names ) {
01940                                    if ( *code != LDAP_SCHERR_OUTOFMEM )
01941                                           *code = LDAP_SCHERR_BADNAME;
01942                                    *errp = ss;
01943                                    ldap_matchingruleuse_free(mru);
01944                                    return NULL;
01945                             }
01946                      } else if ( !strcasecmp(sval,"DESC") ) {
01947                             LDAP_FREE(sval);
01948                             if ( seen_desc ) {
01949                                    *code = LDAP_SCHERR_DUPOPT;
01950                                    *errp = ss;
01951                                    ldap_matchingruleuse_free(mru);
01952                                    return(NULL);
01953                             }
01954                             seen_desc = 1;
01955                             parse_whsp(&ss);
01956                             kind = get_token(&ss,&sval);
01957                             if ( kind != TK_QDSTRING ) {
01958                                    *code = LDAP_SCHERR_UNEXPTOKEN;
01959                                    *errp = ss;
01960                                    LDAP_FREE(sval);
01961                                    ldap_matchingruleuse_free(mru);
01962                                    return NULL;
01963                             }
01964                             mru->mru_desc = sval;
01965                             parse_whsp(&ss);
01966                      } else if ( !strcasecmp(sval,"OBSOLETE") ) {
01967                             LDAP_FREE(sval);
01968                             if ( seen_obsolete ) {
01969                                    *code = LDAP_SCHERR_DUPOPT;
01970                                    *errp = ss;
01971                                    ldap_matchingruleuse_free(mru);
01972                                    return(NULL);
01973                             }
01974                             seen_obsolete = 1;
01975                             mru->mru_obsolete = LDAP_SCHEMA_YES;
01976                             parse_whsp(&ss);
01977                      } else if ( !strcasecmp(sval,"APPLIES") ) {
01978                             LDAP_FREE(sval);
01979                             if ( seen_applies ) {
01980                                    *code = LDAP_SCHERR_DUPOPT;
01981                                    *errp = ss;
01982                                    ldap_matchingruleuse_free(mru);
01983                                    return(NULL);
01984                             }
01985                             seen_applies = 1;
01986                             mru->mru_applies_oids = parse_oids(&ss,
01987                                                       code,
01988                                                       flags);
01989                             if ( !mru->mru_applies_oids && *code != LDAP_SUCCESS ) {
01990                                    *errp = ss;
01991                                    ldap_matchingruleuse_free(mru);
01992                                    return NULL;
01993                             }
01994                      } else if ( sval[0] == 'X' && sval[1] == '-' ) {
01995                             /* Should be parse_qdstrings */
01996                             ext_vals = parse_qdescrs(&ss, code);
01997                             if ( !ext_vals ) {
01998                                    *errp = ss;
01999                                    ldap_matchingruleuse_free(mru);
02000                                    return NULL;
02001                             }
02002                             if ( add_extension(&mru->mru_extensions,
02003                                               sval, ext_vals) ) {
02004                                    *code = LDAP_SCHERR_OUTOFMEM;
02005                                    *errp = ss;
02006                                    LDAP_FREE(sval);
02007                                    ldap_matchingruleuse_free(mru);
02008                                    return NULL;
02009                             }
02010                      } else {
02011                             *code = LDAP_SCHERR_UNEXPTOKEN;
02012                             *errp = ss;
02013                             LDAP_FREE(sval);
02014                             ldap_matchingruleuse_free(mru);
02015                             return NULL;
02016                      }
02017                      break;
02018               default:
02019                      *code = LDAP_SCHERR_UNEXPTOKEN;
02020                      *errp = ss;
02021                      LDAP_FREE(sval);
02022                      ldap_matchingruleuse_free(mru);
02023                      return NULL;
02024               }
02025        }
02026 }
02027 
02028 void
02029 ldap_attributetype_free(LDAPAttributeType * at)
02030 {
02031        if (!at) return;
02032        LDAP_FREE(at->at_oid);
02033        if (at->at_names) LDAP_VFREE(at->at_names);
02034        if (at->at_desc) LDAP_FREE(at->at_desc);
02035        if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid);
02036        if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid);
02037        if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid);
02038        if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid);
02039        if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid);
02040        free_extensions(at->at_extensions);
02041        LDAP_FREE(at);
02042 }
02043 
02044 LDAPAttributeType *
02045 ldap_str2attributetype( LDAP_CONST char * s,
02046        int * code,
02047        LDAP_CONST char ** errp,
02048        LDAP_CONST unsigned flags )
02049 {
02050        tk_t kind;
02051        const char * ss = s;
02052        char * sval;
02053        int seen_name = 0;
02054        int seen_desc = 0;
02055        int seen_obsolete = 0;
02056        int seen_sup = 0;
02057        int seen_equality = 0;
02058        int seen_ordering = 0;
02059        int seen_substr = 0;
02060        int seen_syntax = 0;
02061        int seen_usage = 0;
02062        LDAPAttributeType * at;
02063        char ** ext_vals;
02064        const char * savepos;
02065 
02066        if ( !s ) {
02067               *code = LDAP_SCHERR_EMPTY;
02068               *errp = "";
02069               return NULL;
02070        }
02071 
02072        *errp = s;
02073        at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
02074 
02075        if ( !at ) {
02076               *code = LDAP_SCHERR_OUTOFMEM;
02077               return NULL;
02078        }
02079 
02080        kind = get_token(&ss,&sval);
02081        if ( kind != TK_LEFTPAREN ) {
02082               *code = LDAP_SCHERR_NOLEFTPAREN;
02083               LDAP_FREE(sval);
02084               ldap_attributetype_free(at);
02085               return NULL;
02086        }
02087 
02088        /*
02089         * Definitions MUST begin with an OID in the numericoid format.
02090         * However, this routine is used by clients to parse the response
02091         * from servers and very well known servers will provide an OID
02092         * in the wrong format or even no OID at all.  We do our best to
02093         * extract info from those servers.
02094         */
02095        parse_whsp(&ss);
02096        savepos = ss;
02097        at->at_oid = ldap_int_parse_numericoid(&ss,code,0);
02098        if ( !at->at_oid ) {
02099               if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
02100                             | LDAP_SCHEMA_ALLOW_OID_MACRO ) )
02101                          && (ss == savepos) )
02102               {
02103                      /* Backtracking */
02104                      ss = savepos;
02105                      kind = get_token(&ss,&sval);
02106                      if ( kind == TK_BAREWORD ) {
02107                             if ( !strcasecmp(sval, "NAME") ||
02108                                  !strcasecmp(sval, "DESC") ||
02109                                  !strcasecmp(sval, "OBSOLETE") ||
02110                                  !strcasecmp(sval, "SUP") ||
02111                                  !strcasecmp(sval, "EQUALITY") ||
02112                                  !strcasecmp(sval, "ORDERING") ||
02113                                  !strcasecmp(sval, "SUBSTR") ||
02114                                  !strcasecmp(sval, "SYNTAX") ||
02115                                  !strcasecmp(sval, "SINGLE-VALUE") ||
02116                                  !strcasecmp(sval, "COLLECTIVE") ||
02117                                  !strcasecmp(sval, "NO-USER-MODIFICATION") ||
02118                                  !strcasecmp(sval, "USAGE") ||
02119                                  !strncasecmp(sval, "X-", 2) )
02120                             {
02121                                    /* Missing OID, backtrack */
02122                                    ss = savepos;
02123                             } else if ( flags
02124                                    & LDAP_SCHEMA_ALLOW_OID_MACRO)
02125                             {
02126                                    /* Non-numerical OID ... */
02127                                    int len = ss-savepos;
02128                                    at->at_oid = LDAP_MALLOC(len+1);
02129                                    strncpy(at->at_oid, savepos, len);
02130                                    at->at_oid[len] = 0;
02131                             }
02132                      }
02133                      LDAP_FREE(sval);
02134               } else {
02135                      *errp = ss;
02136                      ldap_attributetype_free(at);
02137                      return NULL;
02138               }
02139        }
02140        parse_whsp(&ss);
02141 
02142        /*
02143         * Beyond this point we will be liberal and accept the items
02144         * in any order.
02145         */
02146        while (1) {
02147               kind = get_token(&ss,&sval);
02148               switch (kind) {
02149               case TK_EOS:
02150                      *code = LDAP_SCHERR_NORIGHTPAREN;
02151                      *errp = EndOfInput;
02152                      ldap_attributetype_free(at);
02153                      return NULL;
02154               case TK_RIGHTPAREN:
02155                      return at;
02156               case TK_BAREWORD:
02157                      if ( !strcasecmp(sval,"NAME") ) {
02158                             LDAP_FREE(sval);
02159                             if ( seen_name ) {
02160                                    *code = LDAP_SCHERR_DUPOPT;
02161                                    *errp = ss;
02162                                    ldap_attributetype_free(at);
02163                                    return(NULL);
02164                             }
02165                             seen_name = 1;
02166                             at->at_names = parse_qdescrs(&ss,code);
02167                             if ( !at->at_names ) {
02168                                    if ( *code != LDAP_SCHERR_OUTOFMEM )
02169                                           *code = LDAP_SCHERR_BADNAME;
02170                                    *errp = ss;
02171                                    ldap_attributetype_free(at);
02172                                    return NULL;
02173                             }
02174                      } else if ( !strcasecmp(sval,"DESC") ) {
02175                             LDAP_FREE(sval);
02176                             if ( seen_desc ) {
02177                                    *code = LDAP_SCHERR_DUPOPT;
02178                                    *errp = ss;
02179                                    ldap_attributetype_free(at);
02180                                    return(NULL);
02181                             }
02182                             seen_desc = 1;
02183                             parse_whsp(&ss);
02184                             kind = get_token(&ss,&sval);
02185                             if ( kind != TK_QDSTRING ) {
02186                                    *code = LDAP_SCHERR_UNEXPTOKEN;
02187                                    *errp = ss;
02188                                    LDAP_FREE(sval);
02189                                    ldap_attributetype_free(at);
02190                                    return NULL;
02191                             }
02192                             at->at_desc = sval;
02193                             parse_whsp(&ss);
02194                      } else if ( !strcasecmp(sval,"OBSOLETE") ) {
02195                             LDAP_FREE(sval);
02196                             if ( seen_obsolete ) {
02197                                    *code = LDAP_SCHERR_DUPOPT;
02198                                    *errp = ss;
02199                                    ldap_attributetype_free(at);
02200                                    return(NULL);
02201                             }
02202                             seen_obsolete = 1;
02203                             at->at_obsolete = LDAP_SCHEMA_YES;
02204                             parse_whsp(&ss);
02205                      } else if ( !strcasecmp(sval,"SUP") ) {
02206                             LDAP_FREE(sval);
02207                             if ( seen_sup ) {
02208                                    *code = LDAP_SCHERR_DUPOPT;
02209                                    *errp = ss;
02210                                    ldap_attributetype_free(at);
02211                                    return(NULL);
02212                             }
02213                             seen_sup = 1;
02214                             at->at_sup_oid = parse_woid(&ss,code);
02215                             if ( !at->at_sup_oid ) {
02216                                    *errp = ss;
02217                                    ldap_attributetype_free(at);
02218                                    return NULL;
02219                             }
02220                      } else if ( !strcasecmp(sval,"EQUALITY") ) {
02221                             LDAP_FREE(sval);
02222                             if ( seen_equality ) {
02223                                    *code = LDAP_SCHERR_DUPOPT;
02224                                    *errp = ss;
02225                                    ldap_attributetype_free(at);
02226                                    return(NULL);
02227                             }
02228                             seen_equality = 1;
02229                             at->at_equality_oid = parse_woid(&ss,code);
02230                             if ( !at->at_equality_oid ) {
02231                                    *errp = ss;
02232                                    ldap_attributetype_free(at);
02233                                    return NULL;
02234                             }
02235                      } else if ( !strcasecmp(sval,"ORDERING") ) {
02236                             LDAP_FREE(sval);
02237                             if ( seen_ordering ) {
02238                                    *code = LDAP_SCHERR_DUPOPT;
02239                                    *errp = ss;
02240                                    ldap_attributetype_free(at);
02241                                    return(NULL);
02242                             }
02243                             seen_ordering = 1;
02244                             at->at_ordering_oid = parse_woid(&ss,code);
02245                             if ( !at->at_ordering_oid ) {
02246                                    *errp = ss;
02247                                    ldap_attributetype_free(at);
02248                                    return NULL;
02249                             }
02250                      } else if ( !strcasecmp(sval,"SUBSTR") ) {
02251                             LDAP_FREE(sval);
02252                             if ( seen_substr ) {
02253                                    *code = LDAP_SCHERR_DUPOPT;
02254                                    *errp = ss;
02255                                    ldap_attributetype_free(at);
02256                                    return(NULL);
02257                             }
02258                             seen_substr = 1;
02259                             at->at_substr_oid = parse_woid(&ss,code);
02260                             if ( !at->at_substr_oid ) {
02261                                    *errp = ss;
02262                                    ldap_attributetype_free(at);
02263                                    return NULL;
02264                             }
02265                      } else if ( !strcasecmp(sval,"SYNTAX") ) {
02266                             LDAP_FREE(sval);
02267                             if ( seen_syntax ) {
02268                                    *code = LDAP_SCHERR_DUPOPT;
02269                                    *errp = ss;
02270                                    ldap_attributetype_free(at);
02271                                    return(NULL);
02272                             }
02273                             seen_syntax = 1;
02274                             parse_whsp(&ss);
02275                             savepos = ss;
02276                             at->at_syntax_oid =
02277                                    parse_noidlen(&ss,
02278                                                 code,
02279                                                 &at->at_syntax_len,
02280                                                 flags);
02281                             if ( !at->at_syntax_oid ) {
02282                                 if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
02283                                    kind = get_token(&ss,&sval);
02284                                    if (kind == TK_BAREWORD)
02285                                    {
02286                                        char *sp = strchr(sval, '{');
02287                                        at->at_syntax_oid = sval;
02288                                        if (sp)
02289                                        {
02290                                           *sp++ = 0;
02291                                           at->at_syntax_len = atoi(sp);
02292                                           while ( LDAP_DIGIT(*sp) )
02293                                                  sp++;
02294                                           if ( *sp != '}' ) {
02295                                               *code = LDAP_SCHERR_UNEXPTOKEN;
02296                                               *errp = ss;
02297                                               ldap_attributetype_free(at);
02298                                               return NULL;
02299                                           }
02300                                        }
02301                                    }
02302                                 } else {
02303                                    *errp = ss;
02304                                    ldap_attributetype_free(at);
02305                                    return NULL;
02306                                 }
02307                             }
02308                             parse_whsp(&ss);
02309                      } else if ( !strcasecmp(sval,"SINGLE-VALUE") ) {
02310                             LDAP_FREE(sval);
02311                             if ( at->at_single_value ) {
02312                                    *code = LDAP_SCHERR_DUPOPT;
02313                                    *errp = ss;
02314                                    ldap_attributetype_free(at);
02315                                    return(NULL);
02316                             }
02317                             at->at_single_value = LDAP_SCHEMA_YES;
02318                             parse_whsp(&ss);
02319                      } else if ( !strcasecmp(sval,"COLLECTIVE") ) {
02320                             LDAP_FREE(sval);
02321                             if ( at->at_collective ) {
02322                                    *code = LDAP_SCHERR_DUPOPT;
02323                                    *errp = ss;
02324                                    ldap_attributetype_free(at);
02325                                    return(NULL);
02326                             }
02327                             at->at_collective = LDAP_SCHEMA_YES;
02328                             parse_whsp(&ss);
02329                      } else if ( !strcasecmp(sval,"NO-USER-MODIFICATION") ) {
02330                             LDAP_FREE(sval);
02331                             if ( at->at_no_user_mod ) {
02332                                    *code = LDAP_SCHERR_DUPOPT;
02333                                    *errp = ss;
02334                                    ldap_attributetype_free(at);
02335                                    return(NULL);
02336                             }
02337                             at->at_no_user_mod = LDAP_SCHEMA_YES;
02338                             parse_whsp(&ss);
02339                      } else if ( !strcasecmp(sval,"USAGE") ) {
02340                             LDAP_FREE(sval);
02341                             if ( seen_usage ) {
02342                                    *code = LDAP_SCHERR_DUPOPT;
02343                                    *errp = ss;
02344                                    ldap_attributetype_free(at);
02345                                    return(NULL);
02346                             }
02347                             seen_usage = 1;
02348                             parse_whsp(&ss);
02349                             kind = get_token(&ss,&sval);
02350                             if ( kind != TK_BAREWORD ) {
02351                                    *code = LDAP_SCHERR_UNEXPTOKEN;
02352                                    *errp = ss;
02353                                    LDAP_FREE(sval);
02354                                    ldap_attributetype_free(at);
02355                                    return NULL;
02356                             }
02357                             if ( !strcasecmp(sval,"userApplications") )
02358                                    at->at_usage =
02359                                        LDAP_SCHEMA_USER_APPLICATIONS;
02360                             else if ( !strcasecmp(sval,"directoryOperation") )
02361                                    at->at_usage =
02362                                        LDAP_SCHEMA_DIRECTORY_OPERATION;
02363                             else if ( !strcasecmp(sval,"distributedOperation") )
02364                                    at->at_usage =
02365                                        LDAP_SCHEMA_DISTRIBUTED_OPERATION;
02366                             else if ( !strcasecmp(sval,"dSAOperation") )
02367                                    at->at_usage =
02368                                        LDAP_SCHEMA_DSA_OPERATION;
02369                             else {
02370                                    *code = LDAP_SCHERR_UNEXPTOKEN;
02371                                    *errp = ss;
02372                                    LDAP_FREE(sval);
02373                                    ldap_attributetype_free(at);
02374                                    return NULL;
02375                             }
02376                             LDAP_FREE(sval);
02377                             parse_whsp(&ss);
02378                      } else if ( sval[0] == 'X' && sval[1] == '-' ) {
02379                             /* Should be parse_qdstrings */
02380                             ext_vals = parse_qdescrs(&ss, code);
02381                             if ( !ext_vals ) {
02382                                    *errp = ss;
02383                                    ldap_attributetype_free(at);
02384                                    return NULL;
02385                             }
02386                             if ( add_extension(&at->at_extensions,
02387                                               sval, ext_vals) ) {
02388                                    *code = LDAP_SCHERR_OUTOFMEM;
02389                                    *errp = ss;
02390                                    LDAP_FREE(sval);
02391                                    ldap_attributetype_free(at);
02392                                    return NULL;
02393                             }
02394                      } else {
02395                             *code = LDAP_SCHERR_UNEXPTOKEN;
02396                             *errp = ss;
02397                             LDAP_FREE(sval);
02398                             ldap_attributetype_free(at);
02399                             return NULL;
02400                      }
02401                      break;
02402               default:
02403                      *code = LDAP_SCHERR_UNEXPTOKEN;
02404                      *errp = ss;
02405                      LDAP_FREE(sval);
02406                      ldap_attributetype_free(at);
02407                      return NULL;
02408               }
02409        }
02410 }
02411 
02412 void
02413 ldap_objectclass_free(LDAPObjectClass * oc)
02414 {
02415        if (!oc) return;
02416        LDAP_FREE(oc->oc_oid);
02417        if (oc->oc_names) LDAP_VFREE(oc->oc_names);
02418        if (oc->oc_desc) LDAP_FREE(oc->oc_desc);
02419        if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids);
02420        if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must);
02421        if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may);
02422        free_extensions(oc->oc_extensions);
02423        LDAP_FREE(oc);
02424 }
02425 
02426 LDAPObjectClass *
02427 ldap_str2objectclass( LDAP_CONST char * s,
02428        int * code,
02429        LDAP_CONST char ** errp,
02430        LDAP_CONST unsigned flags )
02431 {
02432        tk_t kind;
02433        const char * ss = s;
02434        char * sval;
02435        int seen_name = 0;
02436        int seen_desc = 0;
02437        int seen_obsolete = 0;
02438        int seen_sup = 0;
02439        int seen_kind = 0;
02440        int seen_must = 0;
02441        int seen_may = 0;
02442        LDAPObjectClass * oc;
02443        char ** ext_vals;
02444        const char * savepos;
02445 
02446        if ( !s ) {
02447               *code = LDAP_SCHERR_EMPTY;
02448               *errp = "";
02449               return NULL;
02450        }
02451 
02452        *errp = s;
02453        oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
02454 
02455        if ( !oc ) {
02456               *code = LDAP_SCHERR_OUTOFMEM;
02457               return NULL;
02458        }
02459        oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
02460 
02461        kind = get_token(&ss,&sval);
02462        if ( kind != TK_LEFTPAREN ) {
02463               *code = LDAP_SCHERR_NOLEFTPAREN;
02464               LDAP_FREE(sval);
02465               ldap_objectclass_free(oc);
02466               return NULL;
02467        }
02468 
02469        /*
02470         * Definitions MUST begin with an OID in the numericoid format.
02471         * However, this routine is used by clients to parse the response
02472         * from servers and very well known servers will provide an OID
02473         * in the wrong format or even no OID at all.  We do our best to
02474         * extract info from those servers.
02475         */
02476        parse_whsp(&ss);
02477        savepos = ss;
02478        oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0);
02479        if ( !oc->oc_oid ) {
02480               if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
02481                      /* Backtracking */
02482                      ss = savepos;
02483                      kind = get_token(&ss,&sval);
02484                      if ( kind == TK_BAREWORD ) {
02485                             if ( !strcasecmp(sval, "NAME") ||
02486                                  !strcasecmp(sval, "DESC") ||
02487                                  !strcasecmp(sval, "OBSOLETE") ||
02488                                  !strcasecmp(sval, "SUP") ||
02489                                  !strcasecmp(sval, "ABSTRACT") ||
02490                                  !strcasecmp(sval, "STRUCTURAL") ||
02491                                  !strcasecmp(sval, "AUXILIARY") ||
02492                                  !strcasecmp(sval, "MUST") ||
02493                                  !strcasecmp(sval, "MAY") ||
02494                                  !strncasecmp(sval, "X-", 2) ) {
02495                                    /* Missing OID, backtrack */
02496                                    ss = savepos;
02497                             } else if ( flags &
02498                                    LDAP_SCHEMA_ALLOW_OID_MACRO ) {
02499                                    /* Non-numerical OID, ignore */
02500                                    int len = ss-savepos;
02501                                    oc->oc_oid = LDAP_MALLOC(len+1);
02502                                    strncpy(oc->oc_oid, savepos, len);
02503                                    oc->oc_oid[len] = 0;
02504                             }
02505                      }
02506                      LDAP_FREE(sval);
02507                      *code = 0;
02508               } else {
02509                      *errp = ss;
02510                      ldap_objectclass_free(oc);
02511                      return NULL;
02512               }
02513        }
02514        parse_whsp(&ss);
02515 
02516        /*
02517         * Beyond this point we will be liberal an accept the items
02518         * in any order.
02519         */
02520        while (1) {
02521               kind = get_token(&ss,&sval);
02522               switch (kind) {
02523               case TK_EOS:
02524                      *code = LDAP_SCHERR_NORIGHTPAREN;
02525                      *errp = EndOfInput;
02526                      ldap_objectclass_free(oc);
02527                      return NULL;
02528               case TK_RIGHTPAREN:
02529                      return oc;
02530               case TK_BAREWORD:
02531                      if ( !strcasecmp(sval,"NAME") ) {
02532                             LDAP_FREE(sval);
02533                             if ( seen_name ) {
02534                                    *code = LDAP_SCHERR_DUPOPT;
02535                                    *errp = ss;
02536                                    ldap_objectclass_free(oc);
02537                                    return(NULL);
02538                             }
02539                             seen_name = 1;
02540                             oc->oc_names = parse_qdescrs(&ss,code);
02541                             if ( !oc->oc_names ) {
02542                                    if ( *code != LDAP_SCHERR_OUTOFMEM )
02543                                           *code = LDAP_SCHERR_BADNAME;
02544                                    *errp = ss;
02545                                    ldap_objectclass_free(oc);
02546                                    return NULL;
02547                             }
02548                      } else if ( !strcasecmp(sval,"DESC") ) {
02549                             LDAP_FREE(sval);
02550                             if ( seen_desc ) {
02551                                    *code = LDAP_SCHERR_DUPOPT;
02552                                    *errp = ss;
02553                                    ldap_objectclass_free(oc);
02554                                    return(NULL);
02555                             }
02556                             seen_desc = 1;
02557                             parse_whsp(&ss);
02558                             kind = get_token(&ss,&sval);
02559                             if ( kind != TK_QDSTRING ) {
02560                                    *code = LDAP_SCHERR_UNEXPTOKEN;
02561                                    *errp = ss;
02562                                    LDAP_FREE(sval);
02563                                    ldap_objectclass_free(oc);
02564                                    return NULL;
02565                             }
02566                             oc->oc_desc = sval;
02567                             parse_whsp(&ss);
02568                      } else if ( !strcasecmp(sval,"OBSOLETE") ) {
02569                             LDAP_FREE(sval);
02570                             if ( seen_obsolete ) {
02571                                    *code = LDAP_SCHERR_DUPOPT;
02572                                    *errp = ss;
02573                                    ldap_objectclass_free(oc);
02574                                    return(NULL);
02575                             }
02576                             seen_obsolete = 1;
02577                             oc->oc_obsolete = LDAP_SCHEMA_YES;
02578                             parse_whsp(&ss);
02579                      } else if ( !strcasecmp(sval,"SUP") ) {
02580                             LDAP_FREE(sval);
02581                             if ( seen_sup ) {
02582                                    *code = LDAP_SCHERR_DUPOPT;
02583                                    *errp = ss;
02584                                    ldap_objectclass_free(oc);
02585                                    return(NULL);
02586                             }
02587                             seen_sup = 1;
02588                             oc->oc_sup_oids = parse_oids(&ss,
02589                                                       code,
02590                                                       flags);
02591                             if ( !oc->oc_sup_oids && *code != LDAP_SUCCESS ) {
02592                                    *errp = ss;
02593                                    ldap_objectclass_free(oc);
02594                                    return NULL;
02595                             }
02596                             *code = 0;
02597                      } else if ( !strcasecmp(sval,"ABSTRACT") ) {
02598                             LDAP_FREE(sval);
02599                             if ( seen_kind ) {
02600                                    *code = LDAP_SCHERR_DUPOPT;
02601                                    *errp = ss;
02602                                    ldap_objectclass_free(oc);
02603                                    return(NULL);
02604                             }
02605                             seen_kind = 1;
02606                             oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
02607                             parse_whsp(&ss);
02608                      } else if ( !strcasecmp(sval,"STRUCTURAL") ) {
02609                             LDAP_FREE(sval);
02610                             if ( seen_kind ) {
02611                                    *code = LDAP_SCHERR_DUPOPT;
02612                                    *errp = ss;
02613                                    ldap_objectclass_free(oc);
02614                                    return(NULL);
02615                             }
02616                             seen_kind = 1;
02617                             oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
02618                             parse_whsp(&ss);
02619                      } else if ( !strcasecmp(sval,"AUXILIARY") ) {
02620                             LDAP_FREE(sval);
02621                             if ( seen_kind ) {
02622                                    *code = LDAP_SCHERR_DUPOPT;
02623                                    *errp = ss;
02624                                    ldap_objectclass_free(oc);
02625                                    return(NULL);
02626                             }
02627                             seen_kind = 1;
02628                             oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
02629                             parse_whsp(&ss);
02630                      } else if ( !strcasecmp(sval,"MUST") ) {
02631                             LDAP_FREE(sval);
02632                             if ( seen_must ) {
02633                                    *code = LDAP_SCHERR_DUPOPT;
02634                                    *errp = ss;
02635                                    ldap_objectclass_free(oc);
02636                                    return(NULL);
02637                             }
02638                             seen_must = 1;
02639                             oc->oc_at_oids_must = parse_oids(&ss,code,0);
02640                             if ( !oc->oc_at_oids_must && *code != LDAP_SUCCESS ) {
02641                                    *errp = ss;
02642                                    ldap_objectclass_free(oc);
02643                                    return NULL;
02644                             }
02645                             *code = 0;
02646                             parse_whsp(&ss);
02647                      } else if ( !strcasecmp(sval,"MAY") ) {
02648                             LDAP_FREE(sval);
02649                             if ( seen_may ) {
02650                                    *code = LDAP_SCHERR_DUPOPT;
02651                                    *errp = ss;
02652                                    ldap_objectclass_free(oc);
02653                                    return(NULL);
02654                             }
02655                             seen_may = 1;
02656                             oc->oc_at_oids_may = parse_oids(&ss,code,0);
02657                             if ( !oc->oc_at_oids_may && *code != LDAP_SUCCESS ) {
02658                                    *errp = ss;
02659                                    ldap_objectclass_free(oc);
02660                                    return NULL;
02661                             }
02662                             *code = 0;
02663                             parse_whsp(&ss);
02664                      } else if ( sval[0] == 'X' && sval[1] == '-' ) {
02665                             /* Should be parse_qdstrings */
02666                             ext_vals = parse_qdescrs(&ss, code);
02667                             *code = 0;
02668                             if ( !ext_vals ) {
02669                                    *errp = ss;
02670                                    ldap_objectclass_free(oc);
02671                                    return NULL;
02672                             }
02673                             if ( add_extension(&oc->oc_extensions,
02674                                               sval, ext_vals) ) {
02675                                    *code = LDAP_SCHERR_OUTOFMEM;
02676                                    *errp = ss;
02677                                    LDAP_FREE(sval);
02678                                    ldap_objectclass_free(oc);
02679                                    return NULL;
02680                             }
02681                      } else {
02682                             *code = LDAP_SCHERR_UNEXPTOKEN;
02683                             *errp = ss;
02684                             LDAP_FREE(sval);
02685                             ldap_objectclass_free(oc);
02686                             return NULL;
02687                      }
02688                      break;
02689               default:
02690                      *code = LDAP_SCHERR_UNEXPTOKEN;
02691                      *errp = ss;
02692                      LDAP_FREE(sval);
02693                      ldap_objectclass_free(oc);
02694                      return NULL;
02695               }
02696        }
02697 }
02698 
02699 void
02700 ldap_contentrule_free(LDAPContentRule * cr)
02701 {
02702        if (!cr) return;
02703        LDAP_FREE(cr->cr_oid);
02704        if (cr->cr_names) LDAP_VFREE(cr->cr_names);
02705        if (cr->cr_desc) LDAP_FREE(cr->cr_desc);
02706        if (cr->cr_oc_oids_aux) LDAP_VFREE(cr->cr_oc_oids_aux);
02707        if (cr->cr_at_oids_must) LDAP_VFREE(cr->cr_at_oids_must);
02708        if (cr->cr_at_oids_may) LDAP_VFREE(cr->cr_at_oids_may);
02709        if (cr->cr_at_oids_not) LDAP_VFREE(cr->cr_at_oids_not);
02710        free_extensions(cr->cr_extensions);
02711        LDAP_FREE(cr);
02712 }
02713 
02714 LDAPContentRule *
02715 ldap_str2contentrule( LDAP_CONST char * s,
02716        int * code,
02717        LDAP_CONST char ** errp,
02718        LDAP_CONST unsigned flags )
02719 {
02720        tk_t kind;
02721        const char * ss = s;
02722        char * sval;
02723        int seen_name = 0;
02724        int seen_desc = 0;
02725        int seen_obsolete = 0;
02726        int seen_aux = 0;
02727        int seen_must = 0;
02728        int seen_may = 0;
02729        int seen_not = 0;
02730        LDAPContentRule * cr;
02731        char ** ext_vals;
02732        const char * savepos;
02733 
02734        if ( !s ) {
02735               *code = LDAP_SCHERR_EMPTY;
02736               *errp = "";
02737               return NULL;
02738        }
02739 
02740        *errp = s;
02741        cr = LDAP_CALLOC(1,sizeof(LDAPContentRule));
02742 
02743        if ( !cr ) {
02744               *code = LDAP_SCHERR_OUTOFMEM;
02745               return NULL;
02746        }
02747 
02748        kind = get_token(&ss,&sval);
02749        if ( kind != TK_LEFTPAREN ) {
02750               *code = LDAP_SCHERR_NOLEFTPAREN;
02751               LDAP_FREE(sval);
02752               ldap_contentrule_free(cr);
02753               return NULL;
02754        }
02755 
02756        /*
02757         * Definitions MUST begin with an OID in the numericoid format.
02758         */
02759        parse_whsp(&ss);
02760        savepos = ss;
02761        cr->cr_oid = ldap_int_parse_numericoid(&ss,code,0);
02762        if ( !cr->cr_oid ) {
02763               if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
02764                      /* Backtracking */
02765                      ss = savepos;
02766                      kind = get_token(&ss,&sval);
02767                      if ( kind == TK_BAREWORD ) {
02768                             if ( !strcasecmp(sval, "NAME") ||
02769                                  !strcasecmp(sval, "DESC") ||
02770                                  !strcasecmp(sval, "OBSOLETE") ||
02771                                  !strcasecmp(sval, "AUX") ||
02772                                  !strcasecmp(sval, "MUST") ||
02773                                  !strcasecmp(sval, "MAY") ||
02774                                  !strcasecmp(sval, "NOT") ||
02775                                  !strncasecmp(sval, "X-", 2) ) {
02776                                    /* Missing OID, backtrack */
02777                                    ss = savepos;
02778                             } else if ( flags &
02779                                    LDAP_SCHEMA_ALLOW_OID_MACRO ) {
02780                                    /* Non-numerical OID, ignore */
02781                                    int len = ss-savepos;
02782                                    cr->cr_oid = LDAP_MALLOC(len+1);
02783                                    strncpy(cr->cr_oid, savepos, len);
02784                                    cr->cr_oid[len] = 0;
02785                             }
02786                      }
02787                      LDAP_FREE(sval);
02788               } else {
02789                      *errp = ss;
02790                      ldap_contentrule_free(cr);
02791                      return NULL;
02792               }
02793        }
02794        parse_whsp(&ss);
02795 
02796        /*
02797         * Beyond this point we will be liberal an accept the items
02798         * in any order.
02799         */
02800        while (1) {
02801               kind = get_token(&ss,&sval);
02802               switch (kind) {
02803               case TK_EOS:
02804                      *code = LDAP_SCHERR_NORIGHTPAREN;
02805                      *errp = EndOfInput;
02806                      ldap_contentrule_free(cr);
02807                      return NULL;
02808               case TK_RIGHTPAREN:
02809                      return cr;
02810               case TK_BAREWORD:
02811                      if ( !strcasecmp(sval,"NAME") ) {
02812                             LDAP_FREE(sval);
02813                             if ( seen_name ) {
02814                                    *code = LDAP_SCHERR_DUPOPT;
02815                                    *errp = ss;
02816                                    ldap_contentrule_free(cr);
02817                                    return(NULL);
02818                             }
02819                             seen_name = 1;
02820                             cr->cr_names = parse_qdescrs(&ss,code);
02821                             if ( !cr->cr_names ) {
02822                                    if ( *code != LDAP_SCHERR_OUTOFMEM )
02823                                           *code = LDAP_SCHERR_BADNAME;
02824                                    *errp = ss;
02825                                    ldap_contentrule_free(cr);
02826                                    return NULL;
02827                             }
02828                      } else if ( !strcasecmp(sval,"DESC") ) {
02829                             LDAP_FREE(sval);
02830                             if ( seen_desc ) {
02831                                    *code = LDAP_SCHERR_DUPOPT;
02832                                    *errp = ss;
02833                                    ldap_contentrule_free(cr);
02834                                    return(NULL);
02835                             }
02836                             seen_desc = 1;
02837                             parse_whsp(&ss);
02838                             kind = get_token(&ss,&sval);
02839                             if ( kind != TK_QDSTRING ) {
02840                                    *code = LDAP_SCHERR_UNEXPTOKEN;
02841                                    *errp = ss;
02842                                    LDAP_FREE(sval);
02843                                    ldap_contentrule_free(cr);
02844                                    return NULL;
02845                             }
02846                             cr->cr_desc = sval;
02847                             parse_whsp(&ss);
02848                      } else if ( !strcasecmp(sval,"OBSOLETE") ) {
02849                             LDAP_FREE(sval);
02850                             if ( seen_obsolete ) {
02851                                    *code = LDAP_SCHERR_DUPOPT;
02852                                    *errp = ss;
02853                                    ldap_contentrule_free(cr);
02854                                    return(NULL);
02855                             }
02856                             seen_obsolete = 1;
02857                             cr->cr_obsolete = LDAP_SCHEMA_YES;
02858                             parse_whsp(&ss);
02859                      } else if ( !strcasecmp(sval,"AUX") ) {
02860                             LDAP_FREE(sval);
02861                             if ( seen_aux ) {
02862                                    *code = LDAP_SCHERR_DUPOPT;
02863                                    *errp = ss;
02864                                    ldap_contentrule_free(cr);
02865                                    return(NULL);
02866                             }
02867                             seen_aux = 1;
02868                             cr->cr_oc_oids_aux = parse_oids(&ss,code,0);
02869                             if ( !cr->cr_oc_oids_aux ) {
02870                                    *errp = ss;
02871                                    ldap_contentrule_free(cr);
02872                                    return NULL;
02873                             }
02874                             parse_whsp(&ss);
02875                      } else if ( !strcasecmp(sval,"MUST") ) {
02876                             LDAP_FREE(sval);
02877                             if ( seen_must ) {
02878                                    *code = LDAP_SCHERR_DUPOPT;
02879                                    *errp = ss;
02880                                    ldap_contentrule_free(cr);
02881                                    return(NULL);
02882                             }
02883                             seen_must = 1;
02884                             cr->cr_at_oids_must = parse_oids(&ss,code,0);
02885                             if ( !cr->cr_at_oids_must && *code != LDAP_SUCCESS ) {
02886                                    *errp = ss;
02887                                    ldap_contentrule_free(cr);
02888                                    return NULL;
02889                             }
02890                             parse_whsp(&ss);
02891                      } else if ( !strcasecmp(sval,"MAY") ) {
02892                             LDAP_FREE(sval);
02893                             if ( seen_may ) {
02894                                    *code = LDAP_SCHERR_DUPOPT;
02895                                    *errp = ss;
02896                                    ldap_contentrule_free(cr);
02897                                    return(NULL);
02898                             }
02899                             seen_may = 1;
02900                             cr->cr_at_oids_may = parse_oids(&ss,code,0);
02901                             if ( !cr->cr_at_oids_may && *code != LDAP_SUCCESS ) {
02902                                    *errp = ss;
02903                                    ldap_contentrule_free(cr);
02904                                    return NULL;
02905                             }
02906                             parse_whsp(&ss);
02907                      } else if ( !strcasecmp(sval,"NOT") ) {
02908                             LDAP_FREE(sval);
02909                             if ( seen_not ) {
02910                                    *code = LDAP_SCHERR_DUPOPT;
02911                                    *errp = ss;
02912                                    ldap_contentrule_free(cr);
02913                                    return(NULL);
02914                             }
02915                             seen_not = 1;
02916                             cr->cr_at_oids_not = parse_oids(&ss,code,0);
02917                             if ( !cr->cr_at_oids_not && *code != LDAP_SUCCESS ) {
02918                                    *errp = ss;
02919                                    ldap_contentrule_free(cr);
02920                                    return NULL;
02921                             }
02922                             parse_whsp(&ss);
02923                      } else if ( sval[0] == 'X' && sval[1] == '-' ) {
02924                             /* Should be parse_qdstrings */
02925                             ext_vals = parse_qdescrs(&ss, code);
02926                             if ( !ext_vals ) {
02927                                    *errp = ss;
02928                                    ldap_contentrule_free(cr);
02929                                    return NULL;
02930                             }
02931                             if ( add_extension(&cr->cr_extensions,
02932                                               sval, ext_vals) ) {
02933                                    *code = LDAP_SCHERR_OUTOFMEM;
02934                                    *errp = ss;
02935                                    LDAP_FREE(sval);
02936                                    ldap_contentrule_free(cr);
02937                                    return NULL;
02938                             }
02939                      } else {
02940                             *code = LDAP_SCHERR_UNEXPTOKEN;
02941                             *errp = ss;
02942                             LDAP_FREE(sval);
02943                             ldap_contentrule_free(cr);
02944                             return NULL;
02945                      }
02946                      break;
02947               default:
02948                      *code = LDAP_SCHERR_UNEXPTOKEN;
02949                      *errp = ss;
02950                      LDAP_FREE(sval);
02951                      ldap_contentrule_free(cr);
02952                      return NULL;
02953               }
02954        }
02955 }
02956 
02957 void
02958 ldap_structurerule_free(LDAPStructureRule * sr)
02959 {
02960        if (!sr) return;
02961        if (sr->sr_names) LDAP_VFREE(sr->sr_names);
02962        if (sr->sr_desc) LDAP_FREE(sr->sr_desc);
02963        if (sr->sr_nameform) LDAP_FREE(sr->sr_nameform);
02964        if (sr->sr_sup_ruleids) LDAP_FREE(sr->sr_sup_ruleids);
02965        free_extensions(sr->sr_extensions);
02966        LDAP_FREE(sr);
02967 }
02968 
02969 LDAPStructureRule *
02970 ldap_str2structurerule( LDAP_CONST char * s,
02971        int * code,
02972        LDAP_CONST char ** errp,
02973        LDAP_CONST unsigned flags )
02974 {
02975        tk_t kind;
02976        int ret;
02977        const char * ss = s;
02978        char * sval;
02979        int seen_name = 0;
02980        int seen_desc = 0;
02981        int seen_obsolete = 0;
02982        int seen_nameform = 0;
02983        LDAPStructureRule * sr;
02984        char ** ext_vals;
02985        const char * savepos;
02986 
02987        if ( !s ) {
02988               *code = LDAP_SCHERR_EMPTY;
02989               *errp = "";
02990               return NULL;
02991        }
02992 
02993        *errp = s;
02994        sr = LDAP_CALLOC(1,sizeof(LDAPStructureRule));
02995 
02996        if ( !sr ) {
02997               *code = LDAP_SCHERR_OUTOFMEM;
02998               return NULL;
02999        }
03000 
03001        kind = get_token(&ss,&sval);
03002        if ( kind != TK_LEFTPAREN ) {
03003               *code = LDAP_SCHERR_NOLEFTPAREN;
03004               LDAP_FREE(sval);
03005               ldap_structurerule_free(sr);
03006               return NULL;
03007        }
03008 
03009        /*
03010         * Definitions MUST begin with a ruleid.
03011         */
03012        parse_whsp(&ss);
03013        savepos = ss;
03014        ret = ldap_int_parse_ruleid(&ss,code,0,&sr->sr_ruleid);
03015        if ( ret ) {
03016               *errp = ss;
03017               ldap_structurerule_free(sr);
03018               return NULL;
03019        }
03020        parse_whsp(&ss);
03021 
03022        /*
03023         * Beyond this point we will be liberal an accept the items
03024         * in any order.
03025         */
03026        while (1) {
03027               kind = get_token(&ss,&sval);
03028               switch (kind) {
03029               case TK_EOS:
03030                      *code = LDAP_SCHERR_NORIGHTPAREN;
03031                      *errp = EndOfInput;
03032                      ldap_structurerule_free(sr);
03033                      return NULL;
03034               case TK_RIGHTPAREN:
03035                      if( !seen_nameform ) {
03036                             *code = LDAP_SCHERR_MISSING;
03037                             ldap_structurerule_free(sr);
03038                             return NULL;
03039                      }
03040                      return sr;
03041               case TK_BAREWORD:
03042                      if ( !strcasecmp(sval,"NAME") ) {
03043                             LDAP_FREE(sval);
03044                             if ( seen_name ) {
03045                                    *code = LDAP_SCHERR_DUPOPT;
03046                                    *errp = ss;
03047                                    ldap_structurerule_free(sr);
03048                                    return(NULL);
03049                             }
03050                             seen_name = 1;
03051                             sr->sr_names = parse_qdescrs(&ss,code);
03052                             if ( !sr->sr_names ) {
03053                                    if ( *code != LDAP_SCHERR_OUTOFMEM )
03054                                           *code = LDAP_SCHERR_BADNAME;
03055                                    *errp = ss;
03056                                    ldap_structurerule_free(sr);
03057                                    return NULL;
03058                             }
03059                      } else if ( !strcasecmp(sval,"DESC") ) {
03060                             LDAP_FREE(sval);
03061                             if ( seen_desc ) {
03062                                    *code = LDAP_SCHERR_DUPOPT;
03063                                    *errp = ss;
03064                                    ldap_structurerule_free(sr);
03065                                    return(NULL);
03066                             }
03067                             seen_desc = 1;
03068                             parse_whsp(&ss);
03069                             kind = get_token(&ss,&sval);
03070                             if ( kind != TK_QDSTRING ) {
03071                                    *code = LDAP_SCHERR_UNEXPTOKEN;
03072                                    *errp = ss;
03073                                    LDAP_FREE(sval);
03074                                    ldap_structurerule_free(sr);
03075                                    return NULL;
03076                             }
03077                             sr->sr_desc = sval;
03078                             parse_whsp(&ss);
03079                      } else if ( !strcasecmp(sval,"OBSOLETE") ) {
03080                             LDAP_FREE(sval);
03081                             if ( seen_obsolete ) {
03082                                    *code = LDAP_SCHERR_DUPOPT;
03083                                    *errp = ss;
03084                                    ldap_structurerule_free(sr);
03085                                    return(NULL);
03086                             }
03087                             seen_obsolete = 1;
03088                             sr->sr_obsolete = LDAP_SCHEMA_YES;
03089                             parse_whsp(&ss);
03090                      } else if ( !strcasecmp(sval,"FORM") ) {
03091                             LDAP_FREE(sval);
03092                             if ( seen_nameform ) {
03093                                    *code = LDAP_SCHERR_DUPOPT;
03094                                    *errp = ss;
03095                                    ldap_structurerule_free(sr);
03096                                    return(NULL);
03097                             }
03098                             seen_nameform = 1;
03099                             sr->sr_nameform = parse_woid(&ss,code);
03100                             if ( !sr->sr_nameform ) {
03101                                    *errp = ss;
03102                                    ldap_structurerule_free(sr);
03103                                    return NULL;
03104                             }
03105                             parse_whsp(&ss);
03106                      } else if ( sval[0] == 'X' && sval[1] == '-' ) {
03107                             /* Should be parse_qdstrings */
03108                             ext_vals = parse_qdescrs(&ss, code);
03109                             if ( !ext_vals ) {
03110                                    *errp = ss;
03111                                    ldap_structurerule_free(sr);
03112                                    return NULL;
03113                             }
03114                             if ( add_extension(&sr->sr_extensions,
03115                                               sval, ext_vals) ) {
03116                                    *code = LDAP_SCHERR_OUTOFMEM;
03117                                    *errp = ss;
03118                                    LDAP_FREE(sval);
03119                                    ldap_structurerule_free(sr);
03120                                    return NULL;
03121                             }
03122                      } else {
03123                             *code = LDAP_SCHERR_UNEXPTOKEN;
03124                             *errp = ss;
03125                             LDAP_FREE(sval);
03126                             ldap_structurerule_free(sr);
03127                             return NULL;
03128                      }
03129                      break;
03130               default:
03131                      *code = LDAP_SCHERR_UNEXPTOKEN;
03132                      *errp = ss;
03133                      LDAP_FREE(sval);
03134                      ldap_structurerule_free(sr);
03135                      return NULL;
03136               }
03137        }
03138 }
03139 
03140 void
03141 ldap_nameform_free(LDAPNameForm * nf)
03142 {
03143        if (!nf) return;
03144        LDAP_FREE(nf->nf_oid);
03145        if (nf->nf_names) LDAP_VFREE(nf->nf_names);
03146        if (nf->nf_desc) LDAP_FREE(nf->nf_desc);
03147        if (nf->nf_objectclass) LDAP_FREE(nf->nf_objectclass);
03148        if (nf->nf_at_oids_must) LDAP_VFREE(nf->nf_at_oids_must);
03149        if (nf->nf_at_oids_may) LDAP_VFREE(nf->nf_at_oids_may);
03150        free_extensions(nf->nf_extensions);
03151        LDAP_FREE(nf);
03152 }
03153 
03154 LDAPNameForm *
03155 ldap_str2nameform( LDAP_CONST char * s,
03156        int * code,
03157        LDAP_CONST char ** errp,
03158        LDAP_CONST unsigned flags )
03159 {
03160        tk_t kind;
03161        const char * ss = s;
03162        char * sval;
03163        int seen_name = 0;
03164        int seen_desc = 0;
03165        int seen_obsolete = 0;
03166        int seen_class = 0;
03167        int seen_must = 0;
03168        int seen_may = 0;
03169        LDAPNameForm * nf;
03170        char ** ext_vals;
03171        const char * savepos;
03172 
03173        if ( !s ) {
03174               *code = LDAP_SCHERR_EMPTY;
03175               *errp = "";
03176               return NULL;
03177        }
03178 
03179        *errp = s;
03180        nf = LDAP_CALLOC(1,sizeof(LDAPNameForm));
03181 
03182        if ( !nf ) {
03183               *code = LDAP_SCHERR_OUTOFMEM;
03184               return NULL;
03185        }
03186 
03187        kind = get_token(&ss,&sval);
03188        if ( kind != TK_LEFTPAREN ) {
03189               *code = LDAP_SCHERR_NOLEFTPAREN;
03190               LDAP_FREE(sval);
03191               ldap_nameform_free(nf);
03192               return NULL;
03193        }
03194 
03195        /*
03196         * Definitions MUST begin with an OID in the numericoid format.
03197         * However, this routine is used by clients to parse the response
03198         * from servers and very well known servers will provide an OID
03199         * in the wrong format or even no OID at all.  We do our best to
03200         * extract info from those servers.
03201         */
03202        parse_whsp(&ss);
03203        savepos = ss;
03204        nf->nf_oid = ldap_int_parse_numericoid(&ss,code,0);
03205        if ( !nf->nf_oid ) {
03206               *errp = ss;
03207               ldap_nameform_free(nf);
03208               return NULL;
03209        }
03210        parse_whsp(&ss);
03211 
03212        /*
03213         * Beyond this point we will be liberal an accept the items
03214         * in any order.
03215         */
03216        while (1) {
03217               kind = get_token(&ss,&sval);
03218               switch (kind) {
03219               case TK_EOS:
03220                      *code = LDAP_SCHERR_NORIGHTPAREN;
03221                      *errp = EndOfInput;
03222                      ldap_nameform_free(nf);
03223                      return NULL;
03224               case TK_RIGHTPAREN:
03225                      if( !seen_class || !seen_must ) {
03226                             *code = LDAP_SCHERR_MISSING;
03227                             ldap_nameform_free(nf);
03228                             return NULL;
03229                      }
03230                      return nf;
03231               case TK_BAREWORD:
03232                      if ( !strcasecmp(sval,"NAME") ) {
03233                             LDAP_FREE(sval);
03234                             if ( seen_name ) {
03235                                    *code = LDAP_SCHERR_DUPOPT;
03236                                    *errp = ss;
03237                                    ldap_nameform_free(nf);
03238                                    return(NULL);
03239                             }
03240                             seen_name = 1;
03241                             nf->nf_names = parse_qdescrs(&ss,code);
03242                             if ( !nf->nf_names ) {
03243                                    if ( *code != LDAP_SCHERR_OUTOFMEM )
03244                                           *code = LDAP_SCHERR_BADNAME;
03245                                    *errp = ss;
03246                                    ldap_nameform_free(nf);
03247                                    return NULL;
03248                             }
03249                      } else if ( !strcasecmp(sval,"DESC") ) {
03250                             LDAP_FREE(sval);
03251                             if ( seen_desc ) {
03252                                    *code = LDAP_SCHERR_DUPOPT;
03253                                    *errp = ss;
03254                                    ldap_nameform_free(nf);
03255                                    return(NULL);
03256                             }
03257                             seen_desc = 1;
03258                             parse_whsp(&ss);
03259                             kind = get_token(&ss,&sval);
03260                             if ( kind != TK_QDSTRING ) {
03261                                    *code = LDAP_SCHERR_UNEXPTOKEN;
03262                                    *errp = ss;
03263                                    LDAP_FREE(sval);
03264                                    ldap_nameform_free(nf);
03265                                    return NULL;
03266                             }
03267                             nf->nf_desc = sval;
03268                             parse_whsp(&ss);
03269                      } else if ( !strcasecmp(sval,"OBSOLETE") ) {
03270                             LDAP_FREE(sval);
03271                             if ( seen_obsolete ) {
03272                                    *code = LDAP_SCHERR_DUPOPT;
03273                                    *errp = ss;
03274                                    ldap_nameform_free(nf);
03275                                    return(NULL);
03276                             }
03277                             seen_obsolete = 1;
03278                             nf->nf_obsolete = LDAP_SCHEMA_YES;
03279                             parse_whsp(&ss);
03280                      } else if ( !strcasecmp(sval,"OC") ) {
03281                             LDAP_FREE(sval);
03282                             if ( seen_class ) {
03283                                    *code = LDAP_SCHERR_DUPOPT;
03284                                    *errp = ss;
03285                                    ldap_nameform_free(nf);
03286                                    return(NULL);
03287                             }
03288                             seen_class = 1;
03289                             nf->nf_objectclass = parse_woid(&ss,code);
03290                             if ( !nf->nf_objectclass ) {
03291                                    *errp = ss;
03292                                    ldap_nameform_free(nf);
03293                                    return NULL;
03294                             }
03295                      } else if ( !strcasecmp(sval,"MUST") ) {
03296                             LDAP_FREE(sval);
03297                             if ( seen_must ) {
03298                                    *code = LDAP_SCHERR_DUPOPT;
03299                                    *errp = ss;
03300                                    ldap_nameform_free(nf);
03301                                    return(NULL);
03302                             }
03303                             seen_must = 1;
03304                             nf->nf_at_oids_must = parse_oids(&ss,code,0);
03305                             if ( !nf->nf_at_oids_must && *code != LDAP_SUCCESS ) {
03306                                    *errp = ss;
03307                                    ldap_nameform_free(nf);
03308                                    return NULL;
03309                             }
03310                             parse_whsp(&ss);
03311                      } else if ( !strcasecmp(sval,"MAY") ) {
03312                             LDAP_FREE(sval);
03313                             if ( seen_may ) {
03314                                    *code = LDAP_SCHERR_DUPOPT;
03315                                    *errp = ss;
03316                                    ldap_nameform_free(nf);
03317                                    return(NULL);
03318                             }
03319                             seen_may = 1;
03320                             nf->nf_at_oids_may = parse_oids(&ss,code,0);
03321                             if ( !nf->nf_at_oids_may && *code != LDAP_SUCCESS ) {
03322                                    *errp = ss;
03323                                    ldap_nameform_free(nf);
03324                                    return NULL;
03325                             }
03326                             parse_whsp(&ss);
03327                      } else if ( sval[0] == 'X' && sval[1] == '-' ) {
03328                             /* Should be parse_qdstrings */
03329                             ext_vals = parse_qdescrs(&ss, code);
03330                             if ( !ext_vals ) {
03331                                    *errp = ss;
03332                                    ldap_nameform_free(nf);
03333                                    return NULL;
03334                             }
03335                             if ( add_extension(&nf->nf_extensions,
03336                                               sval, ext_vals) ) {
03337                                    *code = LDAP_SCHERR_OUTOFMEM;
03338                                    *errp = ss;
03339                                    LDAP_FREE(sval);
03340                                    ldap_nameform_free(nf);
03341                                    return NULL;
03342                             }
03343                      } else {
03344                             *code = LDAP_SCHERR_UNEXPTOKEN;
03345                             *errp = ss;
03346                             LDAP_FREE(sval);
03347                             ldap_nameform_free(nf);
03348                             return NULL;
03349                      }
03350                      break;
03351               default:
03352                      *code = LDAP_SCHERR_UNEXPTOKEN;
03353                      *errp = ss;
03354                      LDAP_FREE(sval);
03355                      ldap_nameform_free(nf);
03356                      return NULL;
03357               }
03358        }
03359 }
03360 
03361 static char *const err2text[] = {
03362        N_("Success"),
03363        N_("Out of memory"),
03364        N_("Unexpected token"),
03365        N_("Missing opening parenthesis"),
03366        N_("Missing closing parenthesis"),
03367        N_("Expecting digit"),
03368        N_("Expecting a name"),
03369        N_("Bad description"),
03370        N_("Bad superiors"),
03371        N_("Duplicate option"),
03372        N_("Unexpected end of data"),
03373        N_("Missing required field"),
03374        N_("Out of order field")
03375 };
03376 
03377 char *
03378 ldap_scherr2str(int code)
03379 {
03380        if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) {
03381               return _("Unknown error");
03382        } else {
03383               return _(err2text[code]);
03384        }
03385 }