1 /*        $NetBSD: schemaparse.c,v 1.3 2021/08/14 16:14:58 christos Exp $       */
2 
3 /* schemaparse.c - routines to parse config file objectclass definitions */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2021 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 
19 #include <sys/cdefs.h>
20 __RCSID("$NetBSD: schemaparse.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
21 
22 #include "portable.h"
23 
24 #include <stdio.h>
25 
26 #include <ac/ctype.h>
27 #include <ac/string.h>
28 #include <ac/socket.h>
29 
30 #include "slap.h"
31 #include "ldap_schema.h"
32 #include "slap-config.h"
33 
34 static void                   oc_usage(void);
35 static void                   at_usage(void);
36 
37 static char *const err2text[] = {
38           "Success",
39           "Out of memory",
40           "ObjectClass not found",
41           "user-defined ObjectClass includes operational attributes",
42           "user-defined ObjectClass has inappropriate SUPerior",
43           "Duplicate objectClass",
44           "Inconsistent duplicate objectClass",
45           "AttributeType not found",
46           "AttributeType inappropriate matching rule",
47           "AttributeType inappropriate USAGE",
48           "AttributeType inappropriate SUPerior",
49           "AttributeType SYNTAX or SUPerior required",
50           "Duplicate attributeType",
51           "Inconsistent duplicate attributeType",
52           "MatchingRule not found",
53           "MatchingRule incomplete",
54           "Duplicate matchingRule",
55           "Syntax not found",
56           "Duplicate ldapSyntax",
57           "Superior syntax not found",
58           "Substitute syntax not specified",
59           "Substitute syntax not found",
60           "OID or name required",
61           "Qualifier not supported",
62           "Invalid NAME",
63           "OID could not be expanded",
64           "Duplicate Content Rule",
65           "Content Rule not for STRUCTURAL object class",
66           "Content Rule AUX contains inappropriate object class",
67           "Content Rule attribute type list contains duplicate",
68           NULL
69 };
70 
71 char *
scherr2str(int code)72 scherr2str(int code)
73 {
74           if ( code < 0 || SLAP_SCHERR_LAST <= code ) {
75                     return "Unknown error";
76           } else {
77                     return err2text[code];
78           }
79 }
80 
81 /* check schema descr validity */
slap_valid_descr(const char * descr)82 int slap_valid_descr( const char *descr )
83 {
84           int i=0;
85 
86           if( !DESC_LEADCHAR( descr[i] ) ) {
87                     return 0;
88           }
89 
90           while( descr[++i] ) {
91                     if( !DESC_CHAR( descr[i] ) ) {
92                               return 0;
93                     }
94           }
95 
96           return 1;
97 }
98 
99 
100 /* OID Macros */
101 
102 /* String compare with delimiter check. Return 0 if not
103  * matched, otherwise return length matched.
104  */
105 int
dscompare(const char * s1,const char * s2,char delim)106 dscompare(const char *s1, const char *s2, char delim)
107 {
108           const char *orig = s1;
109           while (*s1++ == *s2++)
110                     if (!s1[-1]) break;
111           --s1;
112           --s2;
113           if (!*s1 && (!*s2 || *s2 == delim))
114                     return s1 - orig;
115           return 0;
116 }
117 
118 static void
cr_usage(void)119 cr_usage( void )
120 {
121           fprintf( stderr,
122                     "DITContentRuleDescription = \"(\" whsp\n"
123                     "  numericoid whsp       ; StructuralObjectClass identifier\n"
124                     "  [ \"NAME\" qdescrs ]\n"
125                     "  [ \"DESC\" qdstring ]\n"
126                     "  [ \"OBSOLETE\" whsp ]\n"
127                     "  [ \"AUX\" oids ]      ; Auxiliary ObjectClasses\n"
128                     "  [ \"MUST\" oids ]     ; AttributeTypes\n"
129                     "  [ \"MAY\" oids ]      ; AttributeTypes\n"
130                     "  [ \"NOT\" oids ]      ; AttributeTypes\n"
131                     "  whsp \")\"\n" );
132 }
133 
134 int
parse_cr(struct config_args_s * c,ContentRule ** scr)135 parse_cr(
136           struct config_args_s *c,
137           ContentRule         **scr )
138 {
139           LDAPContentRule *cr;
140           int                 code;
141           const char          *err;
142           char *line = strchr( c->line, '(' );
143 
144           cr = ldap_str2contentrule( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
145           if ( !cr ) {
146                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
147                               c->argv[0], ldap_scherr2str( code ), err );
148                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
149                               "%s %s\n", c->log, c->cr_msg );
150                     cr_usage();
151                     return 1;
152           }
153 
154           if ( cr->cr_oid == NULL ) {
155                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
156                               c->argv[0] );
157                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
158                               "%s %s\n", c->log, c->cr_msg );
159                     cr_usage();
160                     code = 1;
161                     goto done;
162           }
163 
164           code = cr_add( cr, 1, scr, &err );
165           if ( code ) {
166                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
167                               c->argv[0], scherr2str(code), err);
168                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
169                               "%s %s\n", c->log, c->cr_msg );
170                     code = 1;
171                     goto done;
172           }
173 
174 done:;
175           if ( code ) {
176                     ldap_contentrule_free( cr );
177 
178           } else {
179                     ldap_memfree( cr );
180           }
181 
182           return code;
183 }
184 
185 int
parse_oc(struct config_args_s * c,ObjectClass ** soc,ObjectClass * prev)186 parse_oc(
187           struct config_args_s *c,
188           ObjectClass         **soc,
189           ObjectClass *prev )
190 {
191           LDAPObjectClass *oc;
192           int                 code;
193           const char          *err;
194           char *line = strchr( c->line, '(' );
195 
196           oc = ldap_str2objectclass(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
197           if ( !oc ) {
198                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
199                               c->argv[0], ldap_scherr2str( code ), err );
200                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
201                               "%s %s\n", c->log, c->cr_msg );
202                     oc_usage();
203                     return 1;
204           }
205 
206           if ( oc->oc_oid == NULL ) {
207                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
208                               c->argv[0] );
209                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
210                               "%s %s\n", c->log, c->cr_msg );
211                     oc_usage();
212                     code = 1;
213                     goto done;
214           }
215 
216           code = oc_add( oc, 1, soc, prev, &err );
217           if ( code ) {
218                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
219                               c->argv[0], scherr2str(code), err);
220                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
221                               "%s %s\n", c->log, c->cr_msg );
222                     code = 1;
223                     goto done;
224           }
225 
226 done:;
227           if ( code ) {
228                     ldap_objectclass_free( oc );
229 
230           } else {
231                     ldap_memfree( oc );
232           }
233 
234           return code;
235 }
236 
237 static void
oc_usage(void)238 oc_usage( void )
239 {
240           fprintf( stderr,
241                     "ObjectClassDescription = \"(\" whsp\n"
242                     "  numericoid whsp                 ; ObjectClass identifier\n"
243                     "  [ \"NAME\" qdescrs ]\n"
244                     "  [ \"DESC\" qdstring ]\n"
245                     "  [ \"OBSOLETE\" whsp ]\n"
246                     "  [ \"SUP\" oids ]                ; Superior ObjectClasses\n"
247                     "  [ ( \"ABSTRACT\" / \"STRUCTURAL\" / \"AUXILIARY\" ) whsp ]\n"
248                     "                                  ; default structural\n"
249                     "  [ \"MUST\" oids ]               ; AttributeTypes\n"
250                     "  [ \"MAY\" oids ]                ; AttributeTypes\n"
251                     "  whsp \")\"\n" );
252 }
253 
254 static void
at_usage(void)255 at_usage( void )
256 {
257           fprintf( stderr, "%s%s%s",
258                     "AttributeTypeDescription = \"(\" whsp\n"
259                     "  numericoid whsp      ; AttributeType identifier\n"
260                     "  [ \"NAME\" qdescrs ]             ; name used in AttributeType\n"
261                     "  [ \"DESC\" qdstring ]            ; description\n"
262                     "  [ \"OBSOLETE\" whsp ]\n"
263                     "  [ \"SUP\" woid ]                 ; derived from this other\n"
264                     "                                   ; AttributeType\n",
265                     "  [ \"EQUALITY\" woid ]            ; Matching Rule name\n"
266                     "  [ \"ORDERING\" woid ]            ; Matching Rule name\n"
267                     "  [ \"SUBSTR\" woid ]              ; Matching Rule name\n"
268                     "  [ \"SYNTAX\" whsp noidlen whsp ] ; see section 4.3\n"
269                     "  [ \"SINGLE-VALUE\" whsp ]        ; default multi-valued\n"
270                     "  [ \"COLLECTIVE\" whsp ]          ; default not collective\n",
271                     "  [ \"NO-USER-MODIFICATION\" whsp ]; default user modifiable\n"
272                     "  [ \"USAGE\" whsp AttributeUsage ]; default userApplications\n"
273                     "                                   ; userApplications\n"
274                     "                                   ; directoryOperation\n"
275                     "                                   ; distributedOperation\n"
276                     "                                   ; dSAOperation\n"
277                     "  whsp \")\"\n");
278 }
279 
280 int
parse_at(struct config_args_s * c,AttributeType ** sat,AttributeType * prev)281 parse_at(
282           struct config_args_s *c,
283           AttributeType       **sat,
284           AttributeType       *prev )
285 {
286           LDAPAttributeType *at;
287           int                 code;
288           const char          *err;
289           char *line = strchr( c->line, '(' );
290 
291           at = ldap_str2attributetype( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
292           if ( !at ) {
293                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
294                               c->argv[0], ldap_scherr2str(code), err );
295                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
296                               "%s %s\n", c->log, c->cr_msg );
297                     at_usage();
298                     return 1;
299           }
300 
301           if ( at->at_oid == NULL ) {
302                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
303                               c->argv[0] );
304                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
305                               "%s %s\n", c->log, c->cr_msg );
306                     at_usage();
307                     code = 1;
308                     goto done;
309           }
310 
311           /* operational attributes should be defined internally */
312           if ( at->at_usage ) {
313                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: \"%s\" is operational",
314                               c->argv[0], at->at_oid );
315                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
316                               "%s %s\n", c->log, c->cr_msg );
317                     code = 1;
318                     goto done;
319           }
320 
321           code = at_add( at, 1, sat, prev, &err);
322           if ( code ) {
323                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
324                               c->argv[0], scherr2str(code), err);
325                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
326                               "%s %s\n", c->log, c->cr_msg );
327                     code = 1;
328                     goto done;
329           }
330 
331 done:;
332           if ( code ) {
333                     ldap_attributetype_free( at );
334 
335           } else {
336                     ldap_memfree( at );
337           }
338 
339           return code;
340 }
341 
342 static void
syn_usage(void)343 syn_usage( void )
344 {
345           fprintf( stderr, "%s",
346                     "SyntaxDescription = \"(\" whsp\n"
347                     "  numericoid whsp                  ; object identifier\n"
348                     "  [ whsp \"DESC\" whsp qdstring ]  ; description\n"
349                     "  extensions whsp \")\"            ; extensions\n"
350                     "  whsp \")\"\n");
351 }
352 
353 int
parse_syn(struct config_args_s * c,Syntax ** ssyn,Syntax * prev)354 parse_syn(
355           struct config_args_s *c,
356           Syntax **ssyn,
357           Syntax *prev )
358 {
359           LDAPSyntax                    *syn;
360           slap_syntax_defs_rec          def = { 0 };
361           int                           code;
362           const char                    *err;
363           char                          *line = strchr( c->line, '(' );
364 
365           syn = ldap_str2syntax( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
366           if ( !syn ) {
367                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
368                               c->argv[0], ldap_scherr2str(code), err );
369                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
370                               "%s %s\n", c->log, c->cr_msg );
371                     syn_usage();
372                     return 1;
373           }
374 
375           if ( syn->syn_oid == NULL ) {
376                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
377                               c->argv[0] );
378                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
379                               "%s %s\n", c->log, c->cr_msg );
380                     syn_usage();
381                     code = 1;
382                     goto done;
383           }
384 
385           code = syn_add( syn, 1, &def, ssyn, prev, &err );
386           if ( code ) {
387                     snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
388                               c->argv[0], scherr2str(code), err);
389                     Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
390                               "%s %s\n", c->log, c->cr_msg );
391                     code = 1;
392                     goto done;
393           }
394 
395 done:;
396           if ( code ) {
397                     ldap_syntax_free( syn );
398 
399           } else {
400                     ldap_memfree( syn );
401           }
402 
403           return code;
404 }
405 
406