Back to index

openldap  2.4.31
dsaschema.c
Go to the documentation of this file.
00001 /* dsaschema.c */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2004-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 
00017 #include <portable.h>
00018 
00019 #include <ac/string.h>
00020 #include <ac/ctype.h>
00021 #include <ac/signal.h>
00022 #include <ac/errno.h>
00023 #include <ac/stdlib.h>
00024 #include <ac/ctype.h>
00025 #include <ac/time.h>
00026 #include <ac/unistd.h>
00027 
00028 #include <stdio.h>
00029 
00030 /*
00031  * Schema reader that allows us to define DSA schema (including
00032  * operational attributes and non-user object classes)
00033  *
00034  * A kludge, at best, and in order to avoid including slapd
00035  * headers we use fprintf() rather than slapd's native logging,
00036  * which may confuse users...
00037  *
00038  */
00039 
00040 #include <ldap.h>
00041 #include <ldap_schema.h>
00042 
00043 extern int at_add(LDAPAttributeType *at, const char **err);
00044 extern int oc_add(LDAPObjectClass *oc, int user, const char **err);
00045 extern int cr_add(LDAPContentRule *cr, int user, const char **err);
00046 
00047 #define ARGS_STEP 512
00048 
00049 static char *fp_getline(FILE *fp, int *lineno);
00050 static void fp_getline_init(int *lineno);
00051 static int fp_parse_line(int lineno, char *line);
00052 static char *strtok_quote( char *line, char *sep );
00053 
00054 static char **cargv = NULL;
00055 static int cargv_size = 0;
00056 static int cargc = 0;
00057 static char *strtok_quote_ptr;
00058 
00059 int init_module(int argc, char *argv[]);
00060 
00061 static int dsaschema_parse_at(const char *fname, int lineno, char *line, char **argv)
00062 {
00063        LDAPAttributeType *at;
00064        int code;
00065        const char *err;
00066 
00067        at = ldap_str2attributetype(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
00068        if (!at) {
00069               fprintf(stderr, "%s: line %d: %s before %s\n",
00070                      fname, lineno, ldap_scherr2str(code), err);
00071               return 1;
00072        }
00073 
00074        if (at->at_oid == NULL) {
00075               fprintf(stderr, "%s: line %d: attributeType has no OID\n",
00076                      fname, lineno);
00077               return 1;
00078        }
00079 
00080        code = at_add(at, &err);
00081        if (code) {
00082               fprintf(stderr, "%s: line %d: %s: \"%s\"\n",
00083                      fname, lineno, ldap_scherr2str(code), err);
00084               return 1;
00085        }
00086 
00087        ldap_memfree(at);
00088 
00089        return 0;
00090 }
00091 
00092 static int dsaschema_parse_oc(const char *fname, int lineno, char *line, char **argv)
00093 {
00094        LDAPObjectClass *oc;
00095        int code;
00096        const char *err;
00097 
00098        oc = ldap_str2objectclass(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
00099        if (!oc) {
00100               fprintf(stderr, "%s: line %d: %s before %s\n",
00101                      fname, lineno, ldap_scherr2str(code), err);
00102               return 1;
00103        }
00104 
00105        if (oc->oc_oid == NULL) {
00106               fprintf(stderr,
00107                      "%s: line %d: objectclass has no OID\n",
00108                      fname, lineno);
00109               return 1;
00110        }
00111 
00112        code = oc_add(oc, 0, &err);
00113        if (code) {
00114               fprintf(stderr, "%s: line %d: %s: \"%s\"\n",
00115                      fname, lineno, ldap_scherr2str(code), err);
00116               return 1;
00117        }
00118 
00119        ldap_memfree(oc);
00120        return 0;
00121 }
00122 
00123 static int dsaschema_parse_cr(const char *fname, int lineno, char *line, char **argv)
00124 {
00125        LDAPContentRule *cr;
00126        int code;
00127        const char *err;
00128 
00129        cr = ldap_str2contentrule(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL);
00130        if (!cr) {
00131               fprintf(stderr, "%s: line %d: %s before %s\n",
00132                      fname, lineno, ldap_scherr2str(code), err);
00133               return 1;
00134        }
00135 
00136        if (cr->cr_oid == NULL) {
00137               fprintf(stderr,
00138                      "%s: line %d: objectclass has no OID\n",
00139                      fname, lineno);
00140               return 1;
00141        }
00142 
00143        code = cr_add(cr, 0, &err);
00144        if (code) {
00145               fprintf(stderr, "%s: line %d: %s: \"%s\"\n",
00146                      fname, lineno, ldap_scherr2str(code), err);
00147               return 1;
00148        }
00149 
00150        ldap_memfree(cr);
00151        return 0;
00152 }
00153 
00154 static int dsaschema_read_config(const char *fname, int depth)
00155 {
00156        FILE *fp;
00157        char *line, *savefname, *saveline;
00158        int savelineno, lineno;
00159        int rc;
00160 
00161        if (depth == 0) {
00162               cargv = calloc(ARGS_STEP + 1, sizeof(*cargv));
00163               if (cargv == NULL) {
00164                      return 1;
00165               }
00166               cargv_size = ARGS_STEP + 1;
00167        }
00168 
00169        fp = fopen(fname, "r");
00170        if (fp == NULL) {
00171               fprintf(stderr, "could not open config file \"%s\": %s (%d)\n",
00172                      fname, strerror(errno), errno);
00173               return 1;
00174        }
00175        fp_getline_init(&lineno);
00176 
00177        while ((line = fp_getline(fp, &lineno)) != NULL) {
00178               /* skip comments and blank lines */
00179               if (line[0] == '#' || line[0] == '\0') {
00180                      continue;
00181               }
00182 
00183               saveline = strdup(line);
00184               if (saveline == NULL) {
00185                      return 1;
00186               }
00187 
00188               if (fp_parse_line(lineno, line) != 0) {
00189                      return 1;
00190               }
00191 
00192               if (cargc < 1) {
00193                      continue;
00194               }
00195 
00196               if (strcasecmp(cargv[0], "attributetype") == 0 ||
00197                   strcasecmp(cargv[0], "attribute") == 0) {
00198                      if (cargc < 2) {
00199                             fprintf(stderr, "%s: line %d: illegal attribute type format\n",
00200                                    fname, lineno);
00201                             return 1;
00202                      } else if (*cargv[1] == '(' /*')'*/) {
00203                             char *p;
00204        
00205                             p = strchr(saveline, '(' /*')'*/);
00206                             rc = dsaschema_parse_at(fname, lineno, p, cargv);
00207                             if (rc != 0)
00208                                    return rc;
00209                      } else {
00210                             fprintf(stderr, "%s: line %d: old attribute type format not supported\n",
00211                                    fname, lineno);
00212                      }
00213               } else if (strcasecmp(cargv[0], "ditcontentrule") == 0) {
00214                      char *p;
00215                      p = strchr(saveline, '(' /*')'*/);
00216                      rc = dsaschema_parse_cr(fname, lineno, p, cargv);
00217                      if (rc != 0)
00218                             return rc;
00219               } else if (strcasecmp(cargv[0], "objectclass") == 0) {
00220                      if (cargc < 2) {
00221                             fprintf(stderr, "%s: line %d: illegal objectclass format\n",
00222                                    fname, lineno);
00223                             return 1;
00224                      } else if (*cargv[1] == '(' /*')'*/) {
00225                             char *p;
00226 
00227                             p = strchr(saveline, '(' /*')'*/);
00228                             rc = dsaschema_parse_oc(fname, lineno, p, cargv);
00229                             if (rc != 0)
00230                                    return rc;
00231                      } else {
00232                             fprintf(stderr, "%s: line %d: object class format not supported\n",
00233                                    fname, lineno);
00234                      }
00235               } else if (strcasecmp(cargv[0], "include") == 0) {
00236                      if (cargc < 2) {
00237                             fprintf(stderr, "%s: line %d: missing file name in \"include <filename>\" line",
00238                                    fname, lineno);
00239                             return 1;
00240                      }
00241                      savefname = strdup(cargv[1]);
00242                      if (savefname == NULL) {
00243                             return 1;
00244                      }
00245                      if (dsaschema_read_config(savefname, depth + 1) != 0) {
00246                             return 1;
00247                      }
00248                      free(savefname);
00249                      lineno = savelineno - 1;
00250               } else {
00251                      fprintf(stderr, "%s: line %d: unknown directive \"%s\" (ignored)\n",
00252                             fname, lineno, cargv[0]);
00253               }
00254        }
00255 
00256        fclose(fp);
00257 
00258        if (depth == 0)
00259               free(cargv);
00260 
00261        return 0;
00262 }
00263 
00264 int init_module(int argc, char *argv[])
00265 {
00266        int i;
00267        int rc;
00268 
00269        for (i = 0; i < argc; i++) {
00270               rc = dsaschema_read_config(argv[i], 0);
00271               if (rc != 0) {
00272                      break;
00273               }
00274        }
00275 
00276        return rc;
00277 }
00278 
00279 
00280 static int
00281 fp_parse_line(
00282     int              lineno,
00283     char      *line
00284 )
00285 {
00286        char * token;
00287 
00288        cargc = 0;
00289        token = strtok_quote( line, " \t" );
00290 
00291        if ( strtok_quote_ptr ) {
00292               *strtok_quote_ptr = ' ';
00293        }
00294 
00295        if ( strtok_quote_ptr ) {
00296               *strtok_quote_ptr = '\0';
00297        }
00298 
00299        for ( ; token != NULL; token = strtok_quote( NULL, " \t" ) ) {
00300               if ( cargc == cargv_size - 1 ) {
00301                      char **tmp;
00302                      tmp = realloc( cargv, (cargv_size + ARGS_STEP) *
00303                                        sizeof(*cargv) );
00304                      if ( tmp == NULL ) {
00305                             return -1;
00306                      }
00307                      cargv = tmp;
00308                      cargv_size += ARGS_STEP;
00309               }
00310               cargv[cargc++] = token;
00311        }
00312        cargv[cargc] = NULL;
00313        return 0;
00314 }
00315 
00316 static char *
00317 strtok_quote( char *line, char *sep )
00318 {
00319        int           inquote;
00320        char          *tmp;
00321        static char   *next;
00322 
00323        strtok_quote_ptr = NULL;
00324        if ( line != NULL ) {
00325               next = line;
00326        }
00327        while ( *next && strchr( sep, *next ) ) {
00328               next++;
00329        }
00330 
00331        if ( *next == '\0' ) {
00332               next = NULL;
00333               return( NULL );
00334        }
00335        tmp = next;
00336 
00337        for ( inquote = 0; *next; ) {
00338               switch ( *next ) {
00339               case '"':
00340                      if ( inquote ) {
00341                             inquote = 0;
00342                      } else {
00343                             inquote = 1;
00344                      }
00345                      AC_MEMCPY( next, next + 1, strlen( next + 1 ) + 1 );
00346                      break;
00347 
00348               case '\\':
00349                      if ( next[1] )
00350                             AC_MEMCPY( next,
00351                                        next + 1, strlen( next + 1 ) + 1 );
00352                      next++;              /* dont parse the escaped character */
00353                      break;
00354 
00355               default:
00356                      if ( ! inquote ) {
00357                             if ( strchr( sep, *next ) != NULL ) {
00358                                    strtok_quote_ptr = next;
00359                                    *next++ = '\0';
00360                                    return( tmp );
00361                             }
00362                      }
00363                      next++;
00364                      break;
00365               }
00366        }
00367 
00368        return( tmp );
00369 }
00370 
00371 static char   buf[BUFSIZ];
00372 static char   *line;
00373 static size_t lmax, lcur;
00374 
00375 #define CATLINE( buf ) \
00376        do { \
00377               size_t len = strlen( buf ); \
00378               while ( lcur + len + 1 > lmax ) { \
00379                      lmax += BUFSIZ; \
00380                      line = (char *) realloc( line, lmax ); \
00381               } \
00382               strcpy( line + lcur, buf ); \
00383               lcur += len; \
00384        } while( 0 )
00385 
00386 static char *
00387 fp_getline( FILE *fp, int *lineno )
00388 {
00389        char          *p;
00390 
00391        lcur = 0;
00392        CATLINE( buf );
00393        (*lineno)++;
00394 
00395        /* hack attack - keeps us from having to keep a stack of bufs... */
00396        if ( strncasecmp( line, "include", 7 ) == 0 ) {
00397               buf[0] = '\0';
00398               return( line );
00399        }
00400 
00401        while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
00402               /* trim off \r\n or \n */
00403               if ( (p = strchr( buf, '\n' )) != NULL ) {
00404                      if( p > buf && p[-1] == '\r' ) --p;
00405                      *p = '\0';
00406               }
00407               
00408               /* trim off trailing \ and append the next line */
00409               if ( line[ 0 ] != '\0' 
00410                             && (p = line + strlen( line ) - 1)[ 0 ] == '\\'
00411                             && p[ -1 ] != '\\' ) {
00412                      p[ 0 ] = '\0';
00413                      lcur--;
00414 
00415               } else {
00416                      if ( ! isspace( (unsigned char) buf[0] ) ) {
00417                             return( line );
00418                      }
00419 
00420                      /* change leading whitespace to a space */
00421                      buf[0] = ' ';
00422               }
00423 
00424               CATLINE( buf );
00425               (*lineno)++;
00426        }
00427        buf[0] = '\0';
00428 
00429        return( line[0] ? line : NULL );
00430 }
00431 
00432 static void
00433 fp_getline_init( int *lineno )
00434 {
00435        *lineno = -1;
00436        buf[0] = '\0';
00437 }
00438