1 /*        $NetBSD: schema.c,v 1.3 2021/08/14 16:14:56 christos Exp $  */
2 
3 /* $OpenLDAP$ */
4 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5  *
6  * Copyright 1998-2021 The OpenLDAP Foundation.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted only as authorized by the OpenLDAP
11  * Public License.
12  *
13  * A copy of this license is available in the file LICENSE in the
14  * top-level directory of the distribution or, alternatively, at
15  * <http://www.OpenLDAP.org/license.html>.
16  */
17 
18 /*
19  * schema.c:  parsing routines used by servers and clients to process
20  *        schema definitions
21  */
22 
23 #include <sys/cdefs.h>
24 __RCSID("$NetBSD: schema.c,v 1.3 2021/08/14 16:14:56 christos Exp $");
25 
26 #include "portable.h"
27 
28 #include <stdio.h>
29 #include <ac/stdlib.h>
30 
31 #include <ac/string.h>
32 #include <ac/time.h>
33 
34 #include "ldap-int.h"
35 
36 #include <ldap_schema.h>
37 
38 static const char EndOfInput[] = "end of input";
39 
40 static const char *
choose_name(char * names[],const char * fallback)41 choose_name( char *names[], const char *fallback )
42 {
43           return (names != NULL && names[0] != NULL) ? names[0] : fallback;
44 }
45 
46 LDAP_CONST char *
ldap_syntax2name(LDAPSyntax * syn)47 ldap_syntax2name( LDAPSyntax * syn )
48 {
49           if (!syn) return NULL;
50           return( syn->syn_oid );
51 }
52 
53 LDAP_CONST char *
ldap_matchingrule2name(LDAPMatchingRule * mr)54 ldap_matchingrule2name( LDAPMatchingRule * mr )
55 {
56           if (!mr) return NULL;
57           return( choose_name( mr->mr_names, mr->mr_oid ) );
58 }
59 
60 LDAP_CONST char *
ldap_matchingruleuse2name(LDAPMatchingRuleUse * mru)61 ldap_matchingruleuse2name( LDAPMatchingRuleUse * mru )
62 {
63           if (!mru) return NULL;
64           return( choose_name( mru->mru_names, mru->mru_oid ) );
65 }
66 
67 LDAP_CONST char *
ldap_attributetype2name(LDAPAttributeType * at)68 ldap_attributetype2name( LDAPAttributeType * at )
69 {
70           if (!at) return NULL;
71           return( choose_name( at->at_names, at->at_oid ) );
72 }
73 
74 LDAP_CONST char *
ldap_objectclass2name(LDAPObjectClass * oc)75 ldap_objectclass2name( LDAPObjectClass * oc )
76 {
77           if (!oc) return NULL;
78           return( choose_name( oc->oc_names, oc->oc_oid ) );
79 }
80 
81 LDAP_CONST char *
ldap_contentrule2name(LDAPContentRule * cr)82 ldap_contentrule2name( LDAPContentRule * cr )
83 {
84           if (!cr) return NULL;
85           return( choose_name( cr->cr_names, cr->cr_oid ) );
86 }
87 
88 LDAP_CONST char *
ldap_nameform2name(LDAPNameForm * nf)89 ldap_nameform2name( LDAPNameForm * nf )
90 {
91           if (!nf) return NULL;
92           return( choose_name( nf->nf_names, nf->nf_oid ) );
93 }
94 
95 LDAP_CONST char *
ldap_structurerule2name(LDAPStructureRule * sr)96 ldap_structurerule2name( LDAPStructureRule * sr )
97 {
98           if (!sr) return NULL;
99           return( choose_name( sr->sr_names, NULL ) );
100 }
101 
102 /*
103  * When pretty printing the entities we will be appending to a buffer.
104  * Since checking for overflow, realloc'ing and checking if no error
105  * is extremely boring, we will use a protection layer that will let
106  * us blissfully ignore the error until the end.  This layer is
107  * implemented with the help of the next type.
108  */
109 
110 typedef struct safe_string {
111           char * val;
112           ber_len_t size;
113           ber_len_t pos;
114           int at_whsp;
115 } safe_string;
116 
117 static safe_string *
new_safe_string(int size)118 new_safe_string(int size)
119 {
120           safe_string * ss;
121 
122           ss = LDAP_MALLOC(sizeof(safe_string));
123           if ( !ss )
124                     return(NULL);
125 
126           ss->val = LDAP_MALLOC(size);
127           if ( !ss->val ) {
128                     LDAP_FREE(ss);
129                     return(NULL);
130           }
131 
132           ss->size = size;
133           ss->pos = 0;
134           ss->at_whsp = 0;
135 
136           return ss;
137 }
138 
139 static void
safe_string_free(safe_string * ss)140 safe_string_free(safe_string * ss)
141 {
142           if ( !ss )
143                     return;
144           LDAP_FREE(ss->val);
145           LDAP_FREE(ss);
146 }
147 
148 #if 0     /* unused */
149 static char *
150 safe_string_val(safe_string * ss)
151 {
152           ss->val[ss->pos] = '\0';
153           return(ss->val);
154 }
155 #endif
156 
157 static char *
safe_strdup(safe_string * ss)158 safe_strdup(safe_string * ss)
159 {
160           char *ret = LDAP_MALLOC(ss->pos+1);
161           if (!ret)
162                     return NULL;
163           AC_MEMCPY(ret, ss->val, ss->pos);
164           ret[ss->pos] = '\0';
165           return ret;
166 }
167 
168 static int
append_to_safe_string(safe_string * ss,char * s)169 append_to_safe_string(safe_string * ss, char * s)
170 {
171           int l = strlen(s);
172           char * temp;
173 
174           /*
175            * Some runaway process is trying to append to a string that
176            * overflowed and we could not extend.
177            */
178           if ( !ss->val )
179                     return -1;
180 
181           /* We always make sure there is at least one position available */
182           if ( ss->pos + l >= ss->size-1 ) {
183                     ss->size *= 2;
184                     if ( ss->pos + l >= ss->size-1 ) {
185                               ss->size = ss->pos + l + 1;
186                     }
187 
188                     temp = LDAP_REALLOC(ss->val, ss->size);
189                     if ( !temp ) {
190                               /* Trouble, out of memory */
191                               LDAP_FREE(ss->val);
192                               return -1;
193                     }
194                     ss->val = temp;
195           }
196           strncpy(&ss->val[ss->pos], s, l);
197           ss->pos += l;
198           if ( ss->pos > 0 && LDAP_SPACE(ss->val[ss->pos-1]) )
199                     ss->at_whsp = 1;
200           else
201                     ss->at_whsp = 0;
202 
203           return 0;
204 }
205 
206 static int
print_literal(safe_string * ss,char * s)207 print_literal(safe_string *ss, char *s)
208 {
209           return(append_to_safe_string(ss,s));
210 }
211 
212 static int
print_whsp(safe_string * ss)213 print_whsp(safe_string *ss)
214 {
215           if ( ss->at_whsp )
216                     return(append_to_safe_string(ss,""));
217           else
218                     return(append_to_safe_string(ss," "));
219 }
220 
221 static int
print_numericoid(safe_string * ss,char * s)222 print_numericoid(safe_string *ss, char *s)
223 {
224           if ( s )
225                     return(append_to_safe_string(ss,s));
226           else
227                     return(append_to_safe_string(ss,""));
228 }
229 
230 /* This one is identical to print_qdescr */
231 static int
print_qdstring(safe_string * ss,char * s)232 print_qdstring(safe_string *ss, char *s)
233 {
234           print_whsp(ss);
235           print_literal(ss,"'");
236           append_to_safe_string(ss,s);
237           print_literal(ss,"'");
238           return(print_whsp(ss));
239 }
240 
241 static int
print_qdescr(safe_string * ss,char * s)242 print_qdescr(safe_string *ss, char *s)
243 {
244           print_whsp(ss);
245           print_literal(ss,"'");
246           append_to_safe_string(ss,s);
247           print_literal(ss,"'");
248           return(print_whsp(ss));
249 }
250 
251 static int
print_qdescrlist(safe_string * ss,char ** sa)252 print_qdescrlist(safe_string *ss, char **sa)
253 {
254           char **sp;
255           int ret = 0;
256 
257           for (sp=sa; *sp; sp++) {
258                     ret = print_qdescr(ss,*sp);
259           }
260           /* If the list was empty, we return zero that is potentially
261            * incorrect, but since we will be still appending things, the
262            * overflow will be detected later.  Maybe FIX.
263            */
264           return(ret);
265 }
266 
267 static int
print_qdescrs(safe_string * ss,char ** sa)268 print_qdescrs(safe_string *ss, char **sa)
269 {
270           /* The only way to represent an empty list is as a qdescrlist
271            * so, if the list is empty we treat it as a long list.
272            * Really, this is what the syntax mandates.  We should not
273            * be here if the list was empty, but if it happens, a label
274            * has already been output and we cannot undo it.
275            */
276           if ( !sa[0] || ( sa[0] && sa[1] ) ) {
277                     print_whsp(ss);
278                     print_literal(ss,"("/*)*/);
279                     print_qdescrlist(ss,sa);
280                     print_literal(ss,/*(*/")");
281                     return(print_whsp(ss));
282           } else {
283             return(print_qdescr(ss,*sa));
284           }
285 }
286 
287 static int
print_woid(safe_string * ss,char * s)288 print_woid(safe_string *ss, char *s)
289 {
290           print_whsp(ss);
291           append_to_safe_string(ss,s);
292           return print_whsp(ss);
293 }
294 
295 static int
print_oidlist(safe_string * ss,char ** sa)296 print_oidlist(safe_string *ss, char **sa)
297 {
298           char **sp;
299 
300           for (sp=sa; *(sp+1); sp++) {
301                     print_woid(ss,*sp);
302                     print_literal(ss,"$");
303           }
304           return(print_woid(ss,*sp));
305 }
306 
307 static int
print_oids(safe_string * ss,char ** sa)308 print_oids(safe_string *ss, char **sa)
309 {
310           if ( sa[0] && sa[1] ) {
311                     print_literal(ss,"("/*)*/);
312                     print_oidlist(ss,sa);
313                     print_whsp(ss);
314                     return(print_literal(ss,/*(*/")"));
315           } else {
316                     return(print_woid(ss,*sa));
317           }
318 }
319 
320 static int
print_noidlen(safe_string * ss,char * s,int l)321 print_noidlen(safe_string *ss, char *s, int l)
322 {
323           char buf[64];
324           int ret;
325 
326           ret = print_numericoid(ss,s);
327           if ( l ) {
328                     snprintf(buf, sizeof buf, "{%d}",l);
329                     ret = print_literal(ss,buf);
330           }
331           return(ret);
332 }
333 
334 static int
print_ruleid(safe_string * ss,int rid)335 print_ruleid(safe_string *ss, int rid)
336 {
337           char buf[64];
338           snprintf(buf, sizeof buf, "%d", rid);
339           return print_literal(ss,buf);
340 }
341 
342 static int
print_ruleids(safe_string * ss,int n,int * rids)343 print_ruleids(safe_string *ss, int n, int *rids)
344 {
345           int i;
346 
347           if( n == 1 ) {
348                     print_ruleid(ss,rids[0]);
349                     return print_whsp(ss);
350           } else {
351                     print_literal(ss,"("/*)*/);
352                     for( i=0; i<n; i++ ) {
353                               print_whsp(ss);
354                               print_ruleid(ss,rids[i]);
355                     }
356                     print_whsp(ss);
357                     return print_literal(ss,/*(*/")");
358           }
359 }
360 
361 
362 static int
print_extensions(safe_string * ss,LDAPSchemaExtensionItem ** extensions)363 print_extensions(safe_string *ss, LDAPSchemaExtensionItem **extensions)
364 {
365           LDAPSchemaExtensionItem **ext;
366 
367           if ( extensions ) {
368                     print_whsp(ss);
369                     for ( ext = extensions; *ext != NULL; ext++ ) {
370                               print_literal(ss, (*ext)->lsei_name);
371                               print_whsp(ss);
372                               /* Should be print_qdstrings */
373                               print_qdescrs(ss, (*ext)->lsei_values);
374                               print_whsp(ss);
375                     }
376           }
377 
378           return 0;
379 }
380 
381 char *
ldap_syntax2str(LDAPSyntax * syn)382 ldap_syntax2str( LDAPSyntax * syn )
383 {
384           struct berval bv;
385           if (ldap_syntax2bv( syn, &bv ))
386                     return(bv.bv_val);
387           else
388                     return NULL;
389 }
390 
391 struct berval *
ldap_syntax2bv(LDAPSyntax * syn,struct berval * bv)392 ldap_syntax2bv( LDAPSyntax * syn, struct berval *bv )
393 {
394           safe_string * ss;
395 
396           if ( !syn || !bv )
397                     return NULL;
398 
399           ss = new_safe_string(256);
400           if ( !ss )
401                     return NULL;
402 
403           print_literal(ss,"("/*)*/);
404           print_whsp(ss);
405 
406           print_numericoid(ss, syn->syn_oid);
407           print_whsp(ss);
408 
409           if ( syn->syn_desc ) {
410                     print_literal(ss,"DESC");
411                     print_qdstring(ss,syn->syn_desc);
412           }
413 
414           print_whsp(ss);
415 
416           print_extensions(ss, syn->syn_extensions);
417 
418           print_literal(ss,/*(*/ ")");
419 
420           bv->bv_val = safe_strdup(ss);
421           bv->bv_len = ss->pos;
422           safe_string_free(ss);
423           return(bv);
424 }
425 
426 char *
ldap_matchingrule2str(LDAPMatchingRule * mr)427 ldap_matchingrule2str( LDAPMatchingRule * mr )
428 {
429           struct berval bv;
430           if (ldap_matchingrule2bv( mr, &bv ))
431                     return(bv.bv_val);
432           else
433                     return NULL;
434 }
435 
436 struct berval *
ldap_matchingrule2bv(LDAPMatchingRule * mr,struct berval * bv)437 ldap_matchingrule2bv( LDAPMatchingRule * mr, struct berval *bv )
438 {
439           safe_string * ss;
440 
441           if ( !mr || !bv )
442                     return NULL;
443 
444           ss = new_safe_string(256);
445           if ( !ss )
446                     return NULL;
447 
448           print_literal(ss,"(" /*)*/);
449           print_whsp(ss);
450 
451           print_numericoid(ss, mr->mr_oid);
452           print_whsp(ss);
453 
454           if ( mr->mr_names ) {
455                     print_literal(ss,"NAME");
456                     print_qdescrs(ss,mr->mr_names);
457           }
458 
459           if ( mr->mr_desc ) {
460                     print_literal(ss,"DESC");
461                     print_qdstring(ss,mr->mr_desc);
462           }
463 
464           if ( mr->mr_obsolete ) {
465                     print_literal(ss, "OBSOLETE");
466                     print_whsp(ss);
467           }
468 
469           if ( mr->mr_syntax_oid ) {
470                     print_literal(ss,"SYNTAX");
471                     print_whsp(ss);
472                     print_literal(ss, mr->mr_syntax_oid);
473                     print_whsp(ss);
474           }
475 
476           print_whsp(ss);
477 
478           print_extensions(ss, mr->mr_extensions);
479 
480           print_literal(ss,/*(*/")");
481 
482           bv->bv_val = safe_strdup(ss);
483           bv->bv_len = ss->pos;
484           safe_string_free(ss);
485           return(bv);
486 }
487 
488 char *
ldap_matchingruleuse2str(LDAPMatchingRuleUse * mru)489 ldap_matchingruleuse2str( LDAPMatchingRuleUse * mru )
490 {
491           struct berval bv;
492           if (ldap_matchingruleuse2bv( mru, &bv ))
493                     return(bv.bv_val);
494           else
495                     return NULL;
496 }
497 
498 struct berval *
ldap_matchingruleuse2bv(LDAPMatchingRuleUse * mru,struct berval * bv)499 ldap_matchingruleuse2bv( LDAPMatchingRuleUse * mru, struct berval *bv )
500 {
501           safe_string * ss;
502 
503           if ( !mru || !bv )
504                     return NULL;
505 
506           ss = new_safe_string(256);
507           if ( !ss )
508                     return NULL;
509 
510           print_literal(ss,"(" /*)*/);
511           print_whsp(ss);
512 
513           print_numericoid(ss, mru->mru_oid);
514           print_whsp(ss);
515 
516           if ( mru->mru_names ) {
517                     print_literal(ss,"NAME");
518                     print_qdescrs(ss,mru->mru_names);
519           }
520 
521           if ( mru->mru_desc ) {
522                     print_literal(ss,"DESC");
523                     print_qdstring(ss,mru->mru_desc);
524           }
525 
526           if ( mru->mru_obsolete ) {
527                     print_literal(ss, "OBSOLETE");
528                     print_whsp(ss);
529           }
530 
531           if ( mru->mru_applies_oids ) {
532                     print_literal(ss,"APPLIES");
533                     print_whsp(ss);
534                     print_oids(ss, mru->mru_applies_oids);
535                     print_whsp(ss);
536           }
537 
538           print_whsp(ss);
539 
540           print_extensions(ss, mru->mru_extensions);
541 
542           print_literal(ss,/*(*/")");
543 
544           bv->bv_val = safe_strdup(ss);
545           bv->bv_len = ss->pos;
546           safe_string_free(ss);
547           return(bv);
548 }
549 
550 char *
ldap_objectclass2str(LDAPObjectClass * oc)551 ldap_objectclass2str( LDAPObjectClass * oc )
552 {
553           struct berval bv;
554           if (ldap_objectclass2bv( oc, &bv ))
555                     return(bv.bv_val);
556           else
557                     return NULL;
558 }
559 
560 struct berval *
ldap_objectclass2bv(LDAPObjectClass * oc,struct berval * bv)561 ldap_objectclass2bv( LDAPObjectClass * oc, struct berval *bv )
562 {
563           safe_string * ss;
564 
565           if ( !oc || !bv )
566                     return NULL;
567 
568           ss = new_safe_string(256);
569           if ( !ss )
570                     return NULL;
571 
572           print_literal(ss,"("/*)*/);
573           print_whsp(ss);
574 
575           print_numericoid(ss, oc->oc_oid);
576           print_whsp(ss);
577 
578           if ( oc->oc_names ) {
579                     print_literal(ss,"NAME");
580                     print_qdescrs(ss,oc->oc_names);
581           }
582 
583           if ( oc->oc_desc ) {
584                     print_literal(ss,"DESC");
585                     print_qdstring(ss,oc->oc_desc);
586           }
587 
588           if ( oc->oc_obsolete ) {
589                     print_literal(ss, "OBSOLETE");
590                     print_whsp(ss);
591           }
592 
593           if ( oc->oc_sup_oids ) {
594                     print_literal(ss,"SUP");
595                     print_whsp(ss);
596                     print_oids(ss,oc->oc_sup_oids);
597                     print_whsp(ss);
598           }
599 
600           switch (oc->oc_kind) {
601           case LDAP_SCHEMA_ABSTRACT:
602                     print_literal(ss,"ABSTRACT");
603                     break;
604           case LDAP_SCHEMA_STRUCTURAL:
605                     print_literal(ss,"STRUCTURAL");
606                     break;
607           case LDAP_SCHEMA_AUXILIARY:
608                     print_literal(ss,"AUXILIARY");
609                     break;
610           default:
611                     print_literal(ss,"KIND-UNKNOWN");
612                     break;
613           }
614           print_whsp(ss);
615 
616           if ( oc->oc_at_oids_must ) {
617                     print_literal(ss,"MUST");
618                     print_whsp(ss);
619                     print_oids(ss,oc->oc_at_oids_must);
620                     print_whsp(ss);
621           }
622 
623           if ( oc->oc_at_oids_may ) {
624                     print_literal(ss,"MAY");
625                     print_whsp(ss);
626                     print_oids(ss,oc->oc_at_oids_may);
627                     print_whsp(ss);
628           }
629 
630           print_whsp(ss);
631 
632           print_extensions(ss, oc->oc_extensions);
633 
634           print_literal(ss, /*(*/")");
635 
636           bv->bv_val = safe_strdup(ss);
637           bv->bv_len = ss->pos;
638           safe_string_free(ss);
639           return(bv);
640 }
641 
642 char *
ldap_contentrule2str(LDAPContentRule * cr)643 ldap_contentrule2str( LDAPContentRule * cr )
644 {
645           struct berval bv;
646           if (ldap_contentrule2bv( cr, &bv ))
647                     return(bv.bv_val);
648           else
649                     return NULL;
650 }
651 
652 struct berval *
ldap_contentrule2bv(LDAPContentRule * cr,struct berval * bv)653 ldap_contentrule2bv( LDAPContentRule * cr, struct berval *bv )
654 {
655           safe_string * ss;
656 
657           if ( !cr || !bv )
658                     return NULL;
659 
660           ss = new_safe_string(256);
661           if ( !ss )
662                     return NULL;
663 
664           print_literal(ss,"("/*)*/);
665           print_whsp(ss);
666 
667           print_numericoid(ss, cr->cr_oid);
668           print_whsp(ss);
669 
670           if ( cr->cr_names ) {
671                     print_literal(ss,"NAME");
672                     print_qdescrs(ss,cr->cr_names);
673           }
674 
675           if ( cr->cr_desc ) {
676                     print_literal(ss,"DESC");
677                     print_qdstring(ss,cr->cr_desc);
678           }
679 
680           if ( cr->cr_obsolete ) {
681                     print_literal(ss, "OBSOLETE");
682                     print_whsp(ss);
683           }
684 
685           if ( cr->cr_oc_oids_aux ) {
686                     print_literal(ss,"AUX");
687                     print_whsp(ss);
688                     print_oids(ss,cr->cr_oc_oids_aux);
689                     print_whsp(ss);
690           }
691 
692           if ( cr->cr_at_oids_must ) {
693                     print_literal(ss,"MUST");
694                     print_whsp(ss);
695                     print_oids(ss,cr->cr_at_oids_must);
696                     print_whsp(ss);
697           }
698 
699           if ( cr->cr_at_oids_may ) {
700                     print_literal(ss,"MAY");
701                     print_whsp(ss);
702                     print_oids(ss,cr->cr_at_oids_may);
703                     print_whsp(ss);
704           }
705 
706           if ( cr->cr_at_oids_not ) {
707                     print_literal(ss,"NOT");
708                     print_whsp(ss);
709                     print_oids(ss,cr->cr_at_oids_not);
710                     print_whsp(ss);
711           }
712 
713           print_whsp(ss);
714           print_extensions(ss, cr->cr_extensions);
715 
716           print_literal(ss, /*(*/")");
717 
718           bv->bv_val = safe_strdup(ss);
719           bv->bv_len = ss->pos;
720           safe_string_free(ss);
721           return(bv);
722 }
723 
724 char *
ldap_structurerule2str(LDAPStructureRule * sr)725 ldap_structurerule2str( LDAPStructureRule * sr )
726 {
727           struct berval bv;
728           if (ldap_structurerule2bv( sr, &bv ))
729                     return(bv.bv_val);
730           else
731                     return NULL;
732 }
733 
734 struct berval *
ldap_structurerule2bv(LDAPStructureRule * sr,struct berval * bv)735 ldap_structurerule2bv( LDAPStructureRule * sr, struct berval *bv )
736 {
737           safe_string * ss;
738 
739           if ( !sr || !bv )
740                     return NULL;
741 
742           ss = new_safe_string(256);
743           if ( !ss )
744                     return NULL;
745 
746           print_literal(ss,"("/*)*/);
747           print_whsp(ss);
748 
749           print_ruleid(ss, sr->sr_ruleid);
750           print_whsp(ss);
751 
752           if ( sr->sr_names ) {
753                     print_literal(ss,"NAME");
754                     print_qdescrs(ss,sr->sr_names);
755           }
756 
757           if ( sr->sr_desc ) {
758                     print_literal(ss,"DESC");
759                     print_qdstring(ss,sr->sr_desc);
760           }
761 
762           if ( sr->sr_obsolete ) {
763                     print_literal(ss, "OBSOLETE");
764                     print_whsp(ss);
765           }
766 
767           print_literal(ss,"FORM");
768           print_whsp(ss);
769           print_woid(ss,sr->sr_nameform);
770           print_whsp(ss);
771 
772           if ( sr->sr_nsup_ruleids ) {
773                     print_literal(ss,"SUP");
774                     print_whsp(ss);
775                     print_ruleids(ss,sr->sr_nsup_ruleids,sr->sr_sup_ruleids);
776                     print_whsp(ss);
777           }
778 
779           print_whsp(ss);
780           print_extensions(ss, sr->sr_extensions);
781 
782           print_literal(ss, /*(*/")");
783 
784           bv->bv_val = safe_strdup(ss);
785           bv->bv_len = ss->pos;
786           safe_string_free(ss);
787           return(bv);
788 }
789 
790 
791 char *
ldap_nameform2str(LDAPNameForm * nf)792 ldap_nameform2str( LDAPNameForm * nf )
793 {
794           struct berval bv;
795           if (ldap_nameform2bv( nf, &bv ))
796                     return(bv.bv_val);
797           else
798                     return NULL;
799 }
800 
801 struct berval *
ldap_nameform2bv(LDAPNameForm * nf,struct berval * bv)802 ldap_nameform2bv( LDAPNameForm * nf, struct berval *bv )
803 {
804           safe_string * ss;
805 
806           if ( !nf || !bv )
807                     return NULL;
808 
809           ss = new_safe_string(256);
810           if ( !ss )
811                     return NULL;
812 
813           print_literal(ss,"("/*)*/);
814           print_whsp(ss);
815 
816           print_numericoid(ss, nf->nf_oid);
817           print_whsp(ss);
818 
819           if ( nf->nf_names ) {
820                     print_literal(ss,"NAME");
821                     print_qdescrs(ss,nf->nf_names);
822           }
823 
824           if ( nf->nf_desc ) {
825                     print_literal(ss,"DESC");
826                     print_qdstring(ss,nf->nf_desc);
827           }
828 
829           if ( nf->nf_obsolete ) {
830                     print_literal(ss, "OBSOLETE");
831                     print_whsp(ss);
832           }
833 
834           print_literal(ss,"OC");
835           print_whsp(ss);
836           print_woid(ss,nf->nf_objectclass);
837           print_whsp(ss);
838 
839           print_literal(ss,"MUST");
840           print_whsp(ss);
841           print_oids(ss,nf->nf_at_oids_must);
842           print_whsp(ss);
843 
844 
845           if ( nf->nf_at_oids_may ) {
846                     print_literal(ss,"MAY");
847                     print_whsp(ss);
848                     print_oids(ss,nf->nf_at_oids_may);
849                     print_whsp(ss);
850           }
851 
852           print_whsp(ss);
853           print_extensions(ss, nf->nf_extensions);
854 
855           print_literal(ss, /*(*/")");
856 
857           bv->bv_val = safe_strdup(ss);
858           bv->bv_len = ss->pos;
859           safe_string_free(ss);
860           return(bv);
861 }
862 
863 char *
ldap_attributetype2str(LDAPAttributeType * at)864 ldap_attributetype2str( LDAPAttributeType * at )
865 {
866           struct berval bv;
867           if (ldap_attributetype2bv( at, &bv ))
868                     return(bv.bv_val);
869           else
870                     return NULL;
871 }
872 
873 struct berval *
ldap_attributetype2bv(LDAPAttributeType * at,struct berval * bv)874 ldap_attributetype2bv(  LDAPAttributeType * at, struct berval *bv )
875 {
876           safe_string * ss;
877 
878           if ( !at || !bv )
879                     return NULL;
880 
881           ss = new_safe_string(256);
882           if ( !ss )
883                     return NULL;
884 
885           print_literal(ss,"("/*)*/);
886           print_whsp(ss);
887 
888           print_numericoid(ss, at->at_oid);
889           print_whsp(ss);
890 
891           if ( at->at_names ) {
892                     print_literal(ss,"NAME");
893                     print_qdescrs(ss,at->at_names);
894           }
895 
896           if ( at->at_desc ) {
897                     print_literal(ss,"DESC");
898                     print_qdstring(ss,at->at_desc);
899           }
900 
901           if ( at->at_obsolete ) {
902                     print_literal(ss, "OBSOLETE");
903                     print_whsp(ss);
904           }
905 
906           if ( at->at_sup_oid ) {
907                     print_literal(ss,"SUP");
908                     print_woid(ss,at->at_sup_oid);
909           }
910 
911           if ( at->at_equality_oid ) {
912                     print_literal(ss,"EQUALITY");
913                     print_woid(ss,at->at_equality_oid);
914           }
915 
916           if ( at->at_ordering_oid ) {
917                     print_literal(ss,"ORDERING");
918                     print_woid(ss,at->at_ordering_oid);
919           }
920 
921           if ( at->at_substr_oid ) {
922                     print_literal(ss,"SUBSTR");
923                     print_woid(ss,at->at_substr_oid);
924           }
925 
926           if ( at->at_syntax_oid ) {
927                     print_literal(ss,"SYNTAX");
928                     print_whsp(ss);
929                     print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
930                     print_whsp(ss);
931           }
932 
933           if ( at->at_single_value == LDAP_SCHEMA_YES ) {
934                     print_literal(ss,"SINGLE-VALUE");
935                     print_whsp(ss);
936           }
937 
938           if ( at->at_collective == LDAP_SCHEMA_YES ) {
939                     print_literal(ss,"COLLECTIVE");
940                     print_whsp(ss);
941           }
942 
943           if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
944                     print_literal(ss,"NO-USER-MODIFICATION");
945                     print_whsp(ss);
946           }
947 
948           if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
949                     print_literal(ss,"USAGE");
950                     print_whsp(ss);
951                     switch (at->at_usage) {
952                     case LDAP_SCHEMA_DIRECTORY_OPERATION:
953                               print_literal(ss,"directoryOperation");
954                               break;
955                     case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
956                               print_literal(ss,"distributedOperation");
957                               break;
958                     case LDAP_SCHEMA_DSA_OPERATION:
959                               print_literal(ss,"dSAOperation");
960                               break;
961                     default:
962                               print_literal(ss,"UNKNOWN");
963                               break;
964                     }
965           }
966 
967           print_whsp(ss);
968 
969           print_extensions(ss, at->at_extensions);
970 
971           print_literal(ss,/*(*/")");
972 
973           bv->bv_val = safe_strdup(ss);
974           bv->bv_len = ss->pos;
975           safe_string_free(ss);
976           return(bv);
977 }
978 
979 /*
980  * Now come the parsers.  There is one parser for each entity type:
981  * objectclasses, attributetypes, etc.
982  *
983  * Each of them is written as a recursive-descent parser, except that
984  * none of them is really recursive.  But the idea is kept: there
985  * is one routine per non-terminal that either gobbles lexical tokens
986  * or calls lower-level routines, etc.
987  *
988  * The scanner is implemented in the routine get_token.  Actually,
989  * get_token is more than a scanner and will return tokens that are
990  * in fact non-terminals in the grammar.  So you can see the whole
991  * approach as the combination of a low-level bottom-up recognizer
992  * combined with a scanner and a number of top-down parsers.  Or just
993  * consider that the real grammars recognized by the parsers are not
994  * those of the standards.  As a matter of fact, our parsers are more
995  * liberal than the spec when there is no ambiguity.
996  *
997  * The difference is pretty academic (modulo bugs or incorrect
998  * interpretation of the specs).
999  */
1000 
1001 typedef enum tk_t {
1002           TK_NOENDQUOTE       = -2,
1003           TK_OUTOFMEM         = -1,
1004           TK_EOS              = 0,
1005           TK_UNEXPCHAR        = 1,
1006           TK_BAREWORD         = 2,
1007           TK_QDSTRING         = 3,
1008           TK_LEFTPAREN        = 4,
1009           TK_RIGHTPAREN       = 5,
1010           TK_DOLLAR = 6,
1011           TK_QDESCR = TK_QDSTRING
1012 } tk_t;
1013 
1014 static tk_t
get_token(const char ** sp,char ** token_val)1015 get_token( const char ** sp, char ** token_val )
1016 {
1017           tk_t kind;
1018           const char * p;
1019           const char * q;
1020           char * res;
1021 
1022           *token_val = NULL;
1023           switch (**sp) {
1024           case '\0':
1025                     kind = TK_EOS;
1026                     (*sp)++;
1027                     break;
1028           case '(':
1029                     kind = TK_LEFTPAREN;
1030                     (*sp)++;
1031                     break;
1032           case ')':
1033                     kind = TK_RIGHTPAREN;
1034                     (*sp)++;
1035                     break;
1036           case '$':
1037                     kind = TK_DOLLAR;
1038                     (*sp)++;
1039                     break;
1040           case '\'':
1041                     kind = TK_QDSTRING;
1042                     (*sp)++;
1043                     p = *sp;
1044                     while ( **sp != '\'' && **sp != '\0' )
1045                               (*sp)++;
1046                     if ( **sp == '\'' ) {
1047                               q = *sp;
1048                               res = LDAP_MALLOC(q-p+1);
1049                               if ( !res ) {
1050                                         kind = TK_OUTOFMEM;
1051                               } else {
1052                                         strncpy(res,p,q-p);
1053                                         res[q-p] = '\0';
1054                                         *token_val = res;
1055                               }
1056                               (*sp)++;
1057                     } else {
1058                               kind = TK_NOENDQUOTE;
1059                     }
1060                     break;
1061           default:
1062                     kind = TK_BAREWORD;
1063                     p = *sp;
1064                     while ( !LDAP_SPACE(**sp) &&
1065                               **sp != '(' &&
1066                               **sp != ')' &&
1067                               **sp != '$' &&
1068                               **sp != '\'' &&
1069                               /* for suggested minimum upper bound on the number
1070                                * of characters (RFC 4517) */
1071                               **sp != '{' &&
1072                               **sp != '\0' )
1073                               (*sp)++;
1074                     q = *sp;
1075                     res = LDAP_MALLOC(q-p+1);
1076                     if ( !res ) {
1077                               kind = TK_OUTOFMEM;
1078                     } else {
1079                               strncpy(res,p,q-p);
1080                               res[q-p] = '\0';
1081                               *token_val = res;
1082                     }
1083                     break;
1084 /*                  kind = TK_UNEXPCHAR; */
1085 /*                  break; */
1086           }
1087 
1088           return kind;
1089 }
1090 
1091 /* Gobble optional whitespace */
1092 static void
parse_whsp(const char ** sp)1093 parse_whsp(const char **sp)
1094 {
1095           while (LDAP_SPACE(**sp))
1096                     (*sp)++;
1097 }
1098 
1099 /* TBC:!!
1100  * General note for all parsers: to guarantee the algorithm halts they
1101  * must always advance the pointer even when an error is found.  For
1102  * this one is not that important since an error here is fatal at the
1103  * upper layers, but it is a simple strategy that will not get in
1104  * endless loops.
1105  */
1106 
1107 /* Parse a sequence of dot-separated decimal strings */
1108 char *
ldap_int_parse_numericoid(const char ** sp,int * code,const int flags)1109 ldap_int_parse_numericoid(const char **sp, int *code, const int flags)
1110 {
1111           char * res = NULL;
1112           const char * start = *sp;
1113           int len;
1114           int quoted = 0;
1115 
1116           /* Netscape puts the SYNTAX value in quotes (incorrectly) */
1117           if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && **sp == '\'' ) {
1118                     quoted = 1;
1119                     (*sp)++;
1120                     start++;
1121           }
1122           /* Each iteration of this loop gets one decimal string */
1123           while (**sp) {
1124                     if ( !LDAP_DIGIT(**sp) ) {
1125                               /*
1126                                * Initial char is not a digit or char after dot is
1127                                * not a digit
1128                                */
1129                               *code = LDAP_SCHERR_NODIGIT;
1130                               return NULL;
1131                     }
1132                     (*sp)++;
1133                     while ( LDAP_DIGIT(**sp) )
1134                               (*sp)++;
1135                     if ( **sp != '.' )
1136                               break;
1137                     /* Otherwise, gobble the dot and loop again */
1138                     (*sp)++;
1139           }
1140           /* Now *sp points at the char past the numericoid. Perfect. */
1141           len = *sp - start;
1142           if ( flags & LDAP_SCHEMA_ALLOW_QUOTED && quoted ) {
1143                     if ( **sp == '\'' ) {
1144                               (*sp)++;
1145                     } else {
1146                               *code = LDAP_SCHERR_UNEXPTOKEN;
1147                               return NULL;
1148                     }
1149           }
1150           if (flags & LDAP_SCHEMA_SKIP) {
1151                     res = (char *)start;
1152           } else {
1153                     res = LDAP_MALLOC(len+1);
1154                     if (!res) {
1155                               *code = LDAP_SCHERR_OUTOFMEM;
1156                               return(NULL);
1157                     }
1158                     strncpy(res,start,len);
1159                     res[len] = '\0';
1160           }
1161           return(res);
1162 }
1163 
1164 /* Parse a sequence of dot-separated decimal strings */
1165 int
ldap_int_parse_ruleid(const char ** sp,int * code,const int flags,int * ruleid)1166 ldap_int_parse_ruleid(const char **sp, int *code, const int flags, int *ruleid)
1167 {
1168           *ruleid=0;
1169 
1170           if ( !LDAP_DIGIT(**sp) ) {
1171                     *code = LDAP_SCHERR_NODIGIT;
1172                     return -1;
1173           }
1174           *ruleid = (**sp) - '0';
1175           (*sp)++;
1176 
1177           while ( LDAP_DIGIT(**sp) ) {
1178                     *ruleid *= 10;
1179                     *ruleid += (**sp) - '0';
1180                     (*sp)++;
1181           }
1182 
1183           return 0;
1184 }
1185 
1186 /* Parse a qdescr or a list of them enclosed in () */
1187 static char **
parse_qdescrs(const char ** sp,int * code)1188 parse_qdescrs(const char **sp, int *code)
1189 {
1190           char ** res;
1191           char ** res1;
1192           tk_t kind;
1193           char * sval;
1194           int size;
1195           int pos;
1196 
1197           parse_whsp(sp);
1198           kind = get_token(sp,&sval);
1199           if ( kind == TK_LEFTPAREN ) {
1200                     /* Let's presume there will be at least 2 entries */
1201                     size = 3;
1202                     res = LDAP_CALLOC(3,sizeof(char *));
1203                     if ( !res ) {
1204                               *code = LDAP_SCHERR_OUTOFMEM;
1205                               return NULL;
1206                     }
1207                     pos = 0;
1208                     while (1) {
1209                               parse_whsp(sp);
1210                               kind = get_token(sp,&sval);
1211                               if ( kind == TK_RIGHTPAREN )
1212                                         break;
1213                               if ( kind == TK_QDESCR ) {
1214                                         if ( pos == size-2 ) {
1215                                                   size++;
1216                                                   res1 = LDAP_REALLOC(res,size*sizeof(char *));
1217                                                   if ( !res1 ) {
1218                                                             LDAP_VFREE(res);
1219                                                             LDAP_FREE(sval);
1220                                                             *code = LDAP_SCHERR_OUTOFMEM;
1221                                                             return(NULL);
1222                                                   }
1223                                                   res = res1;
1224                                         }
1225                                         res[pos++] = sval;
1226                                         res[pos] = NULL;
1227                                         parse_whsp(sp);
1228                               } else {
1229                                         LDAP_VFREE(res);
1230                                         LDAP_FREE(sval);
1231                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1232                                         return(NULL);
1233                               }
1234                     }
1235                     parse_whsp(sp);
1236                     return(res);
1237           } else if ( kind == TK_QDESCR ) {
1238                     res = LDAP_CALLOC(2,sizeof(char *));
1239                     if ( !res ) {
1240                               *code = LDAP_SCHERR_OUTOFMEM;
1241                               return NULL;
1242                     }
1243                     res[0] = sval;
1244                     res[1] = NULL;
1245                     parse_whsp(sp);
1246                     return res;
1247           } else {
1248                     LDAP_FREE(sval);
1249                     *code = LDAP_SCHERR_BADNAME;
1250                     return NULL;
1251           }
1252 }
1253 
1254 /* Parse a woid */
1255 static char *
parse_woid(const char ** sp,int * code)1256 parse_woid(const char **sp, int *code)
1257 {
1258           char * sval;
1259           tk_t kind;
1260 
1261           parse_whsp(sp);
1262           kind = get_token(sp, &sval);
1263           if ( kind != TK_BAREWORD ) {
1264                     LDAP_FREE(sval);
1265                     *code = LDAP_SCHERR_UNEXPTOKEN;
1266                     return NULL;
1267           }
1268           parse_whsp(sp);
1269           return sval;
1270 }
1271 
1272 /* Parse a noidlen */
1273 static char *
parse_noidlen(const char ** sp,int * code,int * len,int flags)1274 parse_noidlen(const char **sp, int *code, int *len, int flags)
1275 {
1276           char * sval;
1277           const char *savepos;
1278           int quoted = 0;
1279           int allow_quoted = ( flags & LDAP_SCHEMA_ALLOW_QUOTED );
1280           int allow_oidmacro = ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO );
1281 
1282           *len = 0;
1283           /* Netscape puts the SYNTAX value in quotes (incorrectly) */
1284           if ( allow_quoted && **sp == '\'' ) {
1285                     quoted = 1;
1286                     (*sp)++;
1287           }
1288           savepos = *sp;
1289           sval = ldap_int_parse_numericoid(sp, code, 0);
1290           if ( !sval ) {
1291                     if ( allow_oidmacro
1292                               && *sp == savepos
1293                               && *code == LDAP_SCHERR_NODIGIT )
1294                     {
1295                               if ( get_token(sp, &sval) != TK_BAREWORD ) {
1296                                         if ( sval != NULL ) {
1297                                                   LDAP_FREE(sval);
1298                                         }
1299                                         return NULL;
1300                               }
1301                     } else {
1302                               return NULL;
1303                     }
1304           }
1305           if ( **sp == '{' /*}*/ ) {
1306                     (*sp)++;
1307                     *len = atoi(*sp);
1308                     while ( LDAP_DIGIT(**sp) )
1309                               (*sp)++;
1310                     if ( **sp != /*{*/ '}' ) {
1311                               *code = LDAP_SCHERR_UNEXPTOKEN;
1312                               LDAP_FREE(sval);
1313                               return NULL;
1314                     }
1315                     (*sp)++;
1316           }
1317           if ( allow_quoted && quoted ) {
1318                     if ( **sp == '\'' ) {
1319                               (*sp)++;
1320                     } else {
1321                               *code = LDAP_SCHERR_UNEXPTOKEN;
1322                               LDAP_FREE(sval);
1323                               return NULL;
1324                     }
1325           }
1326           return sval;
1327 }
1328 
1329 /*
1330  * Next routine will accept a qdstring in place of an oid if
1331  * allow_quoted is set.  This is necessary to interoperate with
1332  * Netscape Directory server that will improperly quote each oid (at
1333  * least those of the descr kind) in the SUP clause.
1334  */
1335 
1336 /* Parse a woid or a $-separated list of them enclosed in () */
1337 static char **
parse_oids(const char ** sp,int * code,const int allow_quoted)1338 parse_oids(const char **sp, int *code, const int allow_quoted)
1339 {
1340           char ** res;
1341           char ** res1;
1342           tk_t kind;
1343           char * sval;
1344           int size;
1345           int pos;
1346 
1347           /*
1348            * Strictly speaking, doing this here accepts whsp before the
1349            * ( at the beginning of an oidlist, but this is harmless.  Also,
1350            * we are very liberal in what we accept as an OID.  Maybe
1351            * refine later.
1352            */
1353           parse_whsp(sp);
1354           kind = get_token(sp,&sval);
1355           if ( kind == TK_LEFTPAREN ) {
1356                     /* Let's presume there will be at least 2 entries */
1357                     size = 3;
1358                     res = LDAP_CALLOC(3,sizeof(char *));
1359                     if ( !res ) {
1360                               *code = LDAP_SCHERR_OUTOFMEM;
1361                               return NULL;
1362                     }
1363                     pos = 0;
1364                     parse_whsp(sp);
1365                     kind = get_token(sp,&sval);
1366                     if ( kind == TK_BAREWORD ||
1367                          ( allow_quoted && kind == TK_QDSTRING ) ) {
1368                               res[pos++] = sval;
1369                               res[pos] = NULL;
1370                     } else if ( kind == TK_RIGHTPAREN ) {
1371                               /* FIXME: be liberal in what we accept... */
1372                               parse_whsp(sp);
1373                               LDAP_FREE(res);
1374                               return NULL;
1375                     } else {
1376                               *code = LDAP_SCHERR_UNEXPTOKEN;
1377                               LDAP_FREE(sval);
1378                               LDAP_VFREE(res);
1379                               return NULL;
1380                     }
1381                     parse_whsp(sp);
1382                     while (1) {
1383                               kind = get_token(sp,&sval);
1384                               if ( kind == TK_RIGHTPAREN )
1385                                         break;
1386                               if ( kind == TK_DOLLAR ) {
1387                                         parse_whsp(sp);
1388                                         kind = get_token(sp,&sval);
1389                                         if ( kind == TK_BAREWORD ||
1390                                              ( allow_quoted &&
1391                                                kind == TK_QDSTRING ) ) {
1392                                                   if ( pos == size-2 ) {
1393                                                             size++;
1394                                                             res1 = LDAP_REALLOC(res,size*sizeof(char *));
1395                                                             if ( !res1 ) {
1396                                                                       LDAP_FREE(sval);
1397                                                                       LDAP_VFREE(res);
1398                                                                       *code = LDAP_SCHERR_OUTOFMEM;
1399                                                                       return(NULL);
1400                                                             }
1401                                                             res = res1;
1402                                                   }
1403                                                   res[pos++] = sval;
1404                                                   res[pos] = NULL;
1405                                         } else {
1406                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
1407                                                   LDAP_FREE(sval);
1408                                                   LDAP_VFREE(res);
1409                                                   return NULL;
1410                                         }
1411                                         parse_whsp(sp);
1412                               } else {
1413                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1414                                         LDAP_FREE(sval);
1415                                         LDAP_VFREE(res);
1416                                         return NULL;
1417                               }
1418                     }
1419                     parse_whsp(sp);
1420                     return(res);
1421           } else if ( kind == TK_BAREWORD ||
1422                         ( allow_quoted && kind == TK_QDSTRING ) ) {
1423                     res = LDAP_CALLOC(2,sizeof(char *));
1424                     if ( !res ) {
1425                               LDAP_FREE(sval);
1426                               *code = LDAP_SCHERR_OUTOFMEM;
1427                               return NULL;
1428                     }
1429                     res[0] = sval;
1430                     res[1] = NULL;
1431                     parse_whsp(sp);
1432                     return res;
1433           } else {
1434                     LDAP_FREE(sval);
1435                     *code = LDAP_SCHERR_BADNAME;
1436                     return NULL;
1437           }
1438 }
1439 
1440 static int
add_extension(LDAPSchemaExtensionItem *** extensions,char * name,char ** values)1441 add_extension(LDAPSchemaExtensionItem ***extensions,
1442                 char * name, char ** values)
1443 {
1444           int n;
1445           LDAPSchemaExtensionItem **tmp, *ext;
1446 
1447           ext = LDAP_CALLOC(1, sizeof(LDAPSchemaExtensionItem));
1448           if ( !ext )
1449                     return 1;
1450           ext->lsei_name = name;
1451           ext->lsei_values = values;
1452 
1453           if ( !*extensions ) {
1454                     *extensions =
1455                       LDAP_CALLOC(2, sizeof(LDAPSchemaExtensionItem *));
1456                     if ( !*extensions ) {
1457                               LDAP_FREE( ext );
1458                               return 1;
1459                     }
1460                     n = 0;
1461           } else {
1462                     for ( n=0; (*extensions)[n] != NULL; n++ )
1463                               ;
1464                     tmp = LDAP_REALLOC(*extensions,
1465                                            (n+2)*sizeof(LDAPSchemaExtensionItem *));
1466                     if ( !tmp ) {
1467                               LDAP_FREE( ext );
1468                               return 1;
1469                     }
1470                     *extensions = tmp;
1471           }
1472           (*extensions)[n] = ext;
1473           (*extensions)[n+1] = NULL;
1474           return 0;
1475 }
1476 
1477 static void
free_extensions(LDAPSchemaExtensionItem ** extensions)1478 free_extensions(LDAPSchemaExtensionItem **extensions)
1479 {
1480           LDAPSchemaExtensionItem **ext;
1481 
1482           if ( extensions ) {
1483                     for ( ext = extensions; *ext != NULL; ext++ ) {
1484                               LDAP_FREE((*ext)->lsei_name);
1485                               LDAP_VFREE((*ext)->lsei_values);
1486                               LDAP_FREE(*ext);
1487                     }
1488                     LDAP_FREE(extensions);
1489           }
1490 }
1491 
1492 void
ldap_syntax_free(LDAPSyntax * syn)1493 ldap_syntax_free( LDAPSyntax * syn )
1494 {
1495           if ( !syn ) return;
1496           LDAP_FREE(syn->syn_oid);
1497           if (syn->syn_names) LDAP_VFREE(syn->syn_names);
1498           if (syn->syn_desc) LDAP_FREE(syn->syn_desc);
1499           free_extensions(syn->syn_extensions);
1500           LDAP_FREE(syn);
1501 }
1502 
1503 LDAPSyntax *
ldap_str2syntax(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)1504 ldap_str2syntax( LDAP_CONST char * s,
1505           int * code,
1506           LDAP_CONST char ** errp,
1507           LDAP_CONST unsigned flags )
1508 {
1509           tk_t kind;
1510           const char * ss = s;
1511           char * sval;
1512           int seen_name = 0;
1513           int seen_desc = 0;
1514           LDAPSyntax * syn;
1515           char ** ext_vals;
1516 
1517           if ( !s ) {
1518                     *code = LDAP_SCHERR_EMPTY;
1519                     *errp = "";
1520                     return NULL;
1521           }
1522 
1523           *errp = s;
1524           syn = LDAP_CALLOC(1,sizeof(LDAPSyntax));
1525 
1526           if ( !syn ) {
1527                     *code = LDAP_SCHERR_OUTOFMEM;
1528                     return NULL;
1529           }
1530 
1531           kind = get_token(&ss,&sval);
1532           if ( kind != TK_LEFTPAREN ) {
1533                     LDAP_FREE(sval);
1534                     *code = LDAP_SCHERR_NOLEFTPAREN;
1535                     ldap_syntax_free(syn);
1536                     return NULL;
1537           }
1538 
1539           parse_whsp(&ss);
1540           syn->syn_oid = ldap_int_parse_numericoid(&ss,code,0);
1541           if ( !syn->syn_oid ) {
1542                     *errp = ss;
1543                     ldap_syntax_free(syn);
1544                     return NULL;
1545           }
1546           parse_whsp(&ss);
1547 
1548           /*
1549            * Beyond this point we will be liberal and accept the items
1550            * in any order.
1551            */
1552           while (1) {
1553                     kind = get_token(&ss,&sval);
1554                     switch (kind) {
1555                     case TK_EOS:
1556                               *code = LDAP_SCHERR_NORIGHTPAREN;
1557                               *errp = EndOfInput;
1558                               ldap_syntax_free(syn);
1559                               return NULL;
1560                     case TK_RIGHTPAREN:
1561                               return syn;
1562                     case TK_BAREWORD:
1563                               if ( !strcasecmp(sval,"NAME") ) {
1564                                         LDAP_FREE(sval);
1565                                         if ( seen_name ) {
1566                                                   *code = LDAP_SCHERR_DUPOPT;
1567                                                   *errp = ss;
1568                                                   ldap_syntax_free(syn);
1569                                                   return(NULL);
1570                                         }
1571                                         seen_name = 1;
1572                                         syn->syn_names = parse_qdescrs(&ss,code);
1573                                         if ( !syn->syn_names ) {
1574                                                   if ( *code != LDAP_SCHERR_OUTOFMEM )
1575                                                             *code = LDAP_SCHERR_BADNAME;
1576                                                   *errp = ss;
1577                                                   ldap_syntax_free(syn);
1578                                                   return NULL;
1579                                         }
1580                               } else if ( !strcasecmp(sval,"DESC") ) {
1581                                         LDAP_FREE(sval);
1582                                         if ( seen_desc ) {
1583                                                   *code = LDAP_SCHERR_DUPOPT;
1584                                                   *errp = ss;
1585                                                   ldap_syntax_free(syn);
1586                                                   return(NULL);
1587                                         }
1588                                         seen_desc = 1;
1589                                         parse_whsp(&ss);
1590                                         kind = get_token(&ss,&sval);
1591                                         if ( kind != TK_QDSTRING ) {
1592                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
1593                                                   *errp = ss;
1594                                                   LDAP_FREE(sval);
1595                                                   ldap_syntax_free(syn);
1596                                                   return NULL;
1597                                         }
1598                                         syn->syn_desc = sval;
1599                                         parse_whsp(&ss);
1600                               } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1601                                         /* Should be parse_qdstrings */
1602                                         ext_vals = parse_qdescrs(&ss, code);
1603                                         if ( !ext_vals ) {
1604                                                   *errp = ss;
1605                                                   ldap_syntax_free(syn);
1606                                                   return NULL;
1607                                         }
1608                                         if ( add_extension(&syn->syn_extensions,
1609                                                                 sval, ext_vals) ) {
1610                                                   *code = LDAP_SCHERR_OUTOFMEM;
1611                                                   *errp = ss;
1612                                                   LDAP_FREE(sval);
1613                                                   ldap_syntax_free(syn);
1614                                                   return NULL;
1615                                         }
1616                               } else {
1617                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1618                                         *errp = ss;
1619                                         LDAP_FREE(sval);
1620                                         ldap_syntax_free(syn);
1621                                         return NULL;
1622                               }
1623                               break;
1624                     default:
1625                               *code = LDAP_SCHERR_UNEXPTOKEN;
1626                               *errp = ss;
1627                               LDAP_FREE(sval);
1628                               ldap_syntax_free(syn);
1629                               return NULL;
1630                     }
1631           }
1632 }
1633 
1634 void
ldap_matchingrule_free(LDAPMatchingRule * mr)1635 ldap_matchingrule_free( LDAPMatchingRule * mr )
1636 {
1637           if (!mr) return;
1638           LDAP_FREE(mr->mr_oid);
1639           if (mr->mr_names) LDAP_VFREE(mr->mr_names);
1640           if (mr->mr_desc) LDAP_FREE(mr->mr_desc);
1641           if (mr->mr_syntax_oid) LDAP_FREE(mr->mr_syntax_oid);
1642           free_extensions(mr->mr_extensions);
1643           LDAP_FREE(mr);
1644 }
1645 
1646 LDAPMatchingRule *
ldap_str2matchingrule(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)1647 ldap_str2matchingrule( LDAP_CONST char * s,
1648           int * code,
1649           LDAP_CONST char ** errp,
1650           LDAP_CONST unsigned flags )
1651 {
1652           tk_t kind;
1653           const char * ss = s;
1654           char * sval;
1655           int seen_name = 0;
1656           int seen_desc = 0;
1657           int seen_obsolete = 0;
1658           int seen_syntax = 0;
1659           LDAPMatchingRule * mr;
1660           char ** ext_vals;
1661           const char * savepos;
1662 
1663           if ( !s ) {
1664                     *code = LDAP_SCHERR_EMPTY;
1665                     *errp = "";
1666                     return NULL;
1667           }
1668 
1669           *errp = s;
1670           mr = LDAP_CALLOC(1,sizeof(LDAPMatchingRule));
1671 
1672           if ( !mr ) {
1673                     *code = LDAP_SCHERR_OUTOFMEM;
1674                     return NULL;
1675           }
1676 
1677           kind = get_token(&ss,&sval);
1678           if ( kind != TK_LEFTPAREN ) {
1679                     *code = LDAP_SCHERR_NOLEFTPAREN;
1680                     LDAP_FREE(sval);
1681                     ldap_matchingrule_free(mr);
1682                     return NULL;
1683           }
1684 
1685           parse_whsp(&ss);
1686           savepos = ss;
1687           mr->mr_oid = ldap_int_parse_numericoid(&ss,code,flags);
1688           if ( !mr->mr_oid ) {
1689                     if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1690                               /* Backtracking */
1691                               ss = savepos;
1692                               kind = get_token(&ss,&sval);
1693                               if ( kind == TK_BAREWORD ) {
1694                                         if ( !strcasecmp(sval, "NAME") ||
1695                                              !strcasecmp(sval, "DESC") ||
1696                                              !strcasecmp(sval, "OBSOLETE") ||
1697                                              !strcasecmp(sval, "SYNTAX") ||
1698                                              !strncasecmp(sval, "X-", 2) ) {
1699                                                   /* Missing OID, backtrack */
1700                                                   ss = savepos;
1701                                         } else {
1702                                                   /* Non-numerical OID, ignore */
1703                                         }
1704                               }
1705                               LDAP_FREE(sval);
1706                     } else {
1707                               *errp = ss;
1708                               ldap_matchingrule_free(mr);
1709                               return NULL;
1710                     }
1711           }
1712           parse_whsp(&ss);
1713 
1714           /*
1715            * Beyond this point we will be liberal and accept the items
1716            * in any order.
1717            */
1718           while (1) {
1719                     kind = get_token(&ss,&sval);
1720                     switch (kind) {
1721                     case TK_EOS:
1722                               *code = LDAP_SCHERR_NORIGHTPAREN;
1723                               *errp = EndOfInput;
1724                               ldap_matchingrule_free(mr);
1725                               return NULL;
1726                     case TK_RIGHTPAREN:
1727                               if( !seen_syntax ) {
1728                                         *code = LDAP_SCHERR_MISSING;
1729                                         ldap_matchingrule_free(mr);
1730                                         return NULL;
1731                               }
1732                               return mr;
1733                     case TK_BAREWORD:
1734                               if ( !strcasecmp(sval,"NAME") ) {
1735                                         LDAP_FREE(sval);
1736                                         if ( seen_name ) {
1737                                                   *code = LDAP_SCHERR_DUPOPT;
1738                                                   *errp = ss;
1739                                                   ldap_matchingrule_free(mr);
1740                                                   return(NULL);
1741                                         }
1742                                         seen_name = 1;
1743                                         mr->mr_names = parse_qdescrs(&ss,code);
1744                                         if ( !mr->mr_names ) {
1745                                                   if ( *code != LDAP_SCHERR_OUTOFMEM )
1746                                                             *code = LDAP_SCHERR_BADNAME;
1747                                                   *errp = ss;
1748                                                   ldap_matchingrule_free(mr);
1749                                                   return NULL;
1750                                         }
1751                               } else if ( !strcasecmp(sval,"DESC") ) {
1752                                         LDAP_FREE(sval);
1753                                         if ( seen_desc ) {
1754                                                   *code = LDAP_SCHERR_DUPOPT;
1755                                                   *errp = ss;
1756                                                   ldap_matchingrule_free(mr);
1757                                                   return(NULL);
1758                                         }
1759                                         seen_desc = 1;
1760                                         parse_whsp(&ss);
1761                                         kind = get_token(&ss,&sval);
1762                                         if ( kind != TK_QDSTRING ) {
1763                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
1764                                                   *errp = ss;
1765                                                   LDAP_FREE(sval);
1766                                                   ldap_matchingrule_free(mr);
1767                                                   return NULL;
1768                                         }
1769                                         mr->mr_desc = sval;
1770                                         parse_whsp(&ss);
1771                               } else if ( !strcasecmp(sval,"OBSOLETE") ) {
1772                                         LDAP_FREE(sval);
1773                                         if ( seen_obsolete ) {
1774                                                   *code = LDAP_SCHERR_DUPOPT;
1775                                                   *errp = ss;
1776                                                   ldap_matchingrule_free(mr);
1777                                                   return(NULL);
1778                                         }
1779                                         seen_obsolete = 1;
1780                                         mr->mr_obsolete = LDAP_SCHEMA_YES;
1781                                         parse_whsp(&ss);
1782                               } else if ( !strcasecmp(sval,"SYNTAX") ) {
1783                                         LDAP_FREE(sval);
1784                                         if ( seen_syntax ) {
1785                                                   *code = LDAP_SCHERR_DUPOPT;
1786                                                   *errp = ss;
1787                                                   ldap_matchingrule_free(mr);
1788                                                   return(NULL);
1789                                         }
1790                                         seen_syntax = 1;
1791                                         parse_whsp(&ss);
1792                                         mr->mr_syntax_oid =
1793                                                   ldap_int_parse_numericoid(&ss,code,flags);
1794                                         if ( !mr->mr_syntax_oid ) {
1795                                                   *errp = ss;
1796                                                   ldap_matchingrule_free(mr);
1797                                                   return NULL;
1798                                         }
1799                                         parse_whsp(&ss);
1800                               } else if ( sval[0] == 'X' && sval[1] == '-' ) {
1801                                         /* Should be parse_qdstrings */
1802                                         ext_vals = parse_qdescrs(&ss, code);
1803                                         if ( !ext_vals ) {
1804                                                   *errp = ss;
1805                                                   ldap_matchingrule_free(mr);
1806                                                   return NULL;
1807                                         }
1808                                         if ( add_extension(&mr->mr_extensions,
1809                                                                 sval, ext_vals) ) {
1810                                                   *code = LDAP_SCHERR_OUTOFMEM;
1811                                                   *errp = ss;
1812                                                   LDAP_FREE(sval);
1813                                                   ldap_matchingrule_free(mr);
1814                                                   return NULL;
1815                                         }
1816                               } else {
1817                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1818                                         *errp = ss;
1819                                         LDAP_FREE(sval);
1820                                         ldap_matchingrule_free(mr);
1821                                         return NULL;
1822                               }
1823                               break;
1824                     default:
1825                               *code = LDAP_SCHERR_UNEXPTOKEN;
1826                               *errp = ss;
1827                               LDAP_FREE(sval);
1828                               ldap_matchingrule_free(mr);
1829                               return NULL;
1830                     }
1831           }
1832 }
1833 
1834 void
ldap_matchingruleuse_free(LDAPMatchingRuleUse * mru)1835 ldap_matchingruleuse_free( LDAPMatchingRuleUse * mru )
1836 {
1837           if (!mru) return;
1838           LDAP_FREE(mru->mru_oid);
1839           if (mru->mru_names) LDAP_VFREE(mru->mru_names);
1840           if (mru->mru_desc) LDAP_FREE(mru->mru_desc);
1841           if (mru->mru_applies_oids) LDAP_VFREE(mru->mru_applies_oids);
1842           free_extensions(mru->mru_extensions);
1843           LDAP_FREE(mru);
1844 }
1845 
1846 LDAPMatchingRuleUse *
ldap_str2matchingruleuse(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)1847 ldap_str2matchingruleuse( LDAP_CONST char * s,
1848           int * code,
1849           LDAP_CONST char ** errp,
1850           LDAP_CONST unsigned flags )
1851 {
1852           tk_t kind;
1853           const char * ss = s;
1854           char * sval;
1855           int seen_name = 0;
1856           int seen_desc = 0;
1857           int seen_obsolete = 0;
1858           int seen_applies = 0;
1859           LDAPMatchingRuleUse * mru;
1860           char ** ext_vals;
1861           const char * savepos;
1862 
1863           if ( !s ) {
1864                     *code = LDAP_SCHERR_EMPTY;
1865                     *errp = "";
1866                     return NULL;
1867           }
1868 
1869           *errp = s;
1870           mru = LDAP_CALLOC(1,sizeof(LDAPMatchingRuleUse));
1871 
1872           if ( !mru ) {
1873                     *code = LDAP_SCHERR_OUTOFMEM;
1874                     return NULL;
1875           }
1876 
1877           kind = get_token(&ss,&sval);
1878           if ( kind != TK_LEFTPAREN ) {
1879                     *code = LDAP_SCHERR_NOLEFTPAREN;
1880                     LDAP_FREE(sval);
1881                     ldap_matchingruleuse_free(mru);
1882                     return NULL;
1883           }
1884 
1885           parse_whsp(&ss);
1886           savepos = ss;
1887           mru->mru_oid = ldap_int_parse_numericoid(&ss,code,flags);
1888           if ( !mru->mru_oid ) {
1889                     if ( flags & LDAP_SCHEMA_ALLOW_NO_OID ) {
1890                               /* Backtracking */
1891                               ss = savepos;
1892                               kind = get_token(&ss,&sval);
1893                               if ( kind == TK_BAREWORD ) {
1894                                         if ( !strcasecmp(sval, "NAME") ||
1895                                              !strcasecmp(sval, "DESC") ||
1896                                              !strcasecmp(sval, "OBSOLETE") ||
1897                                              !strcasecmp(sval, "APPLIES") ||
1898                                              !strncasecmp(sval, "X-", 2) ) {
1899                                                   /* Missing OID, backtrack */
1900                                                   ss = savepos;
1901                                         } else {
1902                                                   /* Non-numerical OID, ignore */
1903                                         }
1904                               }
1905                               LDAP_FREE(sval);
1906                     } else {
1907                               *errp = ss;
1908                               ldap_matchingruleuse_free(mru);
1909                               return NULL;
1910                     }
1911           }
1912           parse_whsp(&ss);
1913 
1914           /*
1915            * Beyond this point we will be liberal and accept the items
1916            * in any order.
1917            */
1918           while (1) {
1919                     kind = get_token(&ss,&sval);
1920                     switch (kind) {
1921                     case TK_EOS:
1922                               *code = LDAP_SCHERR_NORIGHTPAREN;
1923                               *errp = EndOfInput;
1924                               ldap_matchingruleuse_free(mru);
1925                               return NULL;
1926                     case TK_RIGHTPAREN:
1927                               if( !seen_applies ) {
1928                                         *code = LDAP_SCHERR_MISSING;
1929                                         ldap_matchingruleuse_free(mru);
1930                                         return NULL;
1931                               }
1932                               return mru;
1933                     case TK_BAREWORD:
1934                               if ( !strcasecmp(sval,"NAME") ) {
1935                                         LDAP_FREE(sval);
1936                                         if ( seen_name ) {
1937                                                   *code = LDAP_SCHERR_DUPOPT;
1938                                                   *errp = ss;
1939                                                   ldap_matchingruleuse_free(mru);
1940                                                   return(NULL);
1941                                         }
1942                                         seen_name = 1;
1943                                         mru->mru_names = parse_qdescrs(&ss,code);
1944                                         if ( !mru->mru_names ) {
1945                                                   if ( *code != LDAP_SCHERR_OUTOFMEM )
1946                                                             *code = LDAP_SCHERR_BADNAME;
1947                                                   *errp = ss;
1948                                                   ldap_matchingruleuse_free(mru);
1949                                                   return NULL;
1950                                         }
1951                               } else if ( !strcasecmp(sval,"DESC") ) {
1952                                         LDAP_FREE(sval);
1953                                         if ( seen_desc ) {
1954                                                   *code = LDAP_SCHERR_DUPOPT;
1955                                                   *errp = ss;
1956                                                   ldap_matchingruleuse_free(mru);
1957                                                   return(NULL);
1958                                         }
1959                                         seen_desc = 1;
1960                                         parse_whsp(&ss);
1961                                         kind = get_token(&ss,&sval);
1962                                         if ( kind != TK_QDSTRING ) {
1963                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
1964                                                   *errp = ss;
1965                                                   LDAP_FREE(sval);
1966                                                   ldap_matchingruleuse_free(mru);
1967                                                   return NULL;
1968                                         }
1969                                         mru->mru_desc = sval;
1970                                         parse_whsp(&ss);
1971                               } else if ( !strcasecmp(sval,"OBSOLETE") ) {
1972                                         LDAP_FREE(sval);
1973                                         if ( seen_obsolete ) {
1974                                                   *code = LDAP_SCHERR_DUPOPT;
1975                                                   *errp = ss;
1976                                                   ldap_matchingruleuse_free(mru);
1977                                                   return(NULL);
1978                                         }
1979                                         seen_obsolete = 1;
1980                                         mru->mru_obsolete = LDAP_SCHEMA_YES;
1981                                         parse_whsp(&ss);
1982                               } else if ( !strcasecmp(sval,"APPLIES") ) {
1983                                         LDAP_FREE(sval);
1984                                         if ( seen_applies ) {
1985                                                   *code = LDAP_SCHERR_DUPOPT;
1986                                                   *errp = ss;
1987                                                   ldap_matchingruleuse_free(mru);
1988                                                   return(NULL);
1989                                         }
1990                                         seen_applies = 1;
1991                                         mru->mru_applies_oids = parse_oids(&ss,
1992                                                                            code,
1993                                                                            flags);
1994                                         if ( !mru->mru_applies_oids && *code != LDAP_SUCCESS ) {
1995                                                   *errp = ss;
1996                                                   ldap_matchingruleuse_free(mru);
1997                                                   return NULL;
1998                                         }
1999                               } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2000                                         /* Should be parse_qdstrings */
2001                                         ext_vals = parse_qdescrs(&ss, code);
2002                                         if ( !ext_vals ) {
2003                                                   *errp = ss;
2004                                                   ldap_matchingruleuse_free(mru);
2005                                                   return NULL;
2006                                         }
2007                                         if ( add_extension(&mru->mru_extensions,
2008                                                                 sval, ext_vals) ) {
2009                                                   *code = LDAP_SCHERR_OUTOFMEM;
2010                                                   *errp = ss;
2011                                                   LDAP_FREE(sval);
2012                                                   ldap_matchingruleuse_free(mru);
2013                                                   return NULL;
2014                                         }
2015                               } else {
2016                                         *code = LDAP_SCHERR_UNEXPTOKEN;
2017                                         *errp = ss;
2018                                         LDAP_FREE(sval);
2019                                         ldap_matchingruleuse_free(mru);
2020                                         return NULL;
2021                               }
2022                               break;
2023                     default:
2024                               *code = LDAP_SCHERR_UNEXPTOKEN;
2025                               *errp = ss;
2026                               LDAP_FREE(sval);
2027                               ldap_matchingruleuse_free(mru);
2028                               return NULL;
2029                     }
2030           }
2031 }
2032 
2033 void
ldap_attributetype_free(LDAPAttributeType * at)2034 ldap_attributetype_free(LDAPAttributeType * at)
2035 {
2036           if (!at) return;
2037           LDAP_FREE(at->at_oid);
2038           if (at->at_names) LDAP_VFREE(at->at_names);
2039           if (at->at_desc) LDAP_FREE(at->at_desc);
2040           if (at->at_sup_oid) LDAP_FREE(at->at_sup_oid);
2041           if (at->at_equality_oid) LDAP_FREE(at->at_equality_oid);
2042           if (at->at_ordering_oid) LDAP_FREE(at->at_ordering_oid);
2043           if (at->at_substr_oid) LDAP_FREE(at->at_substr_oid);
2044           if (at->at_syntax_oid) LDAP_FREE(at->at_syntax_oid);
2045           free_extensions(at->at_extensions);
2046           LDAP_FREE(at);
2047 }
2048 
2049 LDAPAttributeType *
ldap_str2attributetype(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)2050 ldap_str2attributetype( LDAP_CONST char * s,
2051           int * code,
2052           LDAP_CONST char ** errp,
2053           LDAP_CONST unsigned flags )
2054 {
2055           tk_t kind;
2056           const char * ss = s;
2057           char * sval;
2058           int seen_name = 0;
2059           int seen_desc = 0;
2060           int seen_obsolete = 0;
2061           int seen_sup = 0;
2062           int seen_equality = 0;
2063           int seen_ordering = 0;
2064           int seen_substr = 0;
2065           int seen_syntax = 0;
2066           int seen_usage = 0;
2067           LDAPAttributeType * at;
2068           char ** ext_vals;
2069           const char * savepos;
2070 
2071           if ( !s ) {
2072                     *code = LDAP_SCHERR_EMPTY;
2073                     *errp = "";
2074                     return NULL;
2075           }
2076 
2077           *errp = s;
2078           at = LDAP_CALLOC(1,sizeof(LDAPAttributeType));
2079 
2080           if ( !at ) {
2081                     *code = LDAP_SCHERR_OUTOFMEM;
2082                     return NULL;
2083           }
2084 
2085           kind = get_token(&ss,&sval);
2086           if ( kind != TK_LEFTPAREN ) {
2087                     *code = LDAP_SCHERR_NOLEFTPAREN;
2088                     LDAP_FREE(sval);
2089                     ldap_attributetype_free(at);
2090                     return NULL;
2091           }
2092 
2093           /*
2094            * Definitions MUST begin with an OID in the numericoid format.
2095            * However, this routine is used by clients to parse the response
2096            * from servers and very well known servers will provide an OID
2097            * in the wrong format or even no OID at all.  We do our best to
2098            * extract info from those servers.
2099            */
2100           parse_whsp(&ss);
2101           savepos = ss;
2102           at->at_oid = ldap_int_parse_numericoid(&ss,code,0);
2103           if ( !at->at_oid ) {
2104                     if ( ( flags & ( LDAP_SCHEMA_ALLOW_NO_OID
2105                                         | LDAP_SCHEMA_ALLOW_OID_MACRO ) )
2106                                   && (ss == savepos) )
2107                     {
2108                               /* Backtracking */
2109                               ss = savepos;
2110                               kind = get_token(&ss,&sval);
2111                               if ( kind == TK_BAREWORD ) {
2112                                         if ( !strcasecmp(sval, "NAME") ||
2113                                              !strcasecmp(sval, "DESC") ||
2114                                              !strcasecmp(sval, "OBSOLETE") ||
2115                                              !strcasecmp(sval, "SUP") ||
2116                                              !strcasecmp(sval, "EQUALITY") ||
2117                                              !strcasecmp(sval, "ORDERING") ||
2118                                              !strcasecmp(sval, "SUBSTR") ||
2119                                              !strcasecmp(sval, "SYNTAX") ||
2120                                              !strcasecmp(sval, "SINGLE-VALUE") ||
2121                                              !strcasecmp(sval, "COLLECTIVE") ||
2122                                              !strcasecmp(sval, "NO-USER-MODIFICATION") ||
2123                                              !strcasecmp(sval, "USAGE") ||
2124                                              !strncasecmp(sval, "X-", 2) )
2125                                         {
2126                                                   /* Missing OID, backtrack */
2127                                                   ss = savepos;
2128                                         } else if ( flags
2129                                                   & LDAP_SCHEMA_ALLOW_OID_MACRO)
2130                                         {
2131                                                   /* Non-numerical OID ... */
2132                                                   int len = ss-savepos;
2133                                                   at->at_oid = LDAP_MALLOC(len+1);
2134                                                   if ( !at->at_oid ) {
2135                                                             ldap_attributetype_free(at);
2136                                                             return NULL;
2137                                                   }
2138 
2139                                                   strncpy(at->at_oid, savepos, len);
2140                                                   at->at_oid[len] = 0;
2141                                         }
2142                               }
2143                               LDAP_FREE(sval);
2144                     } else {
2145                               *errp = ss;
2146                               ldap_attributetype_free(at);
2147                               return NULL;
2148                     }
2149           }
2150           parse_whsp(&ss);
2151 
2152           /*
2153            * Beyond this point we will be liberal and accept the items
2154            * in any order.
2155            */
2156           while (1) {
2157                     kind = get_token(&ss,&sval);
2158                     switch (kind) {
2159                     case TK_EOS:
2160                               *code = LDAP_SCHERR_NORIGHTPAREN;
2161                               *errp = EndOfInput;
2162                               ldap_attributetype_free(at);
2163                               return NULL;
2164                     case TK_RIGHTPAREN:
2165                               return at;
2166                     case TK_BAREWORD:
2167                               if ( !strcasecmp(sval,"NAME") ) {
2168                                         LDAP_FREE(sval);
2169                                         if ( seen_name ) {
2170                                                   *code = LDAP_SCHERR_DUPOPT;
2171                                                   *errp = ss;
2172                                                   ldap_attributetype_free(at);
2173                                                   return(NULL);
2174                                         }
2175                                         seen_name = 1;
2176                                         at->at_names = parse_qdescrs(&ss,code);
2177                                         if ( !at->at_names ) {
2178                                                   if ( *code != LDAP_SCHERR_OUTOFMEM )
2179                                                             *code = LDAP_SCHERR_BADNAME;
2180                                                   *errp = ss;
2181                                                   ldap_attributetype_free(at);
2182                                                   return NULL;
2183                                         }
2184                               } else if ( !strcasecmp(sval,"DESC") ) {
2185                                         LDAP_FREE(sval);
2186                                         if ( seen_desc ) {
2187                                                   *code = LDAP_SCHERR_DUPOPT;
2188                                                   *errp = ss;
2189                                                   ldap_attributetype_free(at);
2190                                                   return(NULL);
2191                                         }
2192                                         seen_desc = 1;
2193                                         parse_whsp(&ss);
2194                                         kind = get_token(&ss,&sval);
2195                                         if ( kind != TK_QDSTRING ) {
2196                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
2197                                                   *errp = ss;
2198                                                   LDAP_FREE(sval);
2199                                                   ldap_attributetype_free(at);
2200                                                   return NULL;
2201                                         }
2202                                         at->at_desc = sval;
2203                                         parse_whsp(&ss);
2204                               } else if ( !strcasecmp(sval,"OBSOLETE") ) {
2205                                         LDAP_FREE(sval);
2206                                         if ( seen_obsolete ) {
2207                                                   *code = LDAP_SCHERR_DUPOPT;
2208                                                   *errp = ss;
2209                                                   ldap_attributetype_free(at);
2210                                                   return(NULL);
2211                                         }
2212                                         seen_obsolete = 1;
2213                                         at->at_obsolete = LDAP_SCHEMA_YES;
2214                                         parse_whsp(&ss);
2215                               } else if ( !strcasecmp(sval,"SUP") ) {
2216                                         LDAP_FREE(sval);
2217                                         if ( seen_sup ) {
2218                                                   *code = LDAP_SCHERR_DUPOPT;
2219                                                   *errp = ss;
2220                                                   ldap_attributetype_free(at);
2221                                                   return(NULL);
2222                                         }
2223                                         seen_sup = 1;
2224                                         at->at_sup_oid = parse_woid(&ss,code);
2225                                         if ( !at->at_sup_oid ) {
2226                                                   *errp = ss;
2227                                                   ldap_attributetype_free(at);
2228                                                   return NULL;
2229                                         }
2230                               } else if ( !strcasecmp(sval,"EQUALITY") ) {
2231                                         LDAP_FREE(sval);
2232                                         if ( seen_equality ) {
2233                                                   *code = LDAP_SCHERR_DUPOPT;
2234                                                   *errp = ss;
2235                                                   ldap_attributetype_free(at);
2236                                                   return(NULL);
2237                                         }
2238                                         seen_equality = 1;
2239                                         at->at_equality_oid = parse_woid(&ss,code);
2240                                         if ( !at->at_equality_oid ) {
2241                                                   *errp = ss;
2242                                                   ldap_attributetype_free(at);
2243                                                   return NULL;
2244                                         }
2245                               } else if ( !strcasecmp(sval,"ORDERING") ) {
2246                                         LDAP_FREE(sval);
2247                                         if ( seen_ordering ) {
2248                                                   *code = LDAP_SCHERR_DUPOPT;
2249                                                   *errp = ss;
2250                                                   ldap_attributetype_free(at);
2251                                                   return(NULL);
2252                                         }
2253                                         seen_ordering = 1;
2254                                         at->at_ordering_oid = parse_woid(&ss,code);
2255                                         if ( !at->at_ordering_oid ) {
2256                                                   *errp = ss;
2257                                                   ldap_attributetype_free(at);
2258                                                   return NULL;
2259                                         }
2260                               } else if ( !strcasecmp(sval,"SUBSTR") ) {
2261                                         LDAP_FREE(sval);
2262                                         if ( seen_substr ) {
2263                                                   *code = LDAP_SCHERR_DUPOPT;
2264                                                   *errp = ss;
2265                                                   ldap_attributetype_free(at);
2266                                                   return(NULL);
2267                                         }
2268                                         seen_substr = 1;
2269                                         at->at_substr_oid = parse_woid(&ss,code);
2270                                         if ( !at->at_substr_oid ) {
2271                                                   *errp = ss;
2272                                                   ldap_attributetype_free(at);
2273                                                   return NULL;
2274                                         }
2275                               } else if ( !strcasecmp(sval,"SYNTAX") ) {
2276                                         LDAP_FREE(sval);
2277                                         if ( seen_syntax ) {
2278                                                   *code = LDAP_SCHERR_DUPOPT;
2279                                                   *errp = ss;
2280                                                   ldap_attributetype_free(at);
2281                                                   return(NULL);
2282                                         }
2283                                         seen_syntax = 1;
2284                                         parse_whsp(&ss);
2285                                         savepos = ss;
2286                                         at->at_syntax_oid =
2287                                                   parse_noidlen(&ss,
2288                                                                   code,
2289                                                                   &at->at_syntax_len,
2290                                                                   flags);
2291                                         if ( !at->at_syntax_oid ) {
2292                                             if ( flags & LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2293                                                   kind = get_token(&ss,&sval);
2294                                                   if (kind == TK_BAREWORD)
2295                                                   {
2296                                                       char *sp = strchr(sval, '{');
2297                                                       at->at_syntax_oid = sval;
2298                                                       if (sp)
2299                                                       {
2300                                                             *sp++ = 0;
2301                                                             at->at_syntax_len = atoi(sp);
2302                                                             while ( LDAP_DIGIT(*sp) )
2303                                                                       sp++;
2304                                                             if ( *sp != '}' ) {
2305                                                                 *code = LDAP_SCHERR_UNEXPTOKEN;
2306                                                                 *errp = ss;
2307                                                                 ldap_attributetype_free(at);
2308                                                                 return NULL;
2309                                                             }
2310                                                       }
2311                                                   }
2312                                             } else {
2313                                                   *errp = ss;
2314                                                   ldap_attributetype_free(at);
2315                                                   return NULL;
2316                                             }
2317                                         }
2318                                         parse_whsp(&ss);
2319                               } else if ( !strcasecmp(sval,"SINGLE-VALUE") ) {
2320                                         LDAP_FREE(sval);
2321                                         if ( at->at_single_value ) {
2322                                                   *code = LDAP_SCHERR_DUPOPT;
2323                                                   *errp = ss;
2324                                                   ldap_attributetype_free(at);
2325                                                   return(NULL);
2326                                         }
2327                                         at->at_single_value = LDAP_SCHEMA_YES;
2328                                         parse_whsp(&ss);
2329                               } else if ( !strcasecmp(sval,"COLLECTIVE") ) {
2330                                         LDAP_FREE(sval);
2331                                         if ( at->at_collective ) {
2332                                                   *code = LDAP_SCHERR_DUPOPT;
2333                                                   *errp = ss;
2334                                                   ldap_attributetype_free(at);
2335                                                   return(NULL);
2336                                         }
2337                                         at->at_collective = LDAP_SCHEMA_YES;
2338                                         parse_whsp(&ss);
2339                               } else if ( !strcasecmp(sval,"NO-USER-MODIFICATION") ) {
2340                                         LDAP_FREE(sval);
2341                                         if ( at->at_no_user_mod ) {
2342                                                   *code = LDAP_SCHERR_DUPOPT;
2343                                                   *errp = ss;
2344                                                   ldap_attributetype_free(at);
2345                                                   return(NULL);
2346                                         }
2347                                         at->at_no_user_mod = LDAP_SCHEMA_YES;
2348                                         parse_whsp(&ss);
2349                               } else if ( !strcasecmp(sval,"USAGE") ) {
2350                                         LDAP_FREE(sval);
2351                                         if ( seen_usage ) {
2352                                                   *code = LDAP_SCHERR_DUPOPT;
2353                                                   *errp = ss;
2354                                                   ldap_attributetype_free(at);
2355                                                   return(NULL);
2356                                         }
2357                                         seen_usage = 1;
2358                                         parse_whsp(&ss);
2359                                         kind = get_token(&ss,&sval);
2360                                         if ( kind != TK_BAREWORD ) {
2361                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
2362                                                   *errp = ss;
2363                                                   LDAP_FREE(sval);
2364                                                   ldap_attributetype_free(at);
2365                                                   return NULL;
2366                                         }
2367                                         if ( !strcasecmp(sval,"userApplications") )
2368                                                   at->at_usage =
2369                                                       LDAP_SCHEMA_USER_APPLICATIONS;
2370                                         else if ( !strcasecmp(sval,"directoryOperation") )
2371                                                   at->at_usage =
2372                                                       LDAP_SCHEMA_DIRECTORY_OPERATION;
2373                                         else if ( !strcasecmp(sval,"distributedOperation") )
2374                                                   at->at_usage =
2375                                                       LDAP_SCHEMA_DISTRIBUTED_OPERATION;
2376                                         else if ( !strcasecmp(sval,"dSAOperation") )
2377                                                   at->at_usage =
2378                                                       LDAP_SCHEMA_DSA_OPERATION;
2379                                         else {
2380                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
2381                                                   *errp = ss;
2382                                                   LDAP_FREE(sval);
2383                                                   ldap_attributetype_free(at);
2384                                                   return NULL;
2385                                         }
2386                                         LDAP_FREE(sval);
2387                                         parse_whsp(&ss);
2388                               } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2389                                         /* Should be parse_qdstrings */
2390                                         ext_vals = parse_qdescrs(&ss, code);
2391                                         if ( !ext_vals ) {
2392                                                   *errp = ss;
2393                                                   ldap_attributetype_free(at);
2394                                                   return NULL;
2395                                         }
2396                                         if ( add_extension(&at->at_extensions,
2397                                                                 sval, ext_vals) ) {
2398                                                   *code = LDAP_SCHERR_OUTOFMEM;
2399                                                   *errp = ss;
2400                                                   LDAP_FREE(sval);
2401                                                   ldap_attributetype_free(at);
2402                                                   return NULL;
2403                                         }
2404                               } else {
2405                                         *code = LDAP_SCHERR_UNEXPTOKEN;
2406                                         *errp = ss;
2407                                         LDAP_FREE(sval);
2408                                         ldap_attributetype_free(at);
2409                                         return NULL;
2410                               }
2411                               break;
2412                     default:
2413                               *code = LDAP_SCHERR_UNEXPTOKEN;
2414                               *errp = ss;
2415                               LDAP_FREE(sval);
2416                               ldap_attributetype_free(at);
2417                               return NULL;
2418                     }
2419           }
2420 }
2421 
2422 void
ldap_objectclass_free(LDAPObjectClass * oc)2423 ldap_objectclass_free(LDAPObjectClass * oc)
2424 {
2425           if (!oc) return;
2426           LDAP_FREE(oc->oc_oid);
2427           if (oc->oc_names) LDAP_VFREE(oc->oc_names);
2428           if (oc->oc_desc) LDAP_FREE(oc->oc_desc);
2429           if (oc->oc_sup_oids) LDAP_VFREE(oc->oc_sup_oids);
2430           if (oc->oc_at_oids_must) LDAP_VFREE(oc->oc_at_oids_must);
2431           if (oc->oc_at_oids_may) LDAP_VFREE(oc->oc_at_oids_may);
2432           free_extensions(oc->oc_extensions);
2433           LDAP_FREE(oc);
2434 }
2435 
2436 LDAPObjectClass *
ldap_str2objectclass(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)2437 ldap_str2objectclass( LDAP_CONST char * s,
2438           int * code,
2439           LDAP_CONST char ** errp,
2440           LDAP_CONST unsigned flags )
2441 {
2442           tk_t kind;
2443           const char * ss = s;
2444           char * sval;
2445           int seen_name = 0;
2446           int seen_desc = 0;
2447           int seen_obsolete = 0;
2448           int seen_sup = 0;
2449           int seen_kind = 0;
2450           int seen_must = 0;
2451           int seen_may = 0;
2452           LDAPObjectClass * oc;
2453           char ** ext_vals;
2454           const char * savepos;
2455 
2456           if ( !s ) {
2457                     *code = LDAP_SCHERR_EMPTY;
2458                     *errp = "";
2459                     return NULL;
2460           }
2461 
2462           *errp = s;
2463           oc = LDAP_CALLOC(1,sizeof(LDAPObjectClass));
2464 
2465           if ( !oc ) {
2466                     *code = LDAP_SCHERR_OUTOFMEM;
2467                     return NULL;
2468           }
2469           oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2470 
2471           kind = get_token(&ss,&sval);
2472           if ( kind != TK_LEFTPAREN ) {
2473                     *code = LDAP_SCHERR_NOLEFTPAREN;
2474                     LDAP_FREE(sval);
2475                     ldap_objectclass_free(oc);
2476                     return NULL;
2477           }
2478 
2479           /*
2480            * Definitions MUST begin with an OID in the numericoid format.
2481            * However, this routine is used by clients to parse the response
2482            * from servers and very well known servers will provide an OID
2483            * in the wrong format or even no OID at all.  We do our best to
2484            * extract info from those servers.
2485            */
2486           parse_whsp(&ss);
2487           savepos = ss;
2488           oc->oc_oid = ldap_int_parse_numericoid(&ss,code,0);
2489           if ( !oc->oc_oid ) {
2490                     if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2491                               /* Backtracking */
2492                               ss = savepos;
2493                               kind = get_token(&ss,&sval);
2494                               if ( kind == TK_BAREWORD ) {
2495                                         if ( !strcasecmp(sval, "NAME") ||
2496                                              !strcasecmp(sval, "DESC") ||
2497                                              !strcasecmp(sval, "OBSOLETE") ||
2498                                              !strcasecmp(sval, "SUP") ||
2499                                              !strcasecmp(sval, "ABSTRACT") ||
2500                                              !strcasecmp(sval, "STRUCTURAL") ||
2501                                              !strcasecmp(sval, "AUXILIARY") ||
2502                                              !strcasecmp(sval, "MUST") ||
2503                                              !strcasecmp(sval, "MAY") ||
2504                                              !strncasecmp(sval, "X-", 2) ) {
2505                                                   /* Missing OID, backtrack */
2506                                                   ss = savepos;
2507                                         } else if ( flags &
2508                                                   LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2509                                                   /* Non-numerical OID, ignore */
2510                                                   int len = ss-savepos;
2511                                                   oc->oc_oid = LDAP_MALLOC(len+1);
2512                                                   if ( !oc->oc_oid ) {
2513                                                             ldap_objectclass_free(oc);
2514                                                             return NULL;
2515                                                   }
2516 
2517                                                   strncpy(oc->oc_oid, savepos, len);
2518                                                   oc->oc_oid[len] = 0;
2519                                         }
2520                               }
2521                               LDAP_FREE(sval);
2522                               *code = 0;
2523                     } else {
2524                               *errp = ss;
2525                               ldap_objectclass_free(oc);
2526                               return NULL;
2527                     }
2528           }
2529           parse_whsp(&ss);
2530 
2531           /*
2532            * Beyond this point we will be liberal an accept the items
2533            * in any order.
2534            */
2535           while (1) {
2536                     kind = get_token(&ss,&sval);
2537                     switch (kind) {
2538                     case TK_EOS:
2539                               *code = LDAP_SCHERR_NORIGHTPAREN;
2540                               *errp = EndOfInput;
2541                               ldap_objectclass_free(oc);
2542                               return NULL;
2543                     case TK_RIGHTPAREN:
2544                               return oc;
2545                     case TK_BAREWORD:
2546                               if ( !strcasecmp(sval,"NAME") ) {
2547                                         LDAP_FREE(sval);
2548                                         if ( seen_name ) {
2549                                                   *code = LDAP_SCHERR_DUPOPT;
2550                                                   *errp = ss;
2551                                                   ldap_objectclass_free(oc);
2552                                                   return(NULL);
2553                                         }
2554                                         seen_name = 1;
2555                                         oc->oc_names = parse_qdescrs(&ss,code);
2556                                         if ( !oc->oc_names ) {
2557                                                   if ( *code != LDAP_SCHERR_OUTOFMEM )
2558                                                             *code = LDAP_SCHERR_BADNAME;
2559                                                   *errp = ss;
2560                                                   ldap_objectclass_free(oc);
2561                                                   return NULL;
2562                                         }
2563                               } else if ( !strcasecmp(sval,"DESC") ) {
2564                                         LDAP_FREE(sval);
2565                                         if ( seen_desc ) {
2566                                                   *code = LDAP_SCHERR_DUPOPT;
2567                                                   *errp = ss;
2568                                                   ldap_objectclass_free(oc);
2569                                                   return(NULL);
2570                                         }
2571                                         seen_desc = 1;
2572                                         parse_whsp(&ss);
2573                                         kind = get_token(&ss,&sval);
2574                                         if ( kind != TK_QDSTRING ) {
2575                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
2576                                                   *errp = ss;
2577                                                   LDAP_FREE(sval);
2578                                                   ldap_objectclass_free(oc);
2579                                                   return NULL;
2580                                         }
2581                                         oc->oc_desc = sval;
2582                                         parse_whsp(&ss);
2583                               } else if ( !strcasecmp(sval,"OBSOLETE") ) {
2584                                         LDAP_FREE(sval);
2585                                         if ( seen_obsolete ) {
2586                                                   *code = LDAP_SCHERR_DUPOPT;
2587                                                   *errp = ss;
2588                                                   ldap_objectclass_free(oc);
2589                                                   return(NULL);
2590                                         }
2591                                         seen_obsolete = 1;
2592                                         oc->oc_obsolete = LDAP_SCHEMA_YES;
2593                                         parse_whsp(&ss);
2594                               } else if ( !strcasecmp(sval,"SUP") ) {
2595                                         LDAP_FREE(sval);
2596                                         if ( seen_sup ) {
2597                                                   *code = LDAP_SCHERR_DUPOPT;
2598                                                   *errp = ss;
2599                                                   ldap_objectclass_free(oc);
2600                                                   return(NULL);
2601                                         }
2602                                         seen_sup = 1;
2603                                         oc->oc_sup_oids = parse_oids(&ss,
2604                                                                            code,
2605                                                                            flags);
2606                                         if ( !oc->oc_sup_oids && *code != LDAP_SUCCESS ) {
2607                                                   *errp = ss;
2608                                                   ldap_objectclass_free(oc);
2609                                                   return NULL;
2610                                         }
2611                                         *code = 0;
2612                               } else if ( !strcasecmp(sval,"ABSTRACT") ) {
2613                                         LDAP_FREE(sval);
2614                                         if ( seen_kind ) {
2615                                                   *code = LDAP_SCHERR_DUPOPT;
2616                                                   *errp = ss;
2617                                                   ldap_objectclass_free(oc);
2618                                                   return(NULL);
2619                                         }
2620                                         seen_kind = 1;
2621                                         oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
2622                                         parse_whsp(&ss);
2623                               } else if ( !strcasecmp(sval,"STRUCTURAL") ) {
2624                                         LDAP_FREE(sval);
2625                                         if ( seen_kind ) {
2626                                                   *code = LDAP_SCHERR_DUPOPT;
2627                                                   *errp = ss;
2628                                                   ldap_objectclass_free(oc);
2629                                                   return(NULL);
2630                                         }
2631                                         seen_kind = 1;
2632                                         oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
2633                                         parse_whsp(&ss);
2634                               } else if ( !strcasecmp(sval,"AUXILIARY") ) {
2635                                         LDAP_FREE(sval);
2636                                         if ( seen_kind ) {
2637                                                   *code = LDAP_SCHERR_DUPOPT;
2638                                                   *errp = ss;
2639                                                   ldap_objectclass_free(oc);
2640                                                   return(NULL);
2641                                         }
2642                                         seen_kind = 1;
2643                                         oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
2644                                         parse_whsp(&ss);
2645                               } else if ( !strcasecmp(sval,"MUST") ) {
2646                                         LDAP_FREE(sval);
2647                                         if ( seen_must ) {
2648                                                   *code = LDAP_SCHERR_DUPOPT;
2649                                                   *errp = ss;
2650                                                   ldap_objectclass_free(oc);
2651                                                   return(NULL);
2652                                         }
2653                                         seen_must = 1;
2654                                         oc->oc_at_oids_must = parse_oids(&ss,code,0);
2655                                         if ( !oc->oc_at_oids_must && *code != LDAP_SUCCESS ) {
2656                                                   *errp = ss;
2657                                                   ldap_objectclass_free(oc);
2658                                                   return NULL;
2659                                         }
2660                                         *code = 0;
2661                                         parse_whsp(&ss);
2662                               } else if ( !strcasecmp(sval,"MAY") ) {
2663                                         LDAP_FREE(sval);
2664                                         if ( seen_may ) {
2665                                                   *code = LDAP_SCHERR_DUPOPT;
2666                                                   *errp = ss;
2667                                                   ldap_objectclass_free(oc);
2668                                                   return(NULL);
2669                                         }
2670                                         seen_may = 1;
2671                                         oc->oc_at_oids_may = parse_oids(&ss,code,0);
2672                                         if ( !oc->oc_at_oids_may && *code != LDAP_SUCCESS ) {
2673                                                   *errp = ss;
2674                                                   ldap_objectclass_free(oc);
2675                                                   return NULL;
2676                                         }
2677                                         *code = 0;
2678                                         parse_whsp(&ss);
2679                               } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2680                                         /* Should be parse_qdstrings */
2681                                         ext_vals = parse_qdescrs(&ss, code);
2682                                         *code = 0;
2683                                         if ( !ext_vals ) {
2684                                                   *errp = ss;
2685                                                   ldap_objectclass_free(oc);
2686                                                   return NULL;
2687                                         }
2688                                         if ( add_extension(&oc->oc_extensions,
2689                                                                 sval, ext_vals) ) {
2690                                                   *code = LDAP_SCHERR_OUTOFMEM;
2691                                                   *errp = ss;
2692                                                   LDAP_FREE(sval);
2693                                                   ldap_objectclass_free(oc);
2694                                                   return NULL;
2695                                         }
2696                               } else {
2697                                         *code = LDAP_SCHERR_UNEXPTOKEN;
2698                                         *errp = ss;
2699                                         LDAP_FREE(sval);
2700                                         ldap_objectclass_free(oc);
2701                                         return NULL;
2702                               }
2703                               break;
2704                     default:
2705                               *code = LDAP_SCHERR_UNEXPTOKEN;
2706                               *errp = ss;
2707                               LDAP_FREE(sval);
2708                               ldap_objectclass_free(oc);
2709                               return NULL;
2710                     }
2711           }
2712 }
2713 
2714 void
ldap_contentrule_free(LDAPContentRule * cr)2715 ldap_contentrule_free(LDAPContentRule * cr)
2716 {
2717           if (!cr) return;
2718           LDAP_FREE(cr->cr_oid);
2719           if (cr->cr_names) LDAP_VFREE(cr->cr_names);
2720           if (cr->cr_desc) LDAP_FREE(cr->cr_desc);
2721           if (cr->cr_oc_oids_aux) LDAP_VFREE(cr->cr_oc_oids_aux);
2722           if (cr->cr_at_oids_must) LDAP_VFREE(cr->cr_at_oids_must);
2723           if (cr->cr_at_oids_may) LDAP_VFREE(cr->cr_at_oids_may);
2724           if (cr->cr_at_oids_not) LDAP_VFREE(cr->cr_at_oids_not);
2725           free_extensions(cr->cr_extensions);
2726           LDAP_FREE(cr);
2727 }
2728 
2729 LDAPContentRule *
ldap_str2contentrule(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)2730 ldap_str2contentrule( LDAP_CONST char * s,
2731           int * code,
2732           LDAP_CONST char ** errp,
2733           LDAP_CONST unsigned flags )
2734 {
2735           tk_t kind;
2736           const char * ss = s;
2737           char * sval;
2738           int seen_name = 0;
2739           int seen_desc = 0;
2740           int seen_obsolete = 0;
2741           int seen_aux = 0;
2742           int seen_must = 0;
2743           int seen_may = 0;
2744           int seen_not = 0;
2745           LDAPContentRule * cr;
2746           char ** ext_vals;
2747           const char * savepos;
2748 
2749           if ( !s ) {
2750                     *code = LDAP_SCHERR_EMPTY;
2751                     *errp = "";
2752                     return NULL;
2753           }
2754 
2755           *errp = s;
2756           cr = LDAP_CALLOC(1,sizeof(LDAPContentRule));
2757 
2758           if ( !cr ) {
2759                     *code = LDAP_SCHERR_OUTOFMEM;
2760                     return NULL;
2761           }
2762 
2763           kind = get_token(&ss,&sval);
2764           if ( kind != TK_LEFTPAREN ) {
2765                     *code = LDAP_SCHERR_NOLEFTPAREN;
2766                     LDAP_FREE(sval);
2767                     ldap_contentrule_free(cr);
2768                     return NULL;
2769           }
2770 
2771           /*
2772            * Definitions MUST begin with an OID in the numericoid format.
2773            */
2774           parse_whsp(&ss);
2775           savepos = ss;
2776           cr->cr_oid = ldap_int_parse_numericoid(&ss,code,0);
2777           if ( !cr->cr_oid ) {
2778                     if ( (flags & LDAP_SCHEMA_ALLOW_ALL) && (ss == savepos) ) {
2779                               /* Backtracking */
2780                               ss = savepos;
2781                               kind = get_token(&ss,&sval);
2782                               if ( kind == TK_BAREWORD ) {
2783                                         if ( !strcasecmp(sval, "NAME") ||
2784                                              !strcasecmp(sval, "DESC") ||
2785                                              !strcasecmp(sval, "OBSOLETE") ||
2786                                              !strcasecmp(sval, "AUX") ||
2787                                              !strcasecmp(sval, "MUST") ||
2788                                              !strcasecmp(sval, "MAY") ||
2789                                              !strcasecmp(sval, "NOT") ||
2790                                              !strncasecmp(sval, "X-", 2) ) {
2791                                                   /* Missing OID, backtrack */
2792                                                   ss = savepos;
2793                                         } else if ( flags &
2794                                                   LDAP_SCHEMA_ALLOW_OID_MACRO ) {
2795                                                   /* Non-numerical OID, ignore */
2796                                                   int len = ss-savepos;
2797                                                   cr->cr_oid = LDAP_MALLOC(len+1);
2798                                                   if ( !cr->cr_oid ) {
2799                                                             ldap_contentrule_free(cr);
2800                                                             return NULL;
2801                                                   }
2802 
2803                                                   strncpy(cr->cr_oid, savepos, len);
2804                                                   cr->cr_oid[len] = 0;
2805                                         }
2806                               }
2807                               LDAP_FREE(sval);
2808                     } else {
2809                               *errp = ss;
2810                               ldap_contentrule_free(cr);
2811                               return NULL;
2812                     }
2813           }
2814           parse_whsp(&ss);
2815 
2816           /*
2817            * Beyond this point we will be liberal an accept the items
2818            * in any order.
2819            */
2820           while (1) {
2821                     kind = get_token(&ss,&sval);
2822                     switch (kind) {
2823                     case TK_EOS:
2824                               *code = LDAP_SCHERR_NORIGHTPAREN;
2825                               *errp = EndOfInput;
2826                               ldap_contentrule_free(cr);
2827                               return NULL;
2828                     case TK_RIGHTPAREN:
2829                               return cr;
2830                     case TK_BAREWORD:
2831                               if ( !strcasecmp(sval,"NAME") ) {
2832                                         LDAP_FREE(sval);
2833                                         if ( seen_name ) {
2834                                                   *code = LDAP_SCHERR_DUPOPT;
2835                                                   *errp = ss;
2836                                                   ldap_contentrule_free(cr);
2837                                                   return(NULL);
2838                                         }
2839                                         seen_name = 1;
2840                                         cr->cr_names = parse_qdescrs(&ss,code);
2841                                         if ( !cr->cr_names ) {
2842                                                   if ( *code != LDAP_SCHERR_OUTOFMEM )
2843                                                             *code = LDAP_SCHERR_BADNAME;
2844                                                   *errp = ss;
2845                                                   ldap_contentrule_free(cr);
2846                                                   return NULL;
2847                                         }
2848                               } else if ( !strcasecmp(sval,"DESC") ) {
2849                                         LDAP_FREE(sval);
2850                                         if ( seen_desc ) {
2851                                                   *code = LDAP_SCHERR_DUPOPT;
2852                                                   *errp = ss;
2853                                                   ldap_contentrule_free(cr);
2854                                                   return(NULL);
2855                                         }
2856                                         seen_desc = 1;
2857                                         parse_whsp(&ss);
2858                                         kind = get_token(&ss,&sval);
2859                                         if ( kind != TK_QDSTRING ) {
2860                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
2861                                                   *errp = ss;
2862                                                   LDAP_FREE(sval);
2863                                                   ldap_contentrule_free(cr);
2864                                                   return NULL;
2865                                         }
2866                                         cr->cr_desc = sval;
2867                                         parse_whsp(&ss);
2868                               } else if ( !strcasecmp(sval,"OBSOLETE") ) {
2869                                         LDAP_FREE(sval);
2870                                         if ( seen_obsolete ) {
2871                                                   *code = LDAP_SCHERR_DUPOPT;
2872                                                   *errp = ss;
2873                                                   ldap_contentrule_free(cr);
2874                                                   return(NULL);
2875                                         }
2876                                         seen_obsolete = 1;
2877                                         cr->cr_obsolete = LDAP_SCHEMA_YES;
2878                                         parse_whsp(&ss);
2879                               } else if ( !strcasecmp(sval,"AUX") ) {
2880                                         LDAP_FREE(sval);
2881                                         if ( seen_aux ) {
2882                                                   *code = LDAP_SCHERR_DUPOPT;
2883                                                   *errp = ss;
2884                                                   ldap_contentrule_free(cr);
2885                                                   return(NULL);
2886                                         }
2887                                         seen_aux = 1;
2888                                         cr->cr_oc_oids_aux = parse_oids(&ss,code,0);
2889                                         if ( !cr->cr_oc_oids_aux ) {
2890                                                   *errp = ss;
2891                                                   ldap_contentrule_free(cr);
2892                                                   return NULL;
2893                                         }
2894                                         parse_whsp(&ss);
2895                               } else if ( !strcasecmp(sval,"MUST") ) {
2896                                         LDAP_FREE(sval);
2897                                         if ( seen_must ) {
2898                                                   *code = LDAP_SCHERR_DUPOPT;
2899                                                   *errp = ss;
2900                                                   ldap_contentrule_free(cr);
2901                                                   return(NULL);
2902                                         }
2903                                         seen_must = 1;
2904                                         cr->cr_at_oids_must = parse_oids(&ss,code,0);
2905                                         if ( !cr->cr_at_oids_must && *code != LDAP_SUCCESS ) {
2906                                                   *errp = ss;
2907                                                   ldap_contentrule_free(cr);
2908                                                   return NULL;
2909                                         }
2910                                         parse_whsp(&ss);
2911                               } else if ( !strcasecmp(sval,"MAY") ) {
2912                                         LDAP_FREE(sval);
2913                                         if ( seen_may ) {
2914                                                   *code = LDAP_SCHERR_DUPOPT;
2915                                                   *errp = ss;
2916                                                   ldap_contentrule_free(cr);
2917                                                   return(NULL);
2918                                         }
2919                                         seen_may = 1;
2920                                         cr->cr_at_oids_may = parse_oids(&ss,code,0);
2921                                         if ( !cr->cr_at_oids_may && *code != LDAP_SUCCESS ) {
2922                                                   *errp = ss;
2923                                                   ldap_contentrule_free(cr);
2924                                                   return NULL;
2925                                         }
2926                                         parse_whsp(&ss);
2927                               } else if ( !strcasecmp(sval,"NOT") ) {
2928                                         LDAP_FREE(sval);
2929                                         if ( seen_not ) {
2930                                                   *code = LDAP_SCHERR_DUPOPT;
2931                                                   *errp = ss;
2932                                                   ldap_contentrule_free(cr);
2933                                                   return(NULL);
2934                                         }
2935                                         seen_not = 1;
2936                                         cr->cr_at_oids_not = parse_oids(&ss,code,0);
2937                                         if ( !cr->cr_at_oids_not && *code != LDAP_SUCCESS ) {
2938                                                   *errp = ss;
2939                                                   ldap_contentrule_free(cr);
2940                                                   return NULL;
2941                                         }
2942                                         parse_whsp(&ss);
2943                               } else if ( sval[0] == 'X' && sval[1] == '-' ) {
2944                                         /* Should be parse_qdstrings */
2945                                         ext_vals = parse_qdescrs(&ss, code);
2946                                         if ( !ext_vals ) {
2947                                                   *errp = ss;
2948                                                   ldap_contentrule_free(cr);
2949                                                   return NULL;
2950                                         }
2951                                         if ( add_extension(&cr->cr_extensions,
2952                                                                 sval, ext_vals) ) {
2953                                                   *code = LDAP_SCHERR_OUTOFMEM;
2954                                                   *errp = ss;
2955                                                   LDAP_FREE(sval);
2956                                                   ldap_contentrule_free(cr);
2957                                                   return NULL;
2958                                         }
2959                               } else {
2960                                         *code = LDAP_SCHERR_UNEXPTOKEN;
2961                                         *errp = ss;
2962                                         LDAP_FREE(sval);
2963                                         ldap_contentrule_free(cr);
2964                                         return NULL;
2965                               }
2966                               break;
2967                     default:
2968                               *code = LDAP_SCHERR_UNEXPTOKEN;
2969                               *errp = ss;
2970                               LDAP_FREE(sval);
2971                               ldap_contentrule_free(cr);
2972                               return NULL;
2973                     }
2974           }
2975 }
2976 
2977 void
ldap_structurerule_free(LDAPStructureRule * sr)2978 ldap_structurerule_free(LDAPStructureRule * sr)
2979 {
2980           if (!sr) return;
2981           if (sr->sr_names) LDAP_VFREE(sr->sr_names);
2982           if (sr->sr_desc) LDAP_FREE(sr->sr_desc);
2983           if (sr->sr_nameform) LDAP_FREE(sr->sr_nameform);
2984           if (sr->sr_sup_ruleids) LDAP_FREE(sr->sr_sup_ruleids);
2985           free_extensions(sr->sr_extensions);
2986           LDAP_FREE(sr);
2987 }
2988 
2989 LDAPStructureRule *
ldap_str2structurerule(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)2990 ldap_str2structurerule( LDAP_CONST char * s,
2991           int * code,
2992           LDAP_CONST char ** errp,
2993           LDAP_CONST unsigned flags )
2994 {
2995           tk_t kind;
2996           int ret;
2997           const char * ss = s;
2998           char * sval;
2999           int seen_name = 0;
3000           int seen_desc = 0;
3001           int seen_obsolete = 0;
3002           int seen_nameform = 0;
3003           LDAPStructureRule * sr;
3004           char ** ext_vals;
3005           const char * savepos;
3006 
3007           if ( !s ) {
3008                     *code = LDAP_SCHERR_EMPTY;
3009                     *errp = "";
3010                     return NULL;
3011           }
3012 
3013           *errp = s;
3014           sr = LDAP_CALLOC(1,sizeof(LDAPStructureRule));
3015 
3016           if ( !sr ) {
3017                     *code = LDAP_SCHERR_OUTOFMEM;
3018                     return NULL;
3019           }
3020 
3021           kind = get_token(&ss,&sval);
3022           if ( kind != TK_LEFTPAREN ) {
3023                     *code = LDAP_SCHERR_NOLEFTPAREN;
3024                     LDAP_FREE(sval);
3025                     ldap_structurerule_free(sr);
3026                     return NULL;
3027           }
3028 
3029           /*
3030            * Definitions MUST begin with a ruleid.
3031            */
3032           parse_whsp(&ss);
3033           savepos = ss;
3034           ret = ldap_int_parse_ruleid(&ss,code,0,&sr->sr_ruleid);
3035           if ( ret ) {
3036                     *errp = ss;
3037                     ldap_structurerule_free(sr);
3038                     return NULL;
3039           }
3040           parse_whsp(&ss);
3041 
3042           /*
3043            * Beyond this point we will be liberal an accept the items
3044            * in any order.
3045            */
3046           while (1) {
3047                     kind = get_token(&ss,&sval);
3048                     switch (kind) {
3049                     case TK_EOS:
3050                               *code = LDAP_SCHERR_NORIGHTPAREN;
3051                               *errp = EndOfInput;
3052                               ldap_structurerule_free(sr);
3053                               return NULL;
3054                     case TK_RIGHTPAREN:
3055                               if( !seen_nameform ) {
3056                                         *code = LDAP_SCHERR_MISSING;
3057                                         ldap_structurerule_free(sr);
3058                                         return NULL;
3059                               }
3060                               return sr;
3061                     case TK_BAREWORD:
3062                               if ( !strcasecmp(sval,"NAME") ) {
3063                                         LDAP_FREE(sval);
3064                                         if ( seen_name ) {
3065                                                   *code = LDAP_SCHERR_DUPOPT;
3066                                                   *errp = ss;
3067                                                   ldap_structurerule_free(sr);
3068                                                   return(NULL);
3069                                         }
3070                                         seen_name = 1;
3071                                         sr->sr_names = parse_qdescrs(&ss,code);
3072                                         if ( !sr->sr_names ) {
3073                                                   if ( *code != LDAP_SCHERR_OUTOFMEM )
3074                                                             *code = LDAP_SCHERR_BADNAME;
3075                                                   *errp = ss;
3076                                                   ldap_structurerule_free(sr);
3077                                                   return NULL;
3078                                         }
3079                               } else if ( !strcasecmp(sval,"DESC") ) {
3080                                         LDAP_FREE(sval);
3081                                         if ( seen_desc ) {
3082                                                   *code = LDAP_SCHERR_DUPOPT;
3083                                                   *errp = ss;
3084                                                   ldap_structurerule_free(sr);
3085                                                   return(NULL);
3086                                         }
3087                                         seen_desc = 1;
3088                                         parse_whsp(&ss);
3089                                         kind = get_token(&ss,&sval);
3090                                         if ( kind != TK_QDSTRING ) {
3091                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
3092                                                   *errp = ss;
3093                                                   LDAP_FREE(sval);
3094                                                   ldap_structurerule_free(sr);
3095                                                   return NULL;
3096                                         }
3097                                         sr->sr_desc = sval;
3098                                         parse_whsp(&ss);
3099                               } else if ( !strcasecmp(sval,"OBSOLETE") ) {
3100                                         LDAP_FREE(sval);
3101                                         if ( seen_obsolete ) {
3102                                                   *code = LDAP_SCHERR_DUPOPT;
3103                                                   *errp = ss;
3104                                                   ldap_structurerule_free(sr);
3105                                                   return(NULL);
3106                                         }
3107                                         seen_obsolete = 1;
3108                                         sr->sr_obsolete = LDAP_SCHEMA_YES;
3109                                         parse_whsp(&ss);
3110                               } else if ( !strcasecmp(sval,"FORM") ) {
3111                                         LDAP_FREE(sval);
3112                                         if ( seen_nameform ) {
3113                                                   *code = LDAP_SCHERR_DUPOPT;
3114                                                   *errp = ss;
3115                                                   ldap_structurerule_free(sr);
3116                                                   return(NULL);
3117                                         }
3118                                         seen_nameform = 1;
3119                                         sr->sr_nameform = parse_woid(&ss,code);
3120                                         if ( !sr->sr_nameform ) {
3121                                                   *errp = ss;
3122                                                   ldap_structurerule_free(sr);
3123                                                   return NULL;
3124                                         }
3125                                         parse_whsp(&ss);
3126                               } else if ( sval[0] == 'X' && sval[1] == '-' ) {
3127                                         /* Should be parse_qdstrings */
3128                                         ext_vals = parse_qdescrs(&ss, code);
3129                                         if ( !ext_vals ) {
3130                                                   *errp = ss;
3131                                                   ldap_structurerule_free(sr);
3132                                                   return NULL;
3133                                         }
3134                                         if ( add_extension(&sr->sr_extensions,
3135                                                                 sval, ext_vals) ) {
3136                                                   *code = LDAP_SCHERR_OUTOFMEM;
3137                                                   *errp = ss;
3138                                                   LDAP_FREE(sval);
3139                                                   ldap_structurerule_free(sr);
3140                                                   return NULL;
3141                                         }
3142                               } else {
3143                                         *code = LDAP_SCHERR_UNEXPTOKEN;
3144                                         *errp = ss;
3145                                         LDAP_FREE(sval);
3146                                         ldap_structurerule_free(sr);
3147                                         return NULL;
3148                               }
3149                               break;
3150                     default:
3151                               *code = LDAP_SCHERR_UNEXPTOKEN;
3152                               *errp = ss;
3153                               LDAP_FREE(sval);
3154                               ldap_structurerule_free(sr);
3155                               return NULL;
3156                     }
3157           }
3158 }
3159 
3160 void
ldap_nameform_free(LDAPNameForm * nf)3161 ldap_nameform_free(LDAPNameForm * nf)
3162 {
3163           if (!nf) return;
3164           LDAP_FREE(nf->nf_oid);
3165           if (nf->nf_names) LDAP_VFREE(nf->nf_names);
3166           if (nf->nf_desc) LDAP_FREE(nf->nf_desc);
3167           if (nf->nf_objectclass) LDAP_FREE(nf->nf_objectclass);
3168           if (nf->nf_at_oids_must) LDAP_VFREE(nf->nf_at_oids_must);
3169           if (nf->nf_at_oids_may) LDAP_VFREE(nf->nf_at_oids_may);
3170           free_extensions(nf->nf_extensions);
3171           LDAP_FREE(nf);
3172 }
3173 
3174 LDAPNameForm *
ldap_str2nameform(LDAP_CONST char * s,int * code,LDAP_CONST char ** errp,LDAP_CONST unsigned flags)3175 ldap_str2nameform( LDAP_CONST char * s,
3176           int * code,
3177           LDAP_CONST char ** errp,
3178           LDAP_CONST unsigned flags )
3179 {
3180           tk_t kind;
3181           const char * ss = s;
3182           char * sval;
3183           int seen_name = 0;
3184           int seen_desc = 0;
3185           int seen_obsolete = 0;
3186           int seen_class = 0;
3187           int seen_must = 0;
3188           int seen_may = 0;
3189           LDAPNameForm * nf;
3190           char ** ext_vals;
3191           const char * savepos;
3192 
3193           if ( !s ) {
3194                     *code = LDAP_SCHERR_EMPTY;
3195                     *errp = "";
3196                     return NULL;
3197           }
3198 
3199           *errp = s;
3200           nf = LDAP_CALLOC(1,sizeof(LDAPNameForm));
3201 
3202           if ( !nf ) {
3203                     *code = LDAP_SCHERR_OUTOFMEM;
3204                     return NULL;
3205           }
3206 
3207           kind = get_token(&ss,&sval);
3208           if ( kind != TK_LEFTPAREN ) {
3209                     *code = LDAP_SCHERR_NOLEFTPAREN;
3210                     LDAP_FREE(sval);
3211                     ldap_nameform_free(nf);
3212                     return NULL;
3213           }
3214 
3215           /*
3216            * Definitions MUST begin with an OID in the numericoid format.
3217            * However, this routine is used by clients to parse the response
3218            * from servers and very well known servers will provide an OID
3219            * in the wrong format or even no OID at all.  We do our best to
3220            * extract info from those servers.
3221            */
3222           parse_whsp(&ss);
3223           savepos = ss;
3224           nf->nf_oid = ldap_int_parse_numericoid(&ss,code,0);
3225           if ( !nf->nf_oid ) {
3226                     *errp = ss;
3227                     ldap_nameform_free(nf);
3228                     return NULL;
3229           }
3230           parse_whsp(&ss);
3231 
3232           /*
3233            * Beyond this point we will be liberal an accept the items
3234            * in any order.
3235            */
3236           while (1) {
3237                     kind = get_token(&ss,&sval);
3238                     switch (kind) {
3239                     case TK_EOS:
3240                               *code = LDAP_SCHERR_NORIGHTPAREN;
3241                               *errp = EndOfInput;
3242                               ldap_nameform_free(nf);
3243                               return NULL;
3244                     case TK_RIGHTPAREN:
3245                               if( !seen_class || !seen_must ) {
3246                                         *code = LDAP_SCHERR_MISSING;
3247                                         ldap_nameform_free(nf);
3248                                         return NULL;
3249                               }
3250                               return nf;
3251                     case TK_BAREWORD:
3252                               if ( !strcasecmp(sval,"NAME") ) {
3253                                         LDAP_FREE(sval);
3254                                         if ( seen_name ) {
3255                                                   *code = LDAP_SCHERR_DUPOPT;
3256                                                   *errp = ss;
3257                                                   ldap_nameform_free(nf);
3258                                                   return(NULL);
3259                                         }
3260                                         seen_name = 1;
3261                                         nf->nf_names = parse_qdescrs(&ss,code);
3262                                         if ( !nf->nf_names ) {
3263                                                   if ( *code != LDAP_SCHERR_OUTOFMEM )
3264                                                             *code = LDAP_SCHERR_BADNAME;
3265                                                   *errp = ss;
3266                                                   ldap_nameform_free(nf);
3267                                                   return NULL;
3268                                         }
3269                               } else if ( !strcasecmp(sval,"DESC") ) {
3270                                         LDAP_FREE(sval);
3271                                         if ( seen_desc ) {
3272                                                   *code = LDAP_SCHERR_DUPOPT;
3273                                                   *errp = ss;
3274                                                   ldap_nameform_free(nf);
3275                                                   return(NULL);
3276                                         }
3277                                         seen_desc = 1;
3278                                         parse_whsp(&ss);
3279                                         kind = get_token(&ss,&sval);
3280                                         if ( kind != TK_QDSTRING ) {
3281                                                   *code = LDAP_SCHERR_UNEXPTOKEN;
3282                                                   *errp = ss;
3283                                                   LDAP_FREE(sval);
3284                                                   ldap_nameform_free(nf);
3285                                                   return NULL;
3286                                         }
3287                                         nf->nf_desc = sval;
3288                                         parse_whsp(&ss);
3289                               } else if ( !strcasecmp(sval,"OBSOLETE") ) {
3290                                         LDAP_FREE(sval);
3291                                         if ( seen_obsolete ) {
3292                                                   *code = LDAP_SCHERR_DUPOPT;
3293                                                   *errp = ss;
3294                                                   ldap_nameform_free(nf);
3295                                                   return(NULL);
3296                                         }
3297                                         seen_obsolete = 1;
3298                                         nf->nf_obsolete = LDAP_SCHEMA_YES;
3299                                         parse_whsp(&ss);
3300                               } else if ( !strcasecmp(sval,"OC") ) {
3301                                         LDAP_FREE(sval);
3302                                         if ( seen_class ) {
3303                                                   *code = LDAP_SCHERR_DUPOPT;
3304                                                   *errp = ss;
3305                                                   ldap_nameform_free(nf);
3306                                                   return(NULL);
3307                                         }
3308                                         seen_class = 1;
3309                                         nf->nf_objectclass = parse_woid(&ss,code);
3310                                         if ( !nf->nf_objectclass ) {
3311                                                   *errp = ss;
3312                                                   ldap_nameform_free(nf);
3313                                                   return NULL;
3314                                         }
3315                               } else if ( !strcasecmp(sval,"MUST") ) {
3316                                         LDAP_FREE(sval);
3317                                         if ( seen_must ) {
3318                                                   *code = LDAP_SCHERR_DUPOPT;
3319                                                   *errp = ss;
3320                                                   ldap_nameform_free(nf);
3321                                                   return(NULL);
3322                                         }
3323                                         seen_must = 1;
3324                                         nf->nf_at_oids_must = parse_oids(&ss,code,0);
3325                                         if ( !nf->nf_at_oids_must && *code != LDAP_SUCCESS ) {
3326                                                   *errp = ss;
3327                                                   ldap_nameform_free(nf);
3328                                                   return NULL;
3329                                         }
3330                                         parse_whsp(&ss);
3331                               } else if ( !strcasecmp(sval,"MAY") ) {
3332                                         LDAP_FREE(sval);
3333                                         if ( seen_may ) {
3334                                                   *code = LDAP_SCHERR_DUPOPT;
3335                                                   *errp = ss;
3336                                                   ldap_nameform_free(nf);
3337                                                   return(NULL);
3338                                         }
3339                                         seen_may = 1;
3340                                         nf->nf_at_oids_may = parse_oids(&ss,code,0);
3341                                         if ( !nf->nf_at_oids_may && *code != LDAP_SUCCESS ) {
3342                                                   *errp = ss;
3343                                                   ldap_nameform_free(nf);
3344                                                   return NULL;
3345                                         }
3346                                         parse_whsp(&ss);
3347                               } else if ( sval[0] == 'X' && sval[1] == '-' ) {
3348                                         /* Should be parse_qdstrings */
3349                                         ext_vals = parse_qdescrs(&ss, code);
3350                                         if ( !ext_vals ) {
3351                                                   *errp = ss;
3352                                                   ldap_nameform_free(nf);
3353                                                   return NULL;
3354                                         }
3355                                         if ( add_extension(&nf->nf_extensions,
3356                                                                 sval, ext_vals) ) {
3357                                                   *code = LDAP_SCHERR_OUTOFMEM;
3358                                                   *errp = ss;
3359                                                   LDAP_FREE(sval);
3360                                                   ldap_nameform_free(nf);
3361                                                   return NULL;
3362                                         }
3363                               } else {
3364                                         *code = LDAP_SCHERR_UNEXPTOKEN;
3365                                         *errp = ss;
3366                                         LDAP_FREE(sval);
3367                                         ldap_nameform_free(nf);
3368                                         return NULL;
3369                               }
3370                               break;
3371                     default:
3372                               *code = LDAP_SCHERR_UNEXPTOKEN;
3373                               *errp = ss;
3374                               LDAP_FREE(sval);
3375                               ldap_nameform_free(nf);
3376                               return NULL;
3377                     }
3378           }
3379 }
3380 
3381 static char *const err2text[] = {
3382           N_("Success"),
3383           N_("Out of memory"),
3384           N_("Unexpected token"),
3385           N_("Missing opening parenthesis"),
3386           N_("Missing closing parenthesis"),
3387           N_("Expecting digit"),
3388           N_("Expecting a name"),
3389           N_("Bad description"),
3390           N_("Bad superiors"),
3391           N_("Duplicate option"),
3392           N_("Unexpected end of data"),
3393           N_("Missing required field"),
3394           N_("Out of order field")
3395 };
3396 
3397 char *
ldap_scherr2str(int code)3398 ldap_scherr2str(int code)
3399 {
3400           if ( code < 0 || code >= (int)(sizeof(err2text)/sizeof(char *)) ) {
3401                     return _("Unknown error");
3402           } else {
3403                     return _(err2text[code]);
3404           }
3405 }
3406