]> git.sur5r.net Git - openldap/blob - libraries/libldap/schema.c
Free strings returned by ldap_get_option().
[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 static 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 /*
694  * Next routine will accept a qdstring in place of an oid.  This is
695  * necessary to interoperate with Netscape Directory server that
696  * will improperly quote each oid (at least those of the descr kind)
697  * in the SUP clause.
698  */
699
700 /* Parse a woid or a $-separated list of them enclosed in () */
701 static char **
702 parse_oids(char **sp, int *code)
703 {
704         char ** res;
705         char ** res1;
706         int kind;
707         char * sval;
708         int size;
709         int pos;
710
711         /*
712          * Strictly speaking, doing this here accepts whsp before the
713          * ( at the begining of an oidlist, but his is harmless.  Also,
714          * we are very liberal in what we accept as an OID.  Maybe
715          * refine later.
716          */
717         parse_whsp(sp);
718         kind = get_token(sp,&sval);
719         if ( kind == TK_LEFTPAREN ) {
720                 /* Let's presume there will be at least 2 entries */
721                 size = 3;
722                 res = LDAP_CALLOC(3,sizeof(char *));
723                 if ( !res ) {
724                         *code = LDAP_SCHERR_OUTOFMEM;
725                         return NULL;
726                 }
727                 pos = 0;
728                 parse_whsp(sp);
729                 kind = get_token(sp,&sval);
730                 if ( kind == TK_BAREWORD || kind == TK_QDSTRING ) {
731                         res[pos] = sval;
732                         pos++;
733                 } else {
734                         *code = LDAP_SCHERR_UNEXPTOKEN;
735                         charray_free(res);
736                         return NULL;
737                 }
738                 parse_whsp(sp);
739                 while (1) {
740                         kind = get_token(sp,&sval);
741                         if ( kind == TK_RIGHTPAREN )
742                                 break;
743                         if ( kind == TK_DOLLAR ) {
744                                 parse_whsp(sp);
745                                 kind = get_token(sp,&sval);
746                                 if ( kind == TK_BAREWORD ||
747                                      kind == TK_QDSTRING ) {
748                                         if ( pos == size-2 ) {
749                                                 size++;
750                                                 res1 = LDAP_REALLOC(res,size*sizeof(char *));
751                                                 if ( !res1 ) {
752                                                   charray_free(res);
753                                                   *code = LDAP_SCHERR_OUTOFMEM;
754                                                   return(NULL);
755                                                 }
756                                                 res = res1;
757                                         }
758                                         res[pos] = sval;
759                                         pos++;
760                                 } else {
761                                         *code = LDAP_SCHERR_UNEXPTOKEN;
762                                         charray_free(res);
763                                         return NULL;
764                                 }
765                                 parse_whsp(sp);
766                         } else {
767                                 *code = LDAP_SCHERR_UNEXPTOKEN;
768                                 charray_free(res);
769                                 return NULL;
770                         }
771                 }
772                 res[pos] = NULL;
773                 parse_whsp(sp);
774                 return(res);
775         } else if ( kind == TK_BAREWORD || kind == TK_QDSTRING ) {
776                 res = LDAP_CALLOC(2,sizeof(char *));
777                 if ( !res ) {
778                         *code = LDAP_SCHERR_OUTOFMEM;
779                         return NULL;
780                 }
781                 res[0] = sval;
782                 res[1] = NULL;
783                 parse_whsp(sp);
784                 return res;
785         } else {
786                 *code = LDAP_SCHERR_BADNAME;
787                 return NULL;
788         }
789 }
790
791 static void
792 free_at(LDAP_ATTRIBUTE_TYPE * at)
793 {
794         ldap_memfree(at->at_oid);
795         charray_free(at->at_names);
796         ldap_memfree(at->at_desc);
797         ldap_memfree(at->at_sup_oid);
798         ldap_memfree(at->at_equality_oid);
799         ldap_memfree(at->at_ordering_oid);
800         ldap_memfree(at->at_substr_oid);
801         ldap_memfree(at->at_syntax_oid);
802         ldap_memfree(at);
803 }
804
805 LDAP_ATTRIBUTE_TYPE *
806 ldap_str2attributetype( char * s, int * code, char ** errp )
807 {
808         int kind;
809         char * ss = s;
810         char * sval;
811         int seen_name = 0;
812         int seen_desc = 0;
813         int seen_obsolete = 0;
814         int seen_sup = 0;
815         int seen_equality = 0;
816         int seen_ordering = 0;
817         int seen_substr = 0;
818         int seen_syntax = 0;
819         int seen_usage = 0;
820         int seen_kind = 0;
821         int seen_must = 0;
822         int seen_may = 0;
823         LDAP_ATTRIBUTE_TYPE * at;
824
825         if ( !s ) {
826                 *code = LDAP_SCHERR_EMPTY;
827                 *errp = "";
828                 return NULL;
829         }
830
831         *errp = s;
832         at = LDAP_CALLOC(1,sizeof(LDAP_ATTRIBUTE_TYPE));
833
834         if ( !at ) {
835                 *code = LDAP_SCHERR_OUTOFMEM;
836                 return NULL;
837         }
838
839         kind = get_token(&ss,&sval);
840         if ( kind != TK_LEFTPAREN ) {
841                 *code = LDAP_SCHERR_NOLEFTPAREN;
842                 free_at(at);
843                 return NULL;
844         }
845
846         parse_whsp(&ss);
847         at->at_oid = parse_numericoid(&ss,code);
848         if ( !at->at_oid ) {
849                 *errp = ss;
850                 free_at(at);
851                 return NULL;
852         }
853         parse_whsp(&ss);
854
855         /*
856          * Beyond this point we will be liberal an accept the items
857          * in any order.
858          */
859         while (1) {
860                 kind = get_token(&ss,&sval);
861                 switch (kind) {
862                 case TK_EOS:
863                         *code = LDAP_SCHERR_NORIGHTPAREN;
864                         *errp = ss;
865                         free_at(at);
866                         return NULL;
867                 case TK_RIGHTPAREN:
868                         return at;
869                 case TK_BAREWORD:
870                         if ( !strcmp(sval,"NAME") ) {
871                                 if ( seen_name ) {
872                                         *code = LDAP_SCHERR_DUPOPT;
873                                         *errp = ss;
874                                         free_at(at);
875                                         return(NULL);
876                                 }
877                                 seen_name = 1;
878                                 at->at_names = parse_qdescrs(&ss,code);
879                                 if ( !at->at_names ) {
880                                         if ( *code != LDAP_SCHERR_OUTOFMEM )
881                                                 *code = LDAP_SCHERR_BADNAME;
882                                         *errp = ss;
883                                         free_at(at);
884                                         return NULL;
885                                 }
886                         } else if ( !strcmp(sval,"DESC") ) {
887                                 if ( seen_desc ) {
888                                         *code = LDAP_SCHERR_DUPOPT;
889                                         *errp = ss;
890                                         free_at(at);
891                                         return(NULL);
892                                 }
893                                 seen_desc = 1;
894                                 parse_whsp(&ss);
895                                 kind = get_token(&ss,&sval);
896                                 if ( kind != TK_QDSTRING ) {
897                                         *code = LDAP_SCHERR_UNEXPTOKEN;
898                                         *errp = ss;
899                                         free_at(at);
900                                         return NULL;
901                                 }
902                                 at->at_desc = sval;
903                                 parse_whsp(&ss);
904                         } else if ( !strcmp(sval,"OBSOLETE") ) {
905                                 if ( seen_obsolete ) {
906                                         *code = LDAP_SCHERR_DUPOPT;
907                                         *errp = ss;
908                                         free_at(at);
909                                         return(NULL);
910                                 }
911                                 seen_obsolete = 1;
912                                 at->at_obsolete = LDAP_SCHEMA_YES;
913                                 parse_whsp(&ss);
914                         } else if ( !strcmp(sval,"SUP") ) {
915                                 if ( seen_sup ) {
916                                         *code = LDAP_SCHERR_DUPOPT;
917                                         *errp = ss;
918                                         free_at(at);
919                                         return(NULL);
920                                 }
921                                 seen_sup = 1;
922                                 at->at_sup_oid = parse_woid(&ss,code);
923                                 if ( !at->at_sup_oid ) {
924                                         *errp = ss;
925                                         free_at(at);
926                                         return NULL;
927                                 }
928                         } else if ( !strcmp(sval,"EQUALITY") ) {
929                                 if ( seen_equality ) {
930                                         *code = LDAP_SCHERR_DUPOPT;
931                                         *errp = ss;
932                                         free_at(at);
933                                         return(NULL);
934                                 }
935                                 seen_equality = 1;
936                                 at->at_equality_oid = parse_woid(&ss,code);
937                                 if ( !at->at_equality_oid ) {
938                                         *errp = ss;
939                                         free_at(at);
940                                         return NULL;
941                                 }
942                         } else if ( !strcmp(sval,"ORDERING") ) {
943                                 if ( seen_ordering ) {
944                                         *code = LDAP_SCHERR_DUPOPT;
945                                         *errp = ss;
946                                         free_at(at);
947                                         return(NULL);
948                                 }
949                                 seen_ordering = 1;
950                                 at->at_ordering_oid = parse_woid(&ss,code);
951                                 if ( !at->at_ordering_oid ) {
952                                         *errp = ss;
953                                         free_at(at);
954                                         return NULL;
955                                 }
956                         } else if ( !strcmp(sval,"SUBSTR") ) {
957                                 if ( seen_substr ) {
958                                         *code = LDAP_SCHERR_DUPOPT;
959                                         *errp = ss;
960                                         free_at(at);
961                                         return(NULL);
962                                 }
963                                 seen_substr = 1;
964                                 at->at_substr_oid = parse_woid(&ss,code);
965                                 if ( !at->at_substr_oid ) {
966                                         *errp = ss;
967                                         free_at(at);
968                                         return NULL;
969                                 }
970                         } else if ( !strcmp(sval,"SYNTAX") ) {
971                                 if ( seen_syntax ) {
972                                         *code = LDAP_SCHERR_DUPOPT;
973                                         *errp = ss;
974                                         free_at(at);
975                                         return(NULL);
976                                 }
977                                 seen_syntax = 1;
978                                 parse_whsp(&ss);
979                                 at->at_syntax_oid = parse_noidlen(&ss,code,&at->at_syntax_len);
980                                 if ( !at->at_syntax_oid ) {
981                                         *errp = ss;
982                                         free_at(at);
983                                         return NULL;
984                                 }
985                                 parse_whsp(&ss);
986                         } else if ( !strcmp(sval,"SINGLE-VALUE") ) {
987                                 if ( at->at_single_value ) {
988                                         *code = LDAP_SCHERR_DUPOPT;
989                                         *errp = ss;
990                                         free_at(at);
991                                         return(NULL);
992                                 }
993                                 at->at_single_value = LDAP_SCHEMA_YES;
994                                 parse_whsp(&ss);
995                         } else if ( !strcmp(sval,"COLLECTIVE") ) {
996                                 if ( at->at_collective ) {
997                                         *code = LDAP_SCHERR_DUPOPT;
998                                         *errp = ss;
999                                         free_at(at);
1000                                         return(NULL);
1001                                 }
1002                                 at->at_collective = LDAP_SCHEMA_YES;
1003                                 parse_whsp(&ss);
1004                         } else if ( !strcmp(sval,"NO-USER-MODIFICATION") ) {
1005                                 if ( at->at_no_user_mod ) {
1006                                         *code = LDAP_SCHERR_DUPOPT;
1007                                         *errp = ss;
1008                                         free_at(at);
1009                                         return(NULL);
1010                                 }
1011                                 at->at_no_user_mod = LDAP_SCHEMA_YES;
1012                                 parse_whsp(&ss);
1013                         } else if ( !strcmp(sval,"USAGE") ) {
1014                                 if ( seen_usage ) {
1015                                         *code = LDAP_SCHERR_DUPOPT;
1016                                         *errp = ss;
1017                                         free_at(at);
1018                                         return(NULL);
1019                                 }
1020                                 seen_usage = 1;
1021                                 parse_whsp(&ss);
1022                                 kind = get_token(&ss,&sval);
1023                                 if ( kind != TK_BAREWORD ) {
1024                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1025                                         *errp = ss;
1026                                         free_at(at);
1027                                         return NULL;
1028                                 }
1029                                 if ( !strcasecmp(sval,"userApplications") )
1030                                         at->at_usage = LDAP_SCHEMA_USER_APPLICATIONS;
1031                                 else if ( !strcasecmp(sval,"directoryOperation") )
1032                                         at->at_usage = LDAP_SCHEMA_DIRECTORY_OPERATION;
1033                                 else if ( !strcasecmp(sval,"distributedOperation") )
1034                                         at->at_usage = LDAP_SCHEMA_DISTRIBUTED_OPERATION;
1035                                 else if ( !strcasecmp(sval,"dSAOperation") )
1036                                         at->at_usage = LDAP_SCHEMA_DSA_OPERATION;
1037                                 else {
1038                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1039                                         *errp = ss;
1040                                         free_at(at);
1041                                         return NULL;
1042                                 }
1043                                 parse_whsp(&ss);
1044                         } else {
1045                                 *code = LDAP_SCHERR_UNEXPTOKEN;
1046                                 *errp = ss;
1047                                 free_at(at);
1048                                 return NULL;
1049                         }
1050                         break;
1051                 default:
1052                         *code = LDAP_SCHERR_UNEXPTOKEN;
1053                         *errp = ss;
1054                         free_at(at);
1055                         return NULL;
1056                 }
1057         }
1058 }
1059
1060 static void
1061 free_oc(LDAP_OBJECT_CLASS * oc)
1062 {
1063         ldap_memfree(oc->oc_oid);
1064         charray_free(oc->oc_names);
1065         ldap_memfree(oc->oc_desc);
1066         charray_free(oc->oc_sup_oids);
1067         charray_free(oc->oc_at_oids_must);
1068         charray_free(oc->oc_at_oids_may);
1069         ldap_memfree(oc);
1070 }
1071
1072 LDAP_OBJECT_CLASS *
1073 ldap_str2objectclass( char * s, int * code, char ** errp )
1074 {
1075         int kind;
1076         char * ss = s;
1077         char * sval;
1078         int seen_name = 0;
1079         int seen_desc = 0;
1080         int seen_obsolete = 0;
1081         int seen_sup = 0;
1082         int seen_kind = 0;
1083         int seen_must = 0;
1084         int seen_may = 0;
1085         LDAP_OBJECT_CLASS * oc;
1086
1087         if ( !s ) {
1088                 *code = LDAP_SCHERR_EMPTY;
1089                 *errp = "";
1090                 return NULL;
1091         }
1092
1093         *errp = s;
1094         oc = LDAP_CALLOC(1,sizeof(LDAP_OBJECT_CLASS));
1095
1096         if ( !oc ) {
1097                 *code = LDAP_SCHERR_OUTOFMEM;
1098                 return NULL;
1099         }
1100
1101         kind = get_token(&ss,&sval);
1102         if ( kind != TK_LEFTPAREN ) {
1103                 *code = LDAP_SCHERR_NOLEFTPAREN;
1104                 free_oc(oc);
1105                 return NULL;
1106         }
1107
1108         parse_whsp(&ss);
1109         oc->oc_oid = parse_numericoid(&ss,code);
1110         if ( !oc->oc_oid ) {
1111                 *errp = ss;
1112                 free_oc(oc);
1113                 return NULL;
1114         }
1115         parse_whsp(&ss);
1116
1117         /*
1118          * Beyond this point we will be liberal an accept the items
1119          * in any order.
1120          */
1121         while (1) {
1122                 kind = get_token(&ss,&sval);
1123                 switch (kind) {
1124                 case TK_EOS:
1125                         *code = LDAP_SCHERR_NORIGHTPAREN;
1126                         *errp = ss;
1127                         free_oc(oc);
1128                         return NULL;
1129                 case TK_RIGHTPAREN:
1130                         return oc;
1131                 case TK_BAREWORD:
1132                         if ( !strcmp(sval,"NAME") ) {
1133                                 if ( seen_name ) {
1134                                         *code = LDAP_SCHERR_DUPOPT;
1135                                         *errp = ss;
1136                                         free_oc(oc);
1137                                         return(NULL);
1138                                 }
1139                                 seen_name = 1;
1140                                 oc->oc_names = parse_qdescrs(&ss,code);
1141                                 if ( !oc->oc_names ) {
1142                                         if ( *code != LDAP_SCHERR_OUTOFMEM )
1143                                                 *code = LDAP_SCHERR_BADNAME;
1144                                         *errp = ss;
1145                                         free_oc(oc);
1146                                         return NULL;
1147                                 }
1148                         } else if ( !strcmp(sval,"DESC") ) {
1149                                 if ( seen_desc ) {
1150                                         *code = LDAP_SCHERR_DUPOPT;
1151                                         *errp = ss;
1152                                         free_oc(oc);
1153                                         return(NULL);
1154                                 }
1155                                 seen_desc = 1;
1156                                 parse_whsp(&ss);
1157                                 kind = get_token(&ss,&sval);
1158                                 if ( kind != TK_QDSTRING ) {
1159                                         *code = LDAP_SCHERR_UNEXPTOKEN;
1160                                         *errp = ss;
1161                                         free_oc(oc);
1162                                         return NULL;
1163                                 }
1164                                 oc->oc_desc = sval;
1165                                 parse_whsp(&ss);
1166                         } else if ( !strcmp(sval,"OBSOLETE") ) {
1167                                 if ( seen_obsolete ) {
1168                                         *code = LDAP_SCHERR_DUPOPT;
1169                                         *errp = ss;
1170                                         free_oc(oc);
1171                                         return(NULL);
1172                                 }
1173                                 seen_obsolete = 1;
1174                                 oc->oc_obsolete = LDAP_SCHEMA_YES;
1175                                 parse_whsp(&ss);
1176                         } else if ( !strcmp(sval,"SUP") ) {
1177                                 if ( seen_sup ) {
1178                                         *code = LDAP_SCHERR_DUPOPT;
1179                                         *errp = ss;
1180                                         free_oc(oc);
1181                                         return(NULL);
1182                                 }
1183                                 seen_sup = 1;
1184                                 oc->oc_sup_oids = parse_oids(&ss,code);
1185                                 if ( !oc->oc_sup_oids ) {
1186                                         *errp = ss;
1187                                         free_oc(oc);
1188                                         return NULL;
1189                                 }
1190                         } else if ( !strcmp(sval,"ABSTRACT") ) {
1191                                 if ( seen_kind ) {
1192                                         *code = LDAP_SCHERR_DUPOPT;
1193                                         *errp = ss;
1194                                         free_oc(oc);
1195                                         return(NULL);
1196                                 }
1197                                 seen_kind = 1;
1198                                 oc->oc_kind = LDAP_SCHEMA_ABSTRACT;
1199                                 parse_whsp(&ss);
1200                         } else if ( !strcmp(sval,"STRUCTURAL") ) {
1201                                 if ( seen_kind ) {
1202                                         *code = LDAP_SCHERR_DUPOPT;
1203                                         *errp = ss;
1204                                         free_oc(oc);
1205                                         return(NULL);
1206                                 }
1207                                 seen_kind = 1;
1208                                 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
1209                                 parse_whsp(&ss);
1210                         } else if ( !strcmp(sval,"AUXILIARY") ) {
1211                                 if ( seen_kind ) {
1212                                         *code = LDAP_SCHERR_DUPOPT;
1213                                         *errp = ss;
1214                                         free_oc(oc);
1215                                         return(NULL);
1216                                 }
1217                                 seen_kind = 1;
1218                                 oc->oc_kind = LDAP_SCHEMA_AUXILIARY;
1219                                 parse_whsp(&ss);
1220                         } else if ( !strcmp(sval,"MUST") ) {
1221                                 if ( seen_must ) {
1222                                         *code = LDAP_SCHERR_DUPOPT;
1223                                         *errp = ss;
1224                                         free_oc(oc);
1225                                         return(NULL);
1226                                 }
1227                                 seen_must = 1;
1228                                 oc->oc_at_oids_must = parse_oids(&ss,code);
1229                                 if ( !oc->oc_at_oids_must ) {
1230                                         *errp = ss;
1231                                         free_oc(oc);
1232                                         return NULL;
1233                                 }
1234                                 parse_whsp(&ss);
1235                         } else if ( !strcmp(sval,"MAY") ) {
1236                                 if ( seen_may ) {
1237                                         *code = LDAP_SCHERR_DUPOPT;
1238                                         *errp = ss;
1239                                         free_oc(oc);
1240                                         return(NULL);
1241                                 }
1242                                 seen_may = 1;
1243                                 oc->oc_at_oids_may = parse_oids(&ss,code);
1244                                 if ( !oc->oc_at_oids_may ) {
1245                                         *errp = ss;
1246                                         free_oc(oc);
1247                                         return NULL;
1248                                 }
1249                                 parse_whsp(&ss);
1250                         } else {
1251                                 *code = LDAP_SCHERR_UNEXPTOKEN;
1252                                 *errp = ss;
1253                                 free_oc(oc);
1254                                 return NULL;
1255                         }
1256                         break;
1257                 default:
1258                         *code = LDAP_SCHERR_UNEXPTOKEN;
1259                         *errp = ss;
1260                         free_oc(oc);
1261                         return NULL;
1262                 }
1263         }
1264 }
1265
1266 static char *err2text[] = {
1267         "",
1268         "Out of memory",
1269         "Unexpected token",
1270         "Missing opening parenthesis",
1271         "Missing closing parenthesis",
1272         "Expecting digit",
1273         "Expecting a name",
1274         "Bad description",
1275         "Bad superiors",
1276         "Duplicate option",
1277         "Unexpected end of data"
1278 };
1279
1280 char *
1281 ldap_scherr2str(int code)
1282 {
1283         if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
1284                 return "Unknown error";
1285         } else {
1286                 return err2text[code];
1287         }
1288 }