Logo Search packages:      
Sourcecode: ldb version File versions  Download package

oLschema2ldif.c

/* 
   ldb database library

   Copyright (C) Simo Sorce 2005

     ** NOTE! The following LGPL license applies to the ldb
     ** library. This does NOT imply that all of Samba is released
     ** under the LGPL
   
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

/*
 *  Name: ldb
 *
 *  Component: oLschema2ldif
 *
 *  Description: utility to convert an OpenLDAP schema into AD LDIF
 *
 *  Author: Simo Sorce
 */

#include "ldb_includes.h"
#include "tools/cmdline.h"
#include "tools/convert.h"

#define SCHEMA_UNKNOWN 0
#define SCHEMA_NAME 1
#define SCHEMA_SUP 2
#define SCHEMA_STRUCTURAL 3
#define SCHEMA_ABSTRACT 4
#define SCHEMA_AUXILIARY 5
#define SCHEMA_MUST 6
#define SCHEMA_MAY 7
#define SCHEMA_SINGLE_VALUE 8
#define SCHEMA_EQUALITY 9
#define SCHEMA_ORDERING 10
#define SCHEMA_SUBSTR 11
#define SCHEMA_SYNTAX 12
#define SCHEMA_DESC 13

struct schema_conv {
      int count;
      int failures;
};

struct schema_token {
      int type;
      char *value;
};

struct ldb_context *ldb_ctx;
struct ldb_dn *basedn;

static int check_braces(const char *string)
{
      int b;
      char *c;

      b = 0;
      if ((c = strchr(string, '(')) == NULL) {
            return -1;
      }
      b++;
      c++;
      while (b) {
            c = strpbrk(c, "()");
            if (c == NULL) return 1;
            if (*c == '(') b++;
            if (*c == ')') b--;
            c++;
      }
      return 0;
}

static char *skip_spaces(char *string) {
      return (string + strspn(string, " \t\n"));
}

static int add_multi_string(struct ldb_message *msg, const char *attr, char *values)
{
      char *c;
      char *s;
      int n;

      c = skip_spaces(values);
      while (*c) {
            n = strcspn(c, " \t$");
            s = talloc_strndup(msg, c, n);
            if (ldb_msg_add_string(msg, attr, s) != 0) {
                  return -1;
            }
            c += n;
            c += strspn(c, " \t$");
      }

      return 0;
}

#define MSG_ADD_STRING(a, v) do { if (ldb_msg_add_string(msg, a, v) != 0) goto failed; } while(0)
#define MSG_ADD_M_STRING(a, v) do { if (add_multi_string(msg, a, v) != 0) goto failed; } while(0)

static char *get_def_value(TALLOC_CTX *ctx, char **string)
{
      char *c = *string;
      char *value;
      int n;

      if (*c == '\'') {
            c++;
            n = strcspn(c, "\'");
            value = talloc_strndup(ctx, c, n);
            c += n;
            c++; /* skip closing \' */
      } else {
            n = strcspn(c, " \t\n");
            value = talloc_strndup(ctx, c, n);
            c += n;
      }
      *string = c;

      return value;
}

static struct schema_token *get_next_schema_token(TALLOC_CTX *ctx, char **string)
{
      char *c = skip_spaces(*string);
      char *type;
      struct schema_token *token;
      int n;

      token = talloc(ctx, struct schema_token);

      n = strcspn(c, " \t\n");
      type = talloc_strndup(token, c, n);
      c += n;
      c = skip_spaces(c);

