]> git.sur5r.net Git - openldap/blob - libraries/libldap/schema.c
d86685b6ad651d6694be5997b703b002fb780f15
[openldap] / libraries / libldap / schema.c
1 /*
2  * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved.
3  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
4  *
5  * schema.c:  parsing routines used by servers and clients to process
6  *      schema definitions
7  */
8
9 #include "portable.h"
10
11 #include <stdio.h>
12 #include <stdlib.h>
13
14 #include <ac/ctype.h>
15 #include <ac/string.h>
16 #include <ac/time.h>
17
18 #include "ldap-int.h"
19
20 #include <ldap_schema.h>
21
22 /*
23  * When pretty printing the entities we will be appending to a buffer.
24  * Since checking for overflow, realloc'ing and checking if no error
25  * is extremely boring, we will use a pretection layer that will let
26  * us blissfully ignore the error until the end.  This layer is
27  * implemented with the help of the next type.
28  */
29
30 typedef struct safe_string {
31         char * val;
32         int size;
33         int pos;
34         int at_whsp;
35 } safe_string;
36
37 static safe_string *
38 new_safe_string(int size)
39 {
40         safe_string * ss;
41         
42         ss = LDAP_MALLOC(sizeof(safe_string));
43         if ( !ss )
44                 return(NULL);
45         ss->size = size;
46         ss->pos = 0;
47         ss->val = LDAP_MALLOC(size);
48         ss->at_whsp = 0;
49         if ( !ss->val ) {
50                 LDAP_FREE(ss);
51                 return(NULL);
52         }
53         return ss;
54 }
55
56 void
57 safe_string_free(safe_string * ss)
58 {
59         if ( !ss )
60                 return;
61         ldap_memfree(ss->val);
62         ldap_memfree(ss);
63 }
64
65 static char *
66 safe_string_val(safe_string * ss)
67 {
68         ss->val[ss->pos] = '\0';
69         return(ss->val);
70 }
71
72 static int
73 append_to_safe_string(safe_string * ss, char * s)
74 {
75         int l = strlen(s);
76         char * temp;
77
78         /*
79          * Some runaway process is trying to append to a string that
80          * overflowed and we could not extend.
81          */
82         if ( !ss->val )
83                 return -1;
84
85         /* We always make sure there is at least one position available */
86         if ( ss->pos + l >= ss->size-1 ) {
87                 ss->size *= 2;
88                 temp = LDAP_REALLOC(ss->val, ss->size);
89                 if ( !temp ) {
90                         /* Trouble, out of memory */
91                         LDAP_FREE(ss->val);
92                         return -1;
93                 }
94                 ss->val = temp;
95         }
96         strncpy(&ss->val[ss->pos], s, l);
97         ss->pos += l;
98         if ( ss->pos > 0 && ss->val[ss->pos-1] == ' ' )
99                 ss->at_whsp = 1;
100         else
101                 ss->at_whsp = 0;
102
103         return 0;
104 }
105
106 static int
107 print_literal(safe_string *ss, char *s)
108 {
109         return(append_to_safe_string(ss,s));
110 }
111
112 static int
113 print_whsp(safe_string *ss)
114 {
115         if ( ss->at_whsp )
116                 return(append_to_safe_string(ss,""));
117         else
118                 return(append_to_safe_string(ss," "));
119 }
120
121 static int
122 print_numericoid(safe_string *ss, char *s)
123 {
124         if ( s )
125                 return(append_to_safe_string(ss,s));
126 }
127
128 /* This one is identical to print_qdescr */
129 static int
130 print_qdstring(safe_string *ss, char *s)
131 {
132         print_whsp(ss);
133         print_literal(ss,"'");
134         append_to_safe_string(ss,s);
135         print_literal(ss,"'");
136         return(print_whsp(ss));
137 }
138
139 static int
140 print_qdescr(safe_string *ss, char *s)
141 {
142         print_whsp(ss);
143         print_literal(ss,"'");
144         append_to_safe_string(ss,s);
145         print_literal(ss,"'");
146         return(print_whsp(ss));
147 }
148
149 static int
150 print_qdescrlist(safe_string *ss, char **sa)
151 {
152         char **sp;
153         int ret = 0;
154         
155         for (sp=sa; *sp; sp++) {
156                 ret = print_qdescr(ss,*sp);
157         }
158         /* If the list was empty, we return zero that is potentially
159          * incorrect, but since we will still appending things, the
160          * overflow will be detected later.  Maybe FIX.
161          */
162         return(ret);
163 }
164
165 static int
166 print_qdescrs(safe_string *ss, char **sa)
167 {
168         /* The only way to represent an empty list is as a qdescrlist
169          * so, if the list is empty we treat it as a long list.
170          * Really, this is what the syntax mandates.
171          */
172         if ( !sa[0] || ( sa[0] && sa[1] ) ) {
173                 print_whsp(ss);
174                 print_literal(ss,"(");
175                 print_qdescrlist(ss,sa);
176                 print_literal(ss,")");
177                 return(print_whsp(ss));
178         } else {
179           return(print_qdescr(ss,*sa));
180         }
181 }
182
183 static int
184 print_woid(safe_string *ss, char *s)
185 {
186         print_whsp(ss);
187         append_to_safe_string(ss,s);
188         return print_whsp(ss);
189 }
190
191 static int
192 print_oidlist(safe_string *ss, char **sa)
193 {
194         char **sp;
195
196         for (sp=sa; *(sp+1); sp++) {
197                 print_woid(ss,*sp);
198                 print_literal(ss,"$");
199         }
200         return(print_woid(ss,*sp));
201 }
202
203 static int
204 print_oids(safe_string *ss, char **sa)
205 {
206         if ( sa[0] && sa[1] ) {
207                 print_literal(ss,"(");
208                 print_oidlist(ss,sa);
209                 print_whsp(ss);
210                 return(print_literal(ss,")"));
211         } else {
212                 return(print_woid(ss,*sa));
213         }
214 }
215
216 static int
217 print_noidlen(safe_string *ss, char *s, int l)
218 {
219         char buf[64];
220         int ret;
221
222         ret = print_numericoid(ss,s);
223         if ( l ) {
224                 sprintf(buf,"{%d}",l);
225                 ret = print_literal(ss,buf);
226         }
227         return(ret);
228 }
229
230 char *
231 ldap_objectclass2str( LDAP_OBJECT_CLASS * oc )
232 {
233         safe_string * ss;
234         char * retstring;
235         
236         ss = new_safe_string(256);
237         if ( !ss )
238                 return NULL;
239
240         print_literal(ss,"(");
241         print_whsp(ss);
242
243         print_numericoid(ss, oc->oc_oid);
244         print_whsp(ss);
245
246         if ( oc->oc_names ) {
247                 print_literal(ss,"NAME");
248                 print_qdescrs(ss,oc->oc_names);
249         }
250
251         if ( oc->oc_desc ) {
252                 print_literal(ss,"DESC");
253                 print_qdstring(ss,oc->oc_desc);
254         }
255
256         if ( oc->oc_obsolete == LDAP_SCHEMA_YES ) {
257                 print_literal(ss, "OBSOLETE");
258                 print_whsp(ss);
259         }
260
261         if ( oc->oc_sup_oids ) {
262                 print_literal(ss,"SUP");
263                 print_oids(ss,oc->oc_sup_oids);
264         }
265
266         switch (oc->oc_kind) {
267         case LDAP_SCHEMA_ABSTRACT:
268                 print_literal(ss,"ABSTRACT");
269                 break;
270         case LDAP_SCHEMA_STRUCTURAL:
271                 print_literal(ss,"STRUCTURAL");
272                 break;
273         case LDAP_SCHEMA_AUXILIARY:
274                 print_literal(ss,"AUXILIARY");
275                 break;
276         default:
277                 print_literal(ss,"KIND-UNKNOWN");
278                 break;
279         }
280         print_whsp(ss);
281         
282         if ( oc->oc_at_oids_must ) {
283                 print_literal(ss,"MUST");
284                 print_whsp(ss);
285                 print_oids(ss,oc->oc_at_oids_must);
286                 print_whsp(ss);
287         }
288
289         if ( oc->oc_at_oids_may ) {
290                 print_literal(ss,"MAY");
291                 print_whsp(ss);
292                 print_oids(ss,oc->oc_at_oids_may);
293                 print_whsp(ss);
294         }
295
296         print_whsp(ss);
297         print_literal(ss,")");
298
299         retstring = strdup(safe_string_val(ss));
300         safe_string_free(ss);
301         return(retstring);
302 }
303
304 char *
305 ldap_attributetype2str( LDAP_ATTRIBUTE_TYPE * at )
306 {
307         safe_string * ss;
308         char * retstring;
309         
310         ss = new_safe_string(256);
311         if ( !ss )
312                 return NULL;
313
314         print_literal(ss,"(");
315         print_whsp(ss);
316
317         print_numericoid(ss, at->at_oid);
318         print_whsp(ss);
319
320         if ( at->at_names ) {
321                 print_literal(ss,"NAME");
322                 print_qdescrs(ss,at->at_names);
323         }
324
325         if ( at->at_desc ) {
326                 print_literal(ss,"DESC");
327                 print_qdstring(ss,at->at_desc);
328         }
329
330         if ( at->at_obsolete == LDAP_SCHEMA_YES ) {
331                 print_literal(ss, "OBSOLETE");
332                 print_whsp(ss);
333         }
334
335         if ( at->at_sup_oid ) {
336                 print_literal(ss,"SUP");
337                 print_woid(ss,at->at_sup_oid);
338         }
339
340         if ( at->at_equality_oid ) {
341                 print_literal(ss,"EQUALITY");
342                 print_woid(ss,at->at_equality_oid);
343         }
344
345         if ( at->at_ordering_oid ) {
346                 print_literal(ss,"ORDERING");
347                 print_woid(ss,at->at_ordering_oid);
348         }
349
350         if ( at->at_substr_oid ) {
351                 print_literal(ss,"SUBSTR");
352                 print_woid(ss,at->at_substr_oid);
353         }
354
355         if ( at->at_syntax_oid ) {
356                 print_literal(ss,"SYNTAX");
357                 print_whsp(ss);
358                 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
359         }
360
361         if ( at->at_single_value == LDAP_SCHEMA_YES ) {
362                 print_literal(ss,"SINGLE-VALUE");
363                 print_whsp(ss);
364         }
365
366         if ( at->at_collective == LDAP_SCHEMA_YES ) {
367                 print_literal(ss,"COLLECTIVE");
368                 print_whsp(ss);
369         }
370
371         if ( at->at_no_user_mod == LDAP_SCHEMA_YES ) {
372                 print_literal(ss,"NO-USER-MODIFICATION");
373                 print_whsp(ss);
374         }
375
376         if ( at->at_usage != LDAP_SCHEMA_USER_APPLICATIONS ) {
377                 print_literal(ss,"USAGE");
378                 print_whsp(ss);
379                 switch (at->at_usage) {
380                 case LDAP_SCHEMA_DIRECTORY_OPERATION:
381                         print_literal(ss,"directoryOperation");
382                         break;
383                 case LDAP_SCHEMA_DISTRIBUTED_OPERATION:
384                         print_literal(ss,"distributedOperation");
385                         break;
386                 case LDAP_SCHEMA_DSA_OPERATION:
387                         print_literal(ss,"dSAOperation");
388                         break;
389                 default:
390                         print_literal(ss,"UNKNOWN");
391                         break;
392                 }
393         }
394         
395         print_whsp(ss);
396         print_literal(ss,")");
397
398         retstring = strdup(safe_string_val(ss));
399         safe_string_free(ss);
400         return(retstring);
401 }
402
403 /*
404  * This is ripped from servers/slapd/charray.c that should be promoted
405  * to -lldap or something so that it is used everywhere.
406  */
407 static void
408 charray_free( char **array )
409 {
410         char    **a;
411
412         if ( array == NULL ) {
413                 return;
414         }
415
416         for ( a = array; *a != NULL; a++ ) {
417                 if ( *a != NULL ) {
418                         LDAP_FREE( *a );
419                 }
420         }
421         LDAP_FREE( (char *) array );
422 }
423
424 /*
425  * Now come the parsers.  There is one parser for each entity type:
426  * objectclasses, attributetypes, etc.
427  *
428  * Each of them is written as a recursive-descent parser, except that
429  * none of them is really recursive.  But the idea is kept: there
430  * is one routine per non-terminal that eithers gobbles lexical tokens
431  * or calls lower-level routines, etc.
432  *
433  * The scanner is implemented in the routine get_token.  Actually,
434  * get_token is more than a scanner and will return tokens that are
435  * in fact non-terminals in the grammar.  So you can see the whole
436  * approach as the combination of a low-level bottom-up recognizer
437  * combined with a scanner and a number of top-down parsers.  Or just
438  * consider that the real grammars recognized by the parsers are not
439  * those of the standards.  As a matter of fact, our parsers are more
440  * liberal than the spec when there is no ambiguity.
441  *
442  * The difference is pretty academic (modulo bugs or incorrect
443  * interpretation of the specs).
444  */
445
446 #define TK_NOENDQUOTE   -2
447 #define TK_OUTOFMEM     -1
448 #define TK_EOS          0
449 #define TK_UNEXPCHAR    1
450 #define TK_BAREWORD     2
451 #define TK_QDSTRING     3
452 #define TK_LEFTPAREN    4
453 #define TK_RIGHTPAREN   5
454 #define TK_DOLLAR       6
455 #define TK_QDESCR       TK_QDSTRING
456
457 struct token {
458   int type;
459   char *sval;
460 };
461
462 static int
463 get_token(char ** sp, char ** token_val)
464 {
465         int kind;
466         char * p;
467         char * q;
468         char * res;
469
470         switch (**sp) {
471         case '\0':
472                 kind = TK_EOS;
473                 (*sp)++;
474                 break;
475         case '(':
476                 kind = TK_LEFTPAREN;
477                 (*sp)++;
478                 break;
479         case ')':
480                 kind = TK_RIGHTPAREN;
481                 (*sp)++;
482                 break;
483         case '$':
484                 kind = TK_DOLLAR;
485                 (*sp)++;
486                 break;
487         case '\'':
488                 kind = TK_QDSTRING;
489                 (*sp)++;
490                 p = *sp;
491                 while ( **sp != '\'' && **sp != '\0' )
492                         (*sp)++;
493                 if ( **sp == '\'' ) {
494                         q = *sp;
495                         res = LDAP_MALLOC(q-p+1);
496                         if ( !res ) {
497                                 kind = TK_OUTOFMEM;
498                         } else {
499                                 strncpy(res,p,q-p);
500                                 res[q-p] = '\0';
501                                 *token_val = res;
502                         }
503                         (*sp)++;
504                 } else {
505                         kind = TK_NOENDQUOTE;
506                 }
507                 break;
508         default:
509                 kind = TK_BAREWORD;
510                 p = *sp;
511                 while ( !isspace(**sp) && **sp != '\0' )
512                         (*sp)++;
513                 q = *sp;
514                 res = LDAP_MALLOC(q-p+1);
515                 if ( !res ) {
516                         kind = TK_OUTOFMEM;
517                 } else {
518                         strncpy(res,p,q-p);
519                         res[q-p] = '\0';
520                         *token_val = res;
521                 }
522                 break;
523 /*              kind = TK_UNEXPCHAR; */
524 /*              break; */
525         }
526         
527         return kind;
528 }
529
530 /* Gobble optional whitespace */
531 static void
532 parse_whsp(char **sp)
533 {
534         while (isspace(**sp))
535                 (*sp)++;
536 }
537
538 /* TBC:!!
539  * General note for all parsers: to guarantee the algorithm halts they
540  * must always advance the pointer even when an error is found.  For
541  * this one is not that important since an error here is fatal at the
542  * upper layers, but it is a simple strategy that will not get in
543  * endless loops.
544  */
545
546 /* Parse a sequence of dot-separated decimal strings */
547 static char *
548 parse_numericoid(char **sp, int *code)
549 {
550         char * res;
551         char * start = *sp;
552         int len;
553
554         /* Each iteration of this loops gets one decimal string */
555         while (**sp) {
556                 if ( !isdigit(**sp) ) {
557                         /* Initial char is not a digit or char after dot is not a digit */
558                         *code = LDAP_SCHERR_NODIGIT;
559                         return NULL;
560                 }
561                 (*sp)++;
562                 while ( isdigit(**sp) )
563                         (*sp)++;
564                 if ( **sp != '.' )
565                         break;
566                 /* Otherwise, gobble the dot and loop again */
567                 (*sp)++;
568         }
569         /* At this point, *sp points at the char past the numericoid. Perfect. */
570         len = *sp - start;
571         res = LDAP_MALLOC(len+1);
572         if (!res) {
573           *code = LDAP_SCHERR_OUTOFMEM;
574           return(NULL);
575         }
576         strncpy(res,start,len);
577         res[len] = '\0';
578         return(res);
579 }
580
581 /* Parse a qdescr or a list of them enclosed in () */
582 static char **
583 parse_qdescrs(char **sp, int *code)
584 {
585         char ** res;
586         char ** res1;
587         int kind;
588         char * sval;
589         int size;
590         int pos;
591
592         parse_whsp(sp);
593         kind = get_token(sp,&sval);
594         if ( kind == TK_LEFTPAREN ) {
595                 /* Let's presume there will be at least 2 entries */
596                 size = 3;
597                 res = LDAP_CALLOC(3,sizeof(char *));
598                 if ( !res ) {
599                         *code = LDAP_SCHERR_OUTOFMEM;
600                         return NULL;
601                 }
602                 pos = 0;
603                 while (1) {
604                         parse_whsp(sp);
605                         kind = get_token(sp,&sval);
606                         if ( kind == TK_RIGHTPAREN )
607                                 break;
608                         if ( kind == TK_QDESCR ) {
609                                 if ( pos == size-2 ) {
610                                         size++;
611                                         res1 = LDAP_REALLOC(res,size*sizeof(char *));
612                                         if ( !res1 ) {
613                                                 charray_free(res);
614                                                 *code = LDAP_SCHERR_OUTOFMEM;
615                                                 return(NULL);
616                                         }
617                                         res = res1;
618                                 }
619                                 res[pos] = sval;
620                                 pos++;
621                                 parse_whsp(sp);
622                         } else {
623                                 charray_free(res);
624                                 *code = LDAP_SCHERR_UNEXPTOKEN;
625                                 return(NULL);
626                         }
627                 }
628                 res[pos] = NULL;
629                 parse_whsp(sp);
630                 return(res);
631         } else if ( kind == TK_QDESCR ) {
632                 res = LDAP_CALLOC(2,sizeof(char *));
633                 if ( !res ) {
634                         *code = LDAP_SCHERR_OUTOFMEM;
635                         return NULL;
636                 }
637                 res[0] = sval;
638                 res[1] = NULL;
639                 parse_whsp(sp);
640                 return res;
641         } else {
642                 *code = LDAP_SCHERR_BADNAME;
643                 return NULL;
644         }
645 }
646
647 /* Parse a woid */
648 static char *
649 parse_woid(char **sp, int *code)
650 {
651         char * sval;
652         int kind;
653
654         parse_whsp(sp);
655         kind = get_token(sp, &sval);
656         if ( kind != TK_BAREWORD ) {
657                 *code = LDAP_SCHERR_UNEXPTOKEN;
658                 return NULL;
659         }
660         parse_whsp(sp);
661         return sval;
662 }
663
664 /* Parse a noidlen */
665 static char *
666 parse_noidlen(char **sp, int *code, int *len)
667 {
668         char * sval;
669         int kind;
670
671         *len = 0;
672         kind = get_token(sp, &sval);
673         if ( kind != TK_BAREWORD ) {
674                 *code = LDAP_SCHERR_UNEXPTOKEN;
675                 return NULL;
676         }
677         if ( **sp == '{' ) {
678                 (*sp)++;
679                 *len = atoi(**sp);
680                 while ( isdigit(**sp) )
681                         (*sp)++;
682                 (*sp)++;
683                 if ( **sp != '}' ) {
684                         *code = LDAP_SCHERR_UNEXPTOKEN;
685                         ldap_memfree(sval);
686                         return NULL;
687                 }
688                 (*sp)++;
689         }               
690         return sval;
691 }
692
693 /* Parse a woid or a $-separated list of them enclosed in () */
694 static char **
695 parse_oids(char **sp, int *code)
696 {
697         char ** res;
698         char ** res1;
699         int kind;
700         char * sval;
701         int size;
702         int pos;
703
704         /*
705          * Strictly speaking, doing this here accepts whsp before the
706          * ( at the begining of an oidlist, but his is harmless.  Also,
707          * we are very liberal in what we accept as an OID.  Maybe
708          * refine later.
709          */
710         parse_whsp(sp);
711         kind = get_token(sp,&sval);
712         if ( kind == TK_LEFTPAREN ) {
713                 /* Let's presume there will be at least 2 entries */
714                 size = 3;
715                 res = LDAP_CALLOC(3,sizeof(char *));
716                 if ( !res ) {
717                         *code = LDAP_SCHERR_OUTOFMEM;
718                         return NULL;
719                 }
720                 pos = 0;
721                 parse_whsp(sp);
722                 kind = get_token(sp,&sval);
723                 if ( kind == TK_BAREWORD ) {
724                         res[pos] = sval;
725                         pos++;
726                 } else {
727                         *code = LDAP_SCHERR_UNEXPTOKEN;
728                         charray_free(res);
729                         return NULL;
730                 }
731                 parse_whsp(sp);
732                 while (1) {
733                         kind = get_token(sp,&sval);
734                         if ( kind == TK_RIGHTPAREN )
735                                 break;
736                         if ( kind == TK_DOLLAR ) {
737                                 parse_whsp(sp);
738                                 kind = get_token(sp,&sval);
739                                 if ( kind == TK_BAREWORD ) {
740                                         if ( pos == size-2 ) {
741                                                 size++;
742                                                 res1 = LDAP_REALLOC(res,size*sizeof(char *));
743                                                 if ( !res1 ) {
744                                                   charray_free(res);
745                                                   *code = LDAP_SCHERR_OUTOFMEM;
746                                                   return(NULL);
747                                                 }
748                                                 res = res1;
749                                         }
750                                         res[pos] = sval;
751                                         pos++;
752                                 } else {
753                                         *code = LDAP_SCHERR_UNEXPTOKEN;
754                                         charray_free(res);
755                                         return NULL;
756                                 }
757                                 parse_whsp(sp);
758                         } else {
759                                 *code = LDAP_SCHERR_UNEXPTOKEN;
760                                 charray_free(res);
761                                 return NULL;
762                         }
763                 }
764                 res[pos] = NULL;
765                 parse_whsp(sp);
766                 return(res);
767         } else if ( kind == TK_BAREWORD ) {
768                 res = LDAP_CALLOC(2,sizeof(char *));
769                 if ( !res ) {
770                         *code = LDAP_SCHERR_OUTOFMEM;
771                         return NULL;
772                 }
773                 res[0] = sval;
774                 res[1] = NULL;
775                 parse_whsp(sp);
776                 return res;
777         } else {
778                 *code = LDAP_SCHERR_BADNAME;
779                 return NULL;
780         }
781 }
782
783 static void
784 free_at(LDAP_ATTRIBUTE_TYPE * at)
785 {
786         ldap_memfree(at->at_oid);
787         charray_free(at->at_names);
788         ldap_memfree(at->at_desc);
789         ldap_memfree(at->at_sup_oid);
790         ldap_memfree(at->at_equality_oid);
791         ldap_memfree(at->at_ordering_oid);
792         ldap_memfree(at->at_substr_oid);
793         ldap_memfree(at->at_syntax_oid);
794         ldap_memfree(at);
795 }
796
797 LDAP_ATTRIBUTE_TYPE *
798 ldap_str2attributetype( char * s, int * code, char ** errp )
799 {
800         int kind;
801         char * ss = s;
802         char * sval;
803         int seen_name = 0;
804         int seen_desc = 0;
805         int seen_obsolete = 0;
806         int seen_sup = 0;
807         int seen_equality = 0;
808         int seen_ordering = 0;
809         int seen_substr = 0;
810         int seen_syntax = 0;
811         int seen_usage = 0;
812         int seen_kind = 0;
813         int seen_must = 0;
814         int seen_may = 0;
815         LDAP_ATTRIBUTE_TYPE * at;
816
817         *errp = s;
818         at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
819
820         if ( !at ) {
821                 *code = LDAP_SCHERR_OUTOFMEM;
822                 return NULL;
823         }
824
825         kind = get_token(&ss,&sval);
826         if ( kind != TK_LEFTPAREN ) {
827                 *code = LDAP_SCHERR_NOLEFTPAREN;
828                 free_at(at);
829                 return NULL;
830         }
831
832         parse_whsp(&ss);
833         at->at_oid = parse_numericoid(&ss,code);
834         if ( !at->at_oid ) {
835                 *errp = ss;
836                 free_at(at);
837                 return NULL;
838         }
839         parse_whsp(&ss);
840
841         /*
842          * Beyond this point we will be liberal an accept the items
843          * in any order.
844          */
845         while (1) {
846                 kind = get_token(&ss,&sval);
847                 switch (kind) {
848                 case TK_EOS:
849                         *code = LDAP_SCHERR_NORIGHTPAREN;
850                         *errp = ss;
851                         free_at(at);
852                         return NULL;
853                 case TK_RIGHTPAREN:
854                         return at;
855                 case TK_BAREWORD:
856                         if ( !strcmp(sval,"NAME") ) {
857                                 if ( seen_name ) {
858                                         *code = LDAP_SCHERR_DUPOPT;
859                                         *errp = ss;
860                                         free_at(at);
861                                         return(NULL);
862                                 }
863                                 seen_name = 1;
864                                 at->at_names = parse_qdescrs(&ss,code);
865                                 if ( !at->at_names ) {
866                                         if ( *code != LDAP_SCHERR_OUTOFMEM )
867                                                 *code = LDAP_SCHERR_BADNAME;
868                                         *errp = ss;
869                                         free_at(at);
870                                         return NULL;
871                                 }
872                         } else if ( !strcmp(sval,"DESC") ) {
873                                 if ( seen_desc ) {
874                                         *code = LDAP_SCHERR_DUPOPT;
875                                         *errp = ss;
876                                         free_at(at);
877                                         return(NULL);
878                                 }
879                                 seen_desc = 1;
880                                 parse_whsp(&ss);
881                                 kind = get_token(&ss,&sval);
882                                 if ( kind != TK_QDSTRING ) {
883                                         *code = LDAP_SCHERR_UNEXPTOKEN;
884                                         *errp = ss;
885                                         free_at(at);
886                                         return NULL;
887                                 }
888                                 at->at_desc = sval;
889                                 parse_whsp(&ss);
890                         } else if ( !strcmp(sval,"OBSOLETE") ) {
891                                 if ( seen_obsolete ) {
892                                         *code = LDAP_SCHERR_DUPOPT;
893                                         *errp = ss;
894                                         free_at(at);
895                                         return(NULL);
896                                 }
897                                 seen_obsolete = 1;
898                                 at->at_obsolete = LDAP_SCHEMA_YES;
899                                 parse_whsp(&ss);
900                         } else if ( !strcmp(sval,"SUP") ) {
901                                 if ( seen_sup ) {
902                                         *code = LDAP_SCHERR_DUPOPT;
903                                         *errp = ss;
904                                         free_at(at);
905                                         return(NULL);
906                                 }
907                                 seen_sup = 1;
908                                 at->at_sup_oid = parse_woid(&ss,code);
909                                 if ( !at->at_sup_oid ) {
910                                         *errp = ss;
911                                         free_at(at);
912                                         return NULL;
913                                 }
914                         } else if ( !strcmp(sval,"EQUALITY") ) {
915                                 if ( seen_equality ) {
916                                         *code = LDAP_SCHERR_DUPOPT;
917                                         *errp = ss;
918                                         free_at(at);
919                                         return(NULL);
920                                 }
921                                 seen_equality = 1;
922                                 at->at_equality_oid = parse_woid(&ss,code);
923                                 if ( !at->at_equality_oid ) {
924                                         *errp = ss;
925                                         free_at(at);
926                                         return NULL;
927                                 }
928                         } else if ( !strcmp(sval,"ORDERING") ) {
929                                 if ( seen_ordering ) {
930                                         *code = LDAP_SCHERR_DUPOPT;
931                                         *errp = ss;
932                                         free_at(at);
933                                         return(NULL);
934                                 }
935                                 seen_ordering = 1;
936                                 at->at_ordering_oid = parse_woid(&ss,code);
937                                 if ( !at->at_ordering_oid ) {
938                                         *errp = ss;
939                                         free_at(at);
940                                         return NULL;
941                                 }
942                         } else if ( !strcmp(sval,"SUBSTR") ) {
943                                 if ( seen_substr ) {
944                                         *code = LDAP_SCHERR_DUPOPT;
945                                         *errp = ss;
946                                         free_at(at);
947                                         return(NULL);
948                                 }
949                                 seen_substr = 1;
950                                 at->at_substr_oid = parse_woid(&ss,code);
951                                 if ( !at->at_substr_oid ) {
952                                         *errp = ss;
953                                         free_at(at);
954                                         return NULL;
955                                 }
956                         } else if ( !strcmp(sval,"SYNTAX") ) {
957                                 if ( seen_syntax ) {
958                                         *code = LDAP_SCHERR_DUPOPT;
959                                         *errp = ss;
960                                         free_at(at);
961                                         return(NULL);
962                                 }
963                                 seen_syntax = 1;
964                                 parse_whsp(&ss);
965                                 at->at_syntax_oid = parse_noidlen(&ss,code,&at->at_syntax_len);
966                                 if ( !at->at_syntax_oid ) {
967                                         *errp = ss;
968                                         free_at(at);
969                                         return NULL;
970                                 }
971                         } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
972                                 if ( at->at_single_value ) {
973                                         *code = LDAP_SCHERR_DUPOPT;
974                                         *errp = ss;
975                                         free_at(at);
976                                         return(NULL);
977                                 }
978                                 at->at_single_value = LDAP_SCHEMA_YES;
979                                 parse_whsp(&ss);
980                         } else if ( !strcmp(sval,"COLLECTIVE") ) {
981                                 if ( at->at_collective ) {
982                                         *code = LDAP_SCHERR_DUPOPT;
983                                         *errp = ss;
984                                         free_at(at);
985                                         return(NULL);
986                                 }
987                                 at->at_collective = LDAP_SCHEMA_YES;
988                                 parse_whsp(&ss);
989                         } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
990                                 if ( at->at_no_user_mod ) {
991                                         *code = LDAP_SCHERR_DUPOPT;
992                                         *errp = ss;
993                                         free_at(at);
994                                         return(NULL);
995                                 }
996                                 at->at_no_user_mod = LDAP_SCHEMA_YES;
997                                 parse_whsp(&ss);
998                         } else if ( !strcmp(sval,"USAGE") ) {
999                                 if ( seen_usage ) {
1000                                         *code = LDAP_SCHERR_DUPOPT;
1001                                         *errp = ss;
1002                                         free_at(at);
1003                                         return(NULL);
1004                                 }
1005                                 seen_usage = 1;
1006                                 parse_whsp(&ss);
1007                                 kind = get_token(&ss,&sval);
1008                                 if ( kind != TK_BAREWORD ) {
1009                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1010                                         *errp = ss;
1011                                         free_at(at);
1012                                         return NULL;
1013                                 }
1014                                 if ( !strcasecmp(sval,"userApplications") )
1015                                         at->at_usage = LDAP_SCHEMA_USER_APPLICATIONS;
1016                                 else if ( !strcasecmp(sval,"directoryOperation") )
1017                                         at->at_usage = LDAP_SCHEMA_DIRECTORY_OPERATION;
1018                                 else if ( !strcasecmp(sval,"distributedOperation") )
1019                                         at->at_usage = LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1020                                 else if ( !strcasecmp(sval,"dSAOperation") )
1021                                         at->at_usage = LDAP_SCHEMA_DSA_OPERATION;
1022                                 else {
1023                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1024                                         *errp = ss;
1025                                         free_at(at);
1026                                         return NULL;
1027                                 }
1028                         } else {
1029                                 *code = LDAP_SCHERR_UNEXPTOKEN;
1030                                 *errp = ss;
1031                                 free_at(at);
1032                                 return NULL;
1033                         }
1034                         break;
1035                 default:
1036                         *code = LDAP_SCHERR_UNEXPTOKEN;
1037                         *errp = ss;
1038                         free_at(at);
1039                         return NULL;
1040                 }
1041         }
1042 }
1043
1044 static void
1045 free_oc(LDAP_OBJECT_CLASS * oc)
1046 {
1047         ldap_memfree(oc->oc_oid);
1048         charray_free(oc->oc_names);
1049         ldap_memfree(oc->oc_desc);
1050         charray_free(oc->oc_sup_oids);
1051         charray_free(oc->oc_at_oids_must);
1052         charray_free(oc->oc_at_oids_may);
1053         ldap_memfree(oc);
1054 }
1055
1056 LDAP_OBJECT_CLASS *
1057 ldap_str2objectclass( char * s, int * code, char ** errp )
1058 {
1059         int kind;
1060         char * ss = s;
1061         char * sval;
1062         int seen_name = 0;
1063         int seen_desc = 0;
1064         int seen_obsolete = 0;
1065         int seen_sup = 0;
1066         int seen_kind = 0;
1067         int seen_must = 0;
1068         int seen_may = 0;
1069         LDAP_OBJECT_CLASS * oc;
1070
1071         *errp = s;
1072         oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1073
1074         if ( !oc ) {
1075                 *code = LDAP_SCHERR_OUTOFMEM;
1076                 return NULL;
1077         }
1078
1079         kind = get_token(&ss,&sval);
1080         if ( kind != TK_LEFTPAREN ) {
1081                 *code = LDAP_SCHERR_NOLEFTPAREN;
1082                 free_oc(oc);
1083                 return NULL;
1084         }
1085
1086         parse_whsp(&ss);
1087         oc->oc_oid = parse_numericoid(&ss,code);
1088         if ( !oc->oc_oid ) {
1089                 *errp = ss;
1090                 free_oc(oc);
1091                 return NULL;
1092         }
1093         parse_whsp(&ss);
1094
1095         /*
1096          * Beyond this point we will be liberal an accept the items
1097          * in any order.
1098          */
1099         while (1) {
1100                 kind = get_token(&ss,&sval);
1101                 switch (kind) {
1102                 case TK_EOS:
1103                         *code = LDAP_SCHERR_NORIGHTPAREN;
1104                         *errp = ss;
1105                         free_oc(oc);
1106                         return NULL;
1107                 case TK_RIGHTPAREN:
1108                         return oc;
1109                 case TK_BAREWORD:
1110                         if ( !strcmp(sval,"NAME") ) {
1111                                 if ( seen_name ) {
1112                                         *code = LDAP_SCHERR_DUPOPT;
1113                                         *errp = ss;
1114                                         free_oc(oc);
1115                                         return(NULL);
1116                                 }
1117                                 seen_name = 1;
1118                                 oc->oc_names = parse_qdescrs(&ss,code);
1119                                 if ( !oc->oc_names ) {
1120                                         if ( *code != LDAP_SCHERR_OUTOFMEM )
1121                                                 *code = LDAP_SCHERR_BADNAME;
1122                                         *errp = ss;
1123                                         free_oc(oc);
1124                                         return NULL;
1125                                 }
1126                         } else if ( !strcmp(sval,"DESC") ) {
1127                                 if ( seen_desc ) {
1128                                         *code = LDAP_SCHERR_DUPOPT;
1129                                         *errp = ss;
1130                                         free_oc(oc);
1131                                         return(NULL);
1132                                 }
1133                                 seen_desc = 1;
1134                                 parse_whsp(&ss);
1135                                 kind = get_token(&ss,&sval);
1136                                 if ( kind != TK_QDSTRING ) {
1137                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1138                                         *errp = ss;
1139                                         free_oc(oc);
1140                                         return NULL;
1141                                 }
1142                                 oc->oc_desc = sval;
1143                                 parse_whsp(&ss);
1144                         } else if ( !strcmp(sval,"OBSOLETE") ) {
1145                                 if ( seen_obsolete ) {
1146                                         *code = LDAP_SCHERR_DUPOPT;
1147                                         *errp = ss;
1148                                         free_oc(oc);
1149                                         return(NULL);
1150                                 }
1151                                 seen_obsolete = 1;
1152                                 oc->oc_obsolete = LDAP_SCHEMA_YES;
1153                                 parse_whsp(&ss);
1154                         } else if ( !strcmp(sval,"SUP") ) {
1155                                 if ( seen_sup ) {
1156                                         *code = LDAP_SCHERR_DUPOPT;
1157                                         *errp = ss;
1158                                         free_oc(oc);
1159                                         return(NULL);
1160                                 }
1161                                 seen_sup = 1;
1162                                 /* Netscape DS is broken or I have not
1163                                    understood the syntax. */
1164                                 /* oc->oc_sup_oids = parse_oids(&ss,code); */
1165                                 oc->oc_sup_oids = parse_qdescrs(&ss,code);
1166                                 if ( !oc->oc_sup_oids ) {
1167                                         *errp = ss;
1168                                         free_oc(oc);
1169                                         return NULL;
1170                                 }
1171                         } else if ( !strcmp(sval,"ABSTRACT") ) {
1172                                 if ( seen_kind ) {
1173                                         *code = LDAP_SCHERR_DUPOPT;
1174                                         *errp = ss;
1175                                         free_oc(oc);
1176                                         return(NULL);
1177                                 }
1178                                 seen_kind = 1;
1179                                 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1180                                 parse_whsp(&ss);
1181                         } else if ( !strcmp(sval,"STRUCTURAL") ) {
1182                                 if ( seen_kind ) {
1183                                         *code = LDAP_SCHERR_DUPOPT;
1184                                         *errp = ss;
1185                                         free_oc(oc);
1186                                         return(NULL);
1187                                 }
1188                                 seen_kind = 1;
1189                                 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1190                                 parse_whsp(&ss);
1191                         } else if ( !strcmp(sval,"AUXILIARY") ) {
1192                                 if ( seen_kind ) {
1193                                         *code = LDAP_SCHERR_DUPOPT;
1194                                         *errp = ss;
1195                                         free_oc(oc);
1196                                         return(NULL);
1197                                 }
1198                                 seen_kind = 1;
1199                                 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1200                                 parse_whsp(&ss);
1201                         } else if ( !strcmp(sval,"MUST") ) {
1202                                 if ( seen_must ) {
1203                                         *code = LDAP_SCHERR_DUPOPT;
1204                                         *errp = ss;
1205                                         free_oc(oc);
1206                                         return(NULL);
1207                                 }
1208                                 seen_must = 1;
1209                                 oc->oc_at_oids_must = parse_oids(&ss,code);
1210                                 if ( !oc->oc_at_oids_must ) {
1211                                         *errp = ss;
1212                                         free_oc(oc);
1213                                         return NULL;
1214                                 }
1215                                 parse_whsp(&ss);
1216                         } else if ( !strcmp(sval,"MAY") ) {
1217                                 if ( seen_may ) {
1218                                         *code = LDAP_SCHERR_DUPOPT;
1219                                         *errp = ss;
1220                                         free_oc(oc);
1221                                         return(NULL);
1222                                 }
1223                                 seen_may = 1;
1224                                 oc->oc_at_oids_may = parse_oids(&ss,code);
1225                                 if ( !oc->oc_at_oids_may ) {
1226                                         *errp = ss;
1227                                         free_oc(oc);
1228                                         return NULL;
1229                                 }
1230                                 parse_whsp(&ss);
1231                         } else {
1232                                 *code = LDAP_SCHERR_UNEXPTOKEN;
1233                                 *errp = ss;
1234                                 free_oc(oc);
1235                                 return NULL;
1236                         }
1237                         break;
1238                 default:
1239                         *code = LDAP_SCHERR_UNEXPTOKEN;
1240                         *errp = ss;
1241                         free_oc(oc);
1242                         return NULL;
1243                 }
1244         }
1245 }
1246
1247 static char *err2text[] = {
1248         "",
1249         "Out of memory",
1250         "Unexpected token",
1251         "Missing opening parenthesis",
1252         "Missing closing parenthesis",
1253         "Expecting digit",
1254         "Expecting a name",
1255         "Bad description",
1256         "Bad superiors",
1257         "Duplicate option"
1258 };
1259
1260 char *
1261 ldap_scherr2str(int code)
1262 {
1263         if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1264                 return "Unknown error";
1265         } else {
1266                 return err2text[code];
1267         }
1268 }