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