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