      if (strcasecmp("NAME", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_NAME;
            /* we do not support aliases so we get only the first name given and skip others */
            if (*c == '(') {
                  char *s = strchr(c, ')');
                  if (s == NULL) return NULL;
                  s = skip_spaces(s);
                  *string = s;

                  c++;
                  c = skip_spaces(c);
            }

            token->value = get_def_value(ctx, &c);

            if (*string < c) { /* single name */
                  c = skip_spaces(c);
                  *string = c;
            }
            return token;
      }
      if (strcasecmp("SUP", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_SUP;

            if (*c == '(') {
                  c++;
                  n = strcspn(c, ")");
                  token->value = talloc_strndup(ctx, c, n);
                  c += n;
                  c++;
            } else {
                  token->value = get_def_value(ctx, &c);
            }

            c = skip_spaces(c);
            *string = c;
            return token;
      }

      if (strcasecmp("STRUCTURAL", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_STRUCTURAL;
            *string = c;
            return token;
      }

      if (strcasecmp("ABSTRACT", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_ABSTRACT;
            *string = c;
            return token;
      }

      if (strcasecmp("AUXILIARY", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_AUXILIARY;
            *string = c;
            return token;
      }

      if (strcasecmp("MUST", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_MUST;

            if (*c == '(') {
                  c++;
                  n = strcspn(c, ")");
                  token->value = talloc_strndup(ctx, c, n);
                  c += n;
                  c++;
            } else {
                  token->value = get_def_value(ctx, &c);
            }

            c = skip_spaces(c);
            *string = c;
            return token;
      }

      if (strcasecmp("MAY", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_MAY;

            if (*c == '(') {
                  c++;
                  n = strcspn(c, ")");
                  token->value = talloc_strndup(ctx, c, n);
                  c += n;
                  c++;
            } else {
                  token->value = get_def_value(ctx, &c);
            }

            c = skip_spaces(c);
            *string = c;
            return token;
      }

      if (strcasecmp("SINGLE-VALUE", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_SINGLE_VALUE;
            *string = c;
            return token;
      }

      if (strcasecmp("EQUALITY", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_EQUALITY;

            token->value = get_def_value(ctx, &c);

            c = skip_spaces(c);
            *string = c;
            return token;
      }

      if (strcasecmp("ORDERING", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_ORDERING;

            token->value = get_def_value(ctx, &c);

            c = skip_spaces(c);
            *string = c;
            return token;
      }

      if (strcasecmp("SUBSTR", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_SUBSTR;

            token->value = get_def_value(ctx, &c);

            c = skip_spaces(c);
            *string = c;
            return token;
      }

      if (strcasecmp("SYNTAX", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_SYNTAX;

            token->value = get_def_value(ctx, &c);

            c = skip_spaces(c);
            *string = c;
            return token;
      }

      if (strcasecmp("DESC", type) == 0) {
            talloc_free(type);
            token->type = SCHEMA_DESC;

            token->value = get_def_value(ctx, &c);

            c = skip_spaces(c);
            *string = c;
            return token;
      }

      token->type = SCHEMA_UNKNOWN;
      token->value = type;
      if (*c == ')') {
            *string = c;
            return token;
      }
      if (*c == '\'') {
            c = strchr(++c, '\'');
            c++;
      } else {
            c += strcspn(c, " \t\n");
      }
      c = skip_spaces(c);
      *string = c;

      return token;
}

static struct ldb_message *process_entry(TALLOC_CTX *mem_ctx, const char *entry)
{
      TALLOC_CTX *ctx;
      struct ldb_message *msg;
      struct schema_token *token;
        char *c, *s;
        int n;

      ctx = talloc_new(mem_ctx);
      msg = ldb_msg_new(ctx);

      ldb_msg_add_string(msg, "objectClass", "top");

      c = talloc_strdup(ctx, entry);
      if (!c) return NULL;

      c = skip_spaces(c);

      switch (*c) {
      case 'a':
            if (strncmp(c, "attributetype", 13) == 0) {
                  c += 13;
                  MSG_ADD_STRING("objectClass", "attributeSchema");
                  break;
            }
            goto failed;
      case 'o':
            if (strncmp(c, "objectclass", 11) == 0) {
                  c += 11;
                  MSG_ADD_STRING("objectClass", "classSchema");
                  break;
            }
            goto failed;
      default:
            goto failed;
      }

      c = strchr(c, '(');
      if (c == NULL) goto failed;
      c++;

      c = skip_spaces(c);

      /* get attributeID */
      n = strcspn(c, " \t");
      s = talloc_strndup(msg, c, n);
      MSG_ADD_STRING("attributeID", s);
      c += n;
      c = skip_spaces(c);     

      while (*c != ')') {
            token = get_next_schema_token(msg, &c);
            if (!token) goto failed;

            switch (token->type) {
            case SCHEMA_NAME:
                  MSG_ADD_STRING("cn", token->value);
                  MSG_ADD_STRING("name", token->value);
                  MSG_ADD_STRING("lDAPDisplayName", token->value);
                  msg->dn = ldb_dn_copy(msg, basedn);
                  ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Schema,CN=Configuration", token->value);
                  break;

            case SCHEMA_SUP:
                  MSG_ADD_M_STRING("subClassOf", token->value);
                  break;

            case SCHEMA_STRUCTURAL:
                  MSG_ADD_STRING("objectClassCategory", "1");
                  break;

            case SCHEMA_ABSTRACT:
                  MSG_ADD_STRING("objectClassCategory", "2");
                  break;

            case SCHEMA_AUXILIARY:
                  MSG_ADD_STRING("objectClassCategory", "3");
                  break;

            case SCHEMA_MUST:
                  MSG_ADD_M_STRING("mustContain", token->value);
                  break;

            case SCHEMA_MAY:
                  MSG_ADD_M_STRING("mayContain", token->value);
                  break;

            case SCHEMA_SINGLE_VALUE:
                  MSG_ADD_STRING("isSingleValued", "TRUE");
                  break;

            case SCHEMA_EQUALITY:
                  /* TODO */
                  break;

            case SCHEMA_ORDERING:
                  /* TODO */
                  break;

            case SCHEMA_SUBSTR:
                  /* TODO */
                  break;

            case SCHEMA_SYNTAX:
            {
                  const struct syntax_map *map = 
                        find_syntax_map_by_standard_oid(token->value);
                  if (!map) {
                        break;
                  }
                  MSG_ADD_STRING("attributeSyntax", map->AD_OID);
                  break;
            }
            case SCHEMA_DESC:
                  MSG_ADD_STRING("description", token->value);
                  break;

            default:
                  fprintf(stderr, "Unknown Definition: %s\n", token->value);
            }
      }

      talloc_steal(mem_ctx, msg);
      talloc_free(ctx);
      return msg;

failed:
      talloc_free(ctx);
      return NULL;
}

static struct schema_conv process_file(FILE *in, FILE *out)
{
      TALLOC_CTX *ctx;
      struct schema_conv ret;
      char *entry;
      int c, t, line;
      struct ldb_ldif ldif;

      ldif.changetype = LDB_CHANGETYPE_NONE;

      ctx = talloc_new(NULL);

      ret.count = 0;
      ret.failures = 0;
      line = 0;

      while ((c = fgetc(in)) != EOF) {
            line++;
            /* fprintf(stderr, "Parsing line %d\n", line); */
            if (c == '#') {
                  do {
                        c = fgetc(in);
                  } while (c != EOF && c != '\n');
                  continue;
            }
            if (c == '\n') {
                  continue;
            }

            t = 0;
            entry = talloc_array(ctx, char, 1024);
            if (entry == NULL) exit(-1);

            do { 
                  if (c == '\n') {
                        entry[t] = '\0';  
                        if (check_braces(entry) == 0) {
                              ret.count++;
                              ldif.msg = process_entry(ctx, entry);
                              if (ldif.msg == NULL) {
                                    ret.failures++;
                                    fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
                                    break;
                              }
                              ldb_ldif_write_file(ldb_ctx, out, &ldif);
                              break;
                        }
                        line++;
                  } else {
                        entry[t] = c;
                        t++;
                  }
                  if ((t % 1023) == 0) {
                        entry = talloc_realloc(ctx, entry, char, t + 1024);
                        if (entry == NULL) exit(-1);
                  }
            } while ((c = fgetc(in)) != EOF); 

            if (c != '\n') {
                  entry[t] = '\0';
                  if (check_braces(entry) == 0) {
                        ret.count++;
                        ldif.msg = process_entry(ctx, entry);
                        if (ldif.msg == NULL) {
                              ret.failures++;
                              fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
                              break;
                        }
                        ldb_ldif_write_file(ldb_ctx, out, &ldif);
                  } else {
                        fprintf(stderr, "malformed entry on line %d\n", line);
                        ret.failures++;
                  }
            }
      
            if (c == EOF) break;
      }

      return ret;
}

static void usage(void)
{
      printf("Usage: oLschema2ldif -H NONE <options>\n");
      printf("\nConvert OpenLDAP schema to AD-like LDIF format\n\n");
      printf("Options:\n");
      printf("  -I inputfile     inputfile of OpenLDAP style schema otherwise STDIN\n");
      printf("  -O outputfile    outputfile otherwise STDOUT\n");
      printf("  -o options       pass options like modules to activate\n");
      printf("              e.g: -o modules:timestamps\n");
      printf("\n");
      printf("Converts records from an openLdap formatted schema to an ldif schema\n\n");
      exit(1);
}

 int main(int argc, const char **argv)
{
      TALLOC_CTX *ctx;
      struct schema_conv ret;
      struct ldb_cmdline *options;
      FILE *in = stdin;
      FILE *out = stdout;
      ldb_global_init();

      ctx = talloc_new(NULL);
      ldb_ctx = ldb_init(ctx);

      setenv("LDB_URL", "NONE", 1);
      options = ldb_cmdline_process(ldb_ctx, argc, argv, usage);

      if (options->basedn == NULL) {
            perror("Base DN not specified");
            exit(1);
      } else {
            basedn = ldb_dn_new(ctx, ldb_ctx, options->basedn);
            if ( ! ldb_dn_validate(basedn)) {
                  perror("Malformed Base DN");
                  exit(1);
            }
      }

      if (options->input) {
            in = fopen(options->input, "r");
            if (!in) {
                  perror(options->input);
                  exit(1);
            }
      }
      if (options->output) {
            out = fopen(options->output, "w");
            if (!out) {
                  perror(options->output);
                  exit(1);
            }
      }

      ret = process_file(in, out);

      fclose(in);
      fclose(out);

      printf("Converted %d records with %d failures\n", ret.count, ret.failures);

      return 0;
}

Generated by  Doxygen 1.6.0   Back to index