1 /* dsaschema.c */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 2004-2021 The OpenLDAP Foundation.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
10 * Public License.
11 *
12 * A copy of this license is available in the file LICENSE in the
13 * top-level directory of the distribution or, alternatively, at
14 * <http://www.OpenLDAP.org/license.html>.
15 */
16
17 #include <portable.h>
18
19 #include <ac/string.h>
20 #include <ac/ctype.h>
21 #include <ac/signal.h>
22 #include <ac/errno.h>
23 #include <ac/stdlib.h>
24 #include <ac/ctype.h>
25 #include <ac/time.h>
26 #include <ac/unistd.h>
27
28 #include <stdio.h>
29
30 /*
31 * Schema reader that allows us to define DSA schema (including
32 * operational attributes and non-user object classes)
33 *
34 * A kludge, at best, and in order to avoid including slapd
35 * headers we use fprintf() rather than slapd's native logging,
36 * which may confuse users...
37 *
38 */
39
40 #include <ldap.h>
41 #include <ldap_schema.h>
42
43 #include <slap.h>
44 #include <slap-config.h>
45
46 #define ARGS_STEP 512
47
48 static char *fp_getline(FILE *fp, int *lineno);
49 static void fp_getline_init(int *lineno);
50 static int fp_parse_line(int lineno, char *line);
51 static char *strtok_quote( char *line, char *sep );
52
53 static char **cargv = NULL;
54 static int cargv_size = 0;
55 static int cargc = 0;
56 static char *strtok_quote_ptr;
57
58 int init_module(int argc, char *argv[]);
59
dsaschema_parse_cr(const char * fname,int lineno,char * line,char ** argv)60 static int dsaschema_parse_cr(const char *fname, int lineno, char *line, char **argv)
61 {
62 struct config_args_s c = { .line = line };
63
64 if ( parse_cr( &c, NULL ) ) {
65 Debug( LDAP_DEBUG_ANY, "dsaschema_parse_cr: "
66 "ditcontentrule definition invalid at %s:%d\n",
67 fname, lineno );
68 return 1;
69 }
70
71 return 0;
72 }
73
dsaschema_read_config(const char * fname,int depth)74 static int dsaschema_read_config(const char *fname, int depth)
75 {
76 FILE *fp;
77 char *line, *savefname, *saveline = NULL;
78 int savelineno, lineno;
79 int rc;
80
81 if (depth == 0) {
82 cargv = ch_calloc(ARGS_STEP + 1, sizeof(*cargv));
83 cargv_size = ARGS_STEP + 1;
84 }
85
86 fp = fopen(fname, "r");
87 if (fp == NULL) {
88 char ebuf[128];
89 int saved_errno = errno;
90 fprintf(stderr, "could not open config file \"%s\": %s (%d)\n",
91 fname, AC_STRERROR_R(saved_errno, ebuf, sizeof(ebuf)), saved_errno);
92 return 1;
93 }
94 fp_getline_init(&lineno);
95
96 while ((line = fp_getline(fp, &lineno)) != NULL) {
97 /* skip comments and blank lines */
98 if (line[0] == '#' || line[0] == '\0') {
99 continue;
100 }
101
102 saveline = ch_strdup(line);
103
104 if (fp_parse_line(lineno, line) != 0) {
105 rc = 1;
106 break;
107 }
108
109 if (cargc < 1) {
110 continue;
111 }
112
113 if (strcasecmp(cargv[0], "attributetype") == 0 ||
114 strcasecmp(cargv[0], "attribute") == 0) {
115 if (cargc < 2) {
116 fprintf(stderr, "%s: line %d: illegal attribute type format\n",
117 fname, lineno);
118 rc = 1;
119 break;
120 } else if (*cargv[1] == '(' /*')'*/) {
121 char *p;
122
123 p = strchr(saveline, '(' /*')'*/);
124 rc = register_at(p, NULL, 0);
125 if (rc != 0) {
126 Debug( LDAP_DEBUG_ANY, "dsaschema_read_config: "
127 "attribute definition invalid at %s:%d\n",
128 fname, lineno );
129 break;
130 }
131 } else {
132 fprintf(stderr, "%s: line %d: old attribute type format not supported\n",
133 fname, lineno);
134 }
135 } else if (strcasecmp(cargv[0], "ditcontentrule") == 0) {
136 char *p;
137 p = strchr(saveline, '(' /*')'*/);
138 rc = dsaschema_parse_cr(fname, lineno, p, cargv);
139 if (rc != 0)
140 break;
141 } else if (strcasecmp(cargv[0], "objectclass") == 0) {
142 if (cargc < 2) {
143 fprintf(stderr, "%s: line %d: illegal objectclass format\n",
144 fname, lineno);
145 rc = 1;
146 break;
147 } else if (*cargv[1] == '(' /*')'*/) {
148 char *p;
149
150 p = strchr(saveline, '(' /*')'*/);
151 rc = register_oc(p, NULL, 0);
152 if (rc != 0) {
153 Debug( LDAP_DEBUG_ANY, "dsaschema_read_config: "
154 "objectclass definition invalid at %s:%d\n",
155 fname, lineno );
156 break;
157 }
158 } else {
159 fprintf(stderr, "%s: line %d: object class format not supported\n",
160 fname, lineno);
161 }
162 } else if (strcasecmp(cargv[0], "include") == 0) {
163 if (cargc < 2) {
164 fprintf(stderr, "%s: line %d: missing file name in \"include <filename>\" line",
165 fname, lineno);
166 rc = 1;
167 break;
168 }
169 savelineno = lineno;
170 savefname = ch_strdup(cargv[1]);
171
172 rc = dsaschema_read_config(savefname, depth + 1);
173 ch_free(savefname);
174 lineno = savelineno - 1;
175 if (rc != 0) {
176 break;
177 }
178 } else {
179 fprintf(stderr, "%s: line %d: unknown directive \"%s\" (ignored)\n",
180 fname, lineno, cargv[0]);
181 }
182
183 ch_free(saveline);
184 saveline = NULL;
185 }
186
187 fclose(fp);
188
189 if (depth == 0)
190 ch_free(cargv);
191
192 if (saveline != NULL)
193 ch_free(saveline);
194
195 return rc;
196 }
197
init_module(int argc,char * argv[])198 int init_module(int argc, char *argv[])
199 {
200 int i;
201 int rc;
202
203 for (i = 0; i < argc; i++) {
204 rc = dsaschema_read_config(argv[i], 0);
205 if (rc != 0) {
206 break;
207 }
208 }
209
210 return rc;
211 }
212
213
214 static int
fp_parse_line(int lineno,char * line)215 fp_parse_line(
216 int lineno,
217 char *line
218 )
219 {
220 char * token;
221
222 cargc = 0;
223 token = strtok_quote( line, " \t" );
224
225 if ( strtok_quote_ptr ) {
226 *strtok_quote_ptr = ' ';
227 }
228
229 if ( strtok_quote_ptr ) {
230 *strtok_quote_ptr = '\0';
231 }
232
233 for ( ; token != NULL; token = strtok_quote( NULL, " \t" ) ) {
234 if ( cargc == cargv_size - 1 ) {
235 char **tmp;
236 tmp = ch_realloc( cargv, (cargv_size + ARGS_STEP) *
237 sizeof(*cargv) );
238 cargv = tmp;
239 cargv_size += ARGS_STEP;
240 }
241 cargv[cargc++] = token;
242 }
243 cargv[cargc] = NULL;
244 return 0;
245 }
246
247 static char *
strtok_quote(char * line,char * sep)248 strtok_quote( char *line, char *sep )
249 {
250 int inquote;
251 char *tmp;
252 static char *next;
253
254 strtok_quote_ptr = NULL;
255 if ( line != NULL ) {
256 next = line;
257 }
258 while ( *next && strchr( sep, *next ) ) {
259 next++;
260 }
261
262 if ( *next == '\0' ) {
263 next = NULL;
264 return( NULL );
265 }
266 tmp = next;
267
268 for ( inquote = 0; *next; ) {
269 switch ( *next ) {
270 case '"':
271 if ( inquote ) {
272 inquote = 0;
273 } else {
274 inquote = 1;
275 }
276 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
277 break;
278
279 case '\\':
280 if ( next[1] )
281 AC_MEMCPY( next,
282 next + 1, strlen( next + 1 ) + 1 );
283 next++; /* dont parse the escaped character */
284 break;
285
286 default:
287 if ( ! inquote ) {
288 if ( strchr( sep, *next ) != NULL ) {
289 strtok_quote_ptr = next;
290 *next++ = '\0';
291 return( tmp );
292 }
293 }
294 next++;
295 break;
296 }
297 }
298
299 return( tmp );
300 }
301
302 static char buf[BUFSIZ];
303 static char *line;
304 static size_t lmax, lcur;
305
306 #define CATLINE( buf ) \
307 do { \
308 size_t len = strlen( buf ); \
309 while ( lcur + len + 1 > lmax ) { \
310 lmax += BUFSIZ; \
311 line = (char *) ch_realloc( line, lmax ); \
312 } \
313 strcpy( line + lcur, buf ); \
314 lcur += len; \
315 } while( 0 )
316
317 static char *
fp_getline(FILE * fp,int * lineno)318 fp_getline( FILE *fp, int *lineno )
319 {
320 char *p;
321
322 lcur = 0;
323 CATLINE( buf );
324 (*lineno)++;
325
326 /* hack attack - keeps us from having to keep a stack of bufs... */
327 if ( strncasecmp( line, "include", 7 ) == 0 ) {
328 buf[0] = '\0';
329 return( line );
330 }
331
332 while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
333 /* trim off \r\n or \n */
334 if ( (p = strchr( buf, '\n' )) != NULL ) {
335 if( p > buf && p[-1] == '\r' ) --p;
336 *p = '\0';
337 }
338
339 /* trim off trailing \ and append the next line */
340 if ( line[ 0 ] != '\0'
341 && (p = line + strlen( line ) - 1)[ 0 ] == '\\'
342 && p[ -1 ] != '\\' ) {
343 p[ 0 ] = '\0';
344 lcur--;
345
346 } else {
347 if ( ! isspace( (unsigned char) buf[0] ) ) {
348 return( line );
349 }
350
351 /* change leading whitespace to a space */
352 buf[0] = ' ';
353 }
354
355 CATLINE( buf );
356 (*lineno)++;
357 }
358 buf[0] = '\0';
359
360 return( line[0] ? line : NULL );
361 }
362
363 static void
fp_getline_init(int * lineno)364 fp_getline_init( int *lineno )
365 {
366 *lineno = -1;
367 buf[0] = '\0';
368 }
369
370