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