3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2004-2018 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
19 #include <ac/string.h>
21 #include <ac/signal.h>
23 #include <ac/stdlib.h>
26 #include <ac/unistd.h>
31 * Schema reader that allows us to define DSA schema (including
32 * operational attributes and non-user object classes)
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...
41 #include <ldap_schema.h>
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);
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 );
54 static char **cargv = NULL;
55 static int cargv_size = 0;
57 static char *strtok_quote_ptr;
59 int init_module(int argc, char *argv[]);
61 static int dsaschema_parse_at(const char *fname, int lineno, char *line, char **argv)
63 LDAPAttributeType *at;
67 at = ldap_str2attributetype(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
69 fprintf(stderr, "%s: line %d: %s before %s\n",
70 fname, lineno, ldap_scherr2str(code), err);
74 if (at->at_oid == NULL) {
75 fprintf(stderr, "%s: line %d: attributeType has no OID\n",
80 code = at_add(at, &err);
82 fprintf(stderr, "%s: line %d: %s: \"%s\"\n",
83 fname, lineno, ldap_scherr2str(code), err);
92 static int dsaschema_parse_oc(const char *fname, int lineno, char *line, char **argv)
98 oc = ldap_str2objectclass(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
100 fprintf(stderr, "%s: line %d: %s before %s\n",
101 fname, lineno, ldap_scherr2str(code), err);
105 if (oc->oc_oid == NULL) {
107 "%s: line %d: objectclass has no OID\n",
112 code = oc_add(oc, 0, &err);
114 fprintf(stderr, "%s: line %d: %s: \"%s\"\n",
115 fname, lineno, ldap_scherr2str(code), err);
123 static int dsaschema_parse_cr(const char *fname, int lineno, char *line, char **argv)
129 cr = ldap_str2contentrule(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
131 fprintf(stderr, "%s: line %d: %s before %s\n",
132 fname, lineno, ldap_scherr2str(code), err);
136 if (cr->cr_oid == NULL) {
138 "%s: line %d: objectclass has no OID\n",
143 code = cr_add(cr, 0, &err);
145 fprintf(stderr, "%s: line %d: %s: \"%s\"\n",
146 fname, lineno, ldap_scherr2str(code), err);
154 static int dsaschema_read_config(const char *fname, int depth)
157 char *line, *savefname, *saveline;
158 int savelineno, lineno;
162 cargv = calloc(ARGS_STEP + 1, sizeof(*cargv));
166 cargv_size = ARGS_STEP + 1;
169 fp = fopen(fname, "r");
171 fprintf(stderr, "could not open config file \"%s\": %s (%d)\n",
172 fname, strerror(errno), errno);
175 fp_getline_init(&lineno);
177 while ((line = fp_getline(fp, &lineno)) != NULL) {
178 /* skip comments and blank lines */
179 if (line[0] == '#' || line[0] == '\0') {
183 saveline = strdup(line);
184 if (saveline == NULL) {
188 if (fp_parse_line(lineno, line) != 0) {
196 if (strcasecmp(cargv[0], "attributetype") == 0 ||
197 strcasecmp(cargv[0], "attribute") == 0) {
199 fprintf(stderr, "%s: line %d: illegal attribute type format\n",
202 } else if (*cargv[1] == '(' /*')'*/) {
205 p = strchr(saveline, '(' /*')'*/);
206 rc = dsaschema_parse_at(fname, lineno, p, cargv);
210 fprintf(stderr, "%s: line %d: old attribute type format not supported\n",
213 } else if (strcasecmp(cargv[0], "ditcontentrule") == 0) {
215 p = strchr(saveline, '(' /*')'*/);
216 rc = dsaschema_parse_cr(fname, lineno, p, cargv);
219 } else if (strcasecmp(cargv[0], "objectclass") == 0) {
221 fprintf(stderr, "%s: line %d: illegal objectclass format\n",
224 } else if (*cargv[1] == '(' /*')'*/) {
227 p = strchr(saveline, '(' /*')'*/);
228 rc = dsaschema_parse_oc(fname, lineno, p, cargv);
232 fprintf(stderr, "%s: line %d: object class format not supported\n",
235 } else if (strcasecmp(cargv[0], "include") == 0) {
237 fprintf(stderr, "%s: line %d: missing file name in \"include <filename>\" line",
241 savefname = strdup(cargv[1]);
242 if (savefname == NULL) {
245 if (dsaschema_read_config(savefname, depth + 1) != 0) {
249 lineno = savelineno - 1;
251 fprintf(stderr, "%s: line %d: unknown directive \"%s\" (ignored)\n",
252 fname, lineno, cargv[0]);
264 int init_module(int argc, char *argv[])
269 for (i = 0; i < argc; i++) {
270 rc = dsaschema_read_config(argv[i], 0);
289 token = strtok_quote( line, " \t" );
291 if ( strtok_quote_ptr ) {
292 *strtok_quote_ptr = ' ';
295 if ( strtok_quote_ptr ) {
296 *strtok_quote_ptr = '\0';
299 for ( ; token != NULL; token = strtok_quote( NULL, " \t" ) ) {
300 if ( cargc == cargv_size - 1 ) {
302 tmp = realloc( cargv, (cargv_size + ARGS_STEP) *
308 cargv_size += ARGS_STEP;
310 cargv[cargc++] = token;
317 strtok_quote( char *line, char *sep )
323 strtok_quote_ptr = NULL;
324 if ( line != NULL ) {
327 while ( *next && strchr( sep, *next ) ) {
331 if ( *next == '\0' ) {
337 for ( inquote = 0; *next; ) {
345 AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
351 next + 1, strlen( next + 1 ) + 1 );
352 next++; /* dont parse the escaped character */
357 if ( strchr( sep, *next ) != NULL ) {
358 strtok_quote_ptr = next;
371 static char buf[BUFSIZ];
373 static size_t lmax, lcur;
375 #define CATLINE( buf ) \
377 size_t len = strlen( buf ); \
378 while ( lcur + len + 1 > lmax ) { \
380 line = (char *) realloc( line, lmax ); \
382 strcpy( line + lcur, buf ); \
387 fp_getline( FILE *fp, int *lineno )
395 /* hack attack - keeps us from having to keep a stack of bufs... */
396 if ( strncasecmp( line, "include", 7 ) == 0 ) {
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;
408 /* trim off trailing \ and append the next line */
409 if ( line[ 0 ] != '\0'
410 && (p = line + strlen( line ) - 1)[ 0 ] == '\\'
411 && p[ -1 ] != '\\' ) {
416 if ( ! isspace( (unsigned char) buf[0] ) ) {
420 /* change leading whitespace to a space */
429 return( line[0] ? line : NULL );
433 fp_getline_init( int *lineno )