2 * Copyright 1999 The OpenLDAP Foundation, All Rights Reserved.
3 * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5 * schema.c: parsing routines used by servers and clients to process
12 #include <ac/string.h>
18 #include <ldap_schema.h>
22 * When pretty printing the entities we will be appending to a buffer.
23 * Since checking for overflow, realloc'ing and checking if no error
24 * is extremely boring, we will use a pretection layer that will let
25 * us blissfully ignore the error until the end. This layer is
26 * implemented with the help of the next type.
29 typedef struct safe_string {
37 new_safe_string(int size)
41 ss = malloc(sizeof(safe_string));
46 ss->val = malloc(size);
56 safe_string_free(safe_string * ss)
60 ldap_memfree(ss->val);
65 safe_string_val(safe_string * ss)
71 append_to_safe_string(safe_string * ss, char * s)
77 * Some runaway process is trying to append to a string that
78 * overflowed and we could not extend.
83 /* We always make sure there is at least one position available */
84 if ( ss->pos + l >= ss->size-1 ) {
86 temp = realloc(ss->val, ss->size);
88 /* Trouble, out of memory */
94 strncpy(&ss->val[ss->pos], s, l);
96 if ( ss->pos > 0 && ss->val[ss->pos-1] == ' ' )
105 print_literal(safe_string *ss, char *s)
107 return(append_to_safe_string(ss,s));
111 print_whsp(safe_string *ss)
114 return(append_to_safe_string(ss,""));
116 return(append_to_safe_string(ss," "));
120 print_numericoid(safe_string *ss, char *s)
122 return(append_to_safe_string(ss,s));
125 /* This one is identical to print_qdescr */
127 print_qdstring(safe_string *ss, char *s)
130 print_literal(ss,"'");
131 append_to_safe_string(ss,s);
132 print_literal(ss,"'");
133 return(print_whsp(ss));
137 print_qdescr(safe_string *ss, char *s)
140 print_literal(ss,"'");
141 append_to_safe_string(ss,s);
142 print_literal(ss,"'");
143 return(print_whsp(ss));
147 print_qdescrlist(safe_string *ss, char **sa)
152 for (sp=sa; *sp; sp++) {
153 ret = print_qdescr(ss,*sp);
155 /* If the list was empty, we return zero that is potentially
156 * incorrect, but since we will still appending things, the
157 * overflow will be detected later. Maybe FIX.
163 print_qdescrs(safe_string *ss, char **sa)
165 /* The only way to represent an empty list is as a qdescrlist
166 * so, if the list is empty we treat it as a long list.
167 * Really, this is what the syntax mandates.
169 if ( !sa[0] || ( sa[0] && sa[1] ) ) {
171 print_literal(ss,"(");
172 print_qdescrlist(ss,sa);
173 print_literal(ss,")");
174 return(print_whsp(ss));
176 return(print_qdescr(ss,*sa));
181 print_woid(safe_string *ss, char *s)
184 append_to_safe_string(ss,s);
185 return print_whsp(ss);
189 print_oidlist(safe_string *ss, char **sa)
193 for (sp=sa; *(sp+1); sp++) {
195 print_literal(ss,"$");
197 return(print_woid(ss,*sp));
201 print_oids(safe_string *ss, char **sa)
203 if ( sa[0] && sa[1] ) {
204 print_literal(ss,"(");
205 print_oidlist(ss,sa);
207 return(print_literal(ss,")"));
209 return(print_woid(ss,*sa));
214 print_noidlen(safe_string *ss, char *s, int l)
219 ret = print_numericoid(ss,s);
221 sprintf(buf,"{%d}",l);
222 ret = print_literal(ss,buf);
228 ldap_objectclass2str( LDAP_OBJECT_CLASS * oc )
233 ss = new_safe_string(256);
237 print_literal(ss,"(");
240 print_numericoid(ss, oc->oc_oid);
243 if ( oc->oc_names ) {
244 print_literal(ss,"NAME");
245 print_qdescrs(ss,oc->oc_names);
249 print_literal(ss,"DESC");
250 print_qdstring(ss,oc->oc_desc);
253 if ( oc->oc_obsolete ) {
254 print_literal(ss, "OBSOLETE");
258 if ( oc->oc_sup_oids ) {
259 print_literal(ss,"SUP");
260 print_oids(ss,oc->oc_sup_oids);
263 switch (oc->oc_kind) {
265 print_literal(ss,"ABSTRACT");
268 print_literal(ss,"STRUCTURAL");
271 print_literal(ss,"AUXILIARY");
274 print_literal(ss,"KIND-UNKNOWN");
279 if ( oc->oc_at_oids_must ) {
280 print_literal(ss,"MUST");
282 print_oids(ss,oc->oc_at_oids_must);
286 if ( oc->oc_at_oids_may ) {
287 print_literal(ss,"MAY");
289 print_oids(ss,oc->oc_at_oids_may);
294 print_literal(ss,")");
296 retstring = safe_string_val(ss);
297 safe_string_free(ss);
302 ldap_attributetype2str( LDAP_ATTRIBUTE_TYPE * at )
307 ss = new_safe_string(256);
311 print_literal(ss,"(");
314 print_numericoid(ss, at->at_oid);
317 if ( at->at_names ) {
318 print_literal(ss,"NAME");
319 print_qdescrs(ss,at->at_names);
323 print_literal(ss,"DESC");
324 print_qdstring(ss,at->at_desc);
327 if ( at->at_obsolete ) {
328 print_literal(ss, "OBSOLETE");
332 if ( at->at_sup_oid ) {
333 print_literal(ss,"SUP");
334 print_woid(ss,at->at_sup_oid);
337 if ( at->at_equality_oid ) {
338 print_literal(ss,"EQUALITY");
339 print_woid(ss,at->at_equality_oid);
342 if ( at->at_ordering_oid ) {
343 print_literal(ss,"ORDERING");
344 print_woid(ss,at->at_ordering_oid);
347 if ( at->at_substr_oid ) {
348 print_literal(ss,"SUBSTR");
349 print_woid(ss,at->at_substr_oid);
352 if ( at->at_syntax_oid ) {
353 print_literal(ss,"SYNTAX");
354 print_noidlen(ss,at->at_syntax_oid,at->at_syntax_len);
357 if ( at->at_single_value ) {
358 print_literal(ss,"SINGLE-VALUE");
362 if ( at->at_collective ) {
363 print_literal(ss,"COLLECTIVE");
367 if ( at->at_no_user_mod ) {
368 print_literal(ss,"NO-USER-MODIFICATION");
372 if ( at->at_usage ) {
373 print_literal(ss,"USAGE");
375 switch (at->at_usage) {
377 print_literal(ss,"directoryOperation");
380 print_literal(ss,"distributedOperation");
383 print_literal(ss,"dSAOperation");
386 print_literal(ss,"UNKNOWN");
392 print_literal(ss,")");
394 retstring = safe_string_val(ss);
395 safe_string_free(ss);
400 * This is ripped from servers/slapd/charray.c that should be promoted
401 * to -lldap or something so that it is used everywhere.
404 charray_free( char **array )
408 if ( array == NULL ) {
412 for ( a = array; *a != NULL; a++ ) {
417 free( (char *) array );
420 #define TK_NOENDQUOTE -2
421 #define TK_OUTOFMEM -1
423 #define TK_UNEXPCHAR 1
424 #define TK_BAREWORD 2
425 #define TK_QDSTRING 3
426 #define TK_LEFTPAREN 4
427 #define TK_RIGHTPAREN 5
429 #define TK_QDESCR TK_QDSTRING
437 get_token(char ** sp, char ** token_val)
454 kind = TK_RIGHTPAREN;
465 while ( **sp != '\'' && **sp != '\0' )
467 if ( **sp == '\'' ) {
479 kind = TK_NOENDQUOTE;
485 while ( !isspace(**sp) && **sp != '\0' )
497 /* kind = TK_UNEXPCHAR; */
504 /* Gobble optional whitespace */
506 parse_whsp(char **sp)
508 while (isspace(**sp))
513 * General note for all parsers: to guarantee the algorithm halts they
514 * must always advance the pointer even when an error is found. For
515 * this one is not that important since an error here is fatal at the
516 * upper layers, but it is a simple strategy that will not get in
520 /* Parse a sequence of dot-separated decimal strings */
522 parse_numericoid(char **sp, int *code)
528 /* Each iteration of this loops gets one decimal string */
530 if ( !isdigit(**sp) ) {
531 /* Initial char is not a digit or char after dot is not a digit */
532 *code = SCHEMA_ERR_NODIGIT;
536 while ( isdigit(**sp) )
540 /* Otherwise, gobble the dot and loop again */
543 /* At this point, *sp points at the char past the numericoid. Perfect. */
547 *code = SCHEMA_ERR_OUTOFMEM;
550 strncpy(res,start,len);
555 /* Parse a qdescr or a list of them enclosed in () */
557 parse_qdescrs(char **sp, int *code)
567 kind = get_token(sp,&sval);
568 if ( kind == TK_LEFTPAREN ) {
569 /* Let's presume there will be at least 2 entries */
571 res = calloc(3,sizeof(char *));
573 *code = SCHEMA_ERR_OUTOFMEM;
579 kind = get_token(sp,&sval);
580 if ( kind == TK_RIGHTPAREN )
582 if ( kind == TK_QDESCR ) {
583 if ( pos == size-2 ) {
585 res1 = realloc(res,size*sizeof(char *));
588 *code = SCHEMA_ERR_OUTOFMEM;
598 *code = SCHEMA_ERR_UNEXPTOKEN;
605 } else if ( kind == TK_QDESCR ) {
606 res = calloc(2,sizeof(char *));
608 *code = SCHEMA_ERR_OUTOFMEM;
616 *code = SCHEMA_ERR_BADNAME;
621 /* Parse a woid or a $-separated list of them enclosed in () */
623 parse_oids(char **sp, int *code)
633 * Strictly speaking, doing this here accepts whsp before the
634 * ( at the begining of an oidlist, but his is harmless. Also,
635 * we are very liberal in what we accept as an OID. Maybe
639 kind = get_token(sp,&sval);
640 if ( kind == TK_LEFTPAREN ) {
641 /* Let's presume there will be at least 2 entries */
643 res = calloc(3,sizeof(char *));
645 *code = SCHEMA_ERR_OUTOFMEM;
650 kind = get_token(sp,&sval);
651 if ( kind == TK_BAREWORD ) {
655 *code = SCHEMA_ERR_UNEXPTOKEN;
661 kind = get_token(sp,&sval);
662 if ( kind == TK_RIGHTPAREN )
664 if ( kind == TK_DOLLAR ) {
666 kind = get_token(sp,&sval);
667 if ( kind == TK_BAREWORD ) {
668 if ( pos == size-2 ) {
670 res1 = realloc(res,size*sizeof(char *));
673 *code = SCHEMA_ERR_OUTOFMEM;
681 *code = SCHEMA_ERR_UNEXPTOKEN;
687 *code = SCHEMA_ERR_UNEXPTOKEN;
695 } else if ( kind == TK_BAREWORD ) {
696 res = calloc(2,sizeof(char *));
698 *code = SCHEMA_ERR_OUTOFMEM;
706 *code = SCHEMA_ERR_BADNAME;
712 free_oc(LDAP_OBJECT_CLASS * oc)
714 ldap_memfree(oc->oc_oid);
715 charray_free(oc->oc_names);
716 ldap_memfree(oc->oc_desc);
717 charray_free(oc->oc_sup_oids);
718 charray_free(oc->oc_at_oids_must);
719 charray_free(oc->oc_at_oids_may);
724 ldap_str2objectclass( char * s, int * code, char ** errp )
731 int seen_obsolete = 0;
736 LDAP_OBJECT_CLASS * oc;
739 oc = calloc(1,sizeof(LDAP_OBJECT_CLASS));
742 *code = SCHEMA_ERR_OUTOFMEM;
746 kind = get_token(&ss,&sval);
747 if ( kind != TK_LEFTPAREN ) {
748 *code = SCHEMA_ERR_NOLEFTPAREN;
754 oc->oc_oid = parse_numericoid(&ss,code);
763 * Beyond this point we will be liberal an accept the items
767 kind = get_token(&ss,&sval);
770 *code = SCHEMA_ERR_NORIGHTPAREN;
777 if ( !strcmp(sval,"NAME") ) {
779 *code = SCHEMA_ERR_DUPOPT;
785 oc->oc_names = parse_qdescrs(&ss,code);
786 if ( !oc->oc_names ) {
787 if ( *code != SCHEMA_ERR_OUTOFMEM )
788 *code = SCHEMA_ERR_BADNAME;
793 } else if ( !strcmp(sval,"DESC") ) {
795 *code = SCHEMA_ERR_DUPOPT;
802 kind = get_token(&ss,&sval);
803 if ( kind != TK_QDSTRING ) {
804 *code = SCHEMA_ERR_UNEXPTOKEN;
811 } else if ( !strcmp(sval,"OBSOLETE") ) {
812 if ( seen_obsolete ) {
813 *code = SCHEMA_ERR_DUPOPT;
821 } else if ( !strcmp(sval,"SUP") ) {
823 *code = SCHEMA_ERR_DUPOPT;
829 /* Netscape DS is broken or I have not
830 understood the syntax. */
831 /* oc->oc_sup_oids = parse_oids(&ss,code); */
832 oc->oc_sup_oids = parse_qdescrs(&ss,code);
833 if ( !oc->oc_sup_oids ) {
838 } else if ( !strcmp(sval,"ABSTRACT") ) {
840 *code = SCHEMA_ERR_DUPOPT;
848 } else if ( !strcmp(sval,"STRUCTURAL") ) {
850 *code = SCHEMA_ERR_DUPOPT;
858 } else if ( !strcmp(sval,"AUXILIARY") ) {
860 *code = SCHEMA_ERR_DUPOPT;
868 } else if ( !strcmp(sval,"MUST") ) {
870 *code = SCHEMA_ERR_DUPOPT;
876 oc->oc_at_oids_must = parse_oids(&ss,code);
877 if ( !oc->oc_at_oids_must ) {
883 } else if ( !strcmp(sval,"MAY") ) {
885 *code = SCHEMA_ERR_DUPOPT;
891 oc->oc_at_oids_may = parse_oids(&ss,code);
892 if ( !oc->oc_at_oids_may ) {
899 *code = SCHEMA_ERR_UNEXPTOKEN;
906 *code = SCHEMA_ERR_UNEXPTOKEN;