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