root/source4/utils/oLschema2ldif.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_braces
  2. skip_spaces
  3. add_multi_string
  4. get_def_value
  5. get_next_schema_token
  6. process_entry
  7. process_file
  8. usage
  9. main

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Simo Sorce 2005
   5 
   6      ** NOTE! The following LGPL license applies to the ldb
   7      ** library. This does NOT imply that all of Samba is released
   8      ** under the LGPL
   9    
  10    This library is free software; you can redistribute it and/or
  11    modify it under the terms of the GNU Lesser General Public
  12    License as published by the Free Software Foundation; either
  13    version 3 of the License, or (at your option) any later version.
  14 
  15    This library is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18    Lesser General Public License for more details.
  19 
  20    You should have received a copy of the GNU Lesser General Public
  21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 /*
  25  *  Name: ldb
  26  *
  27  *  Component: oLschema2ldif
  28  *
  29  *  Description: utility to convert an OpenLDAP schema into AD LDIF
  30  *
  31  *  Author: Simo Sorce
  32  */
  33 
  34 #include "includes.h"
  35 #include "ldb.h"
  36 #include "tools/cmdline.h"
  37 #include "dsdb/samdb/samdb.h"
  38 
  39 #define SCHEMA_UNKNOWN 0
  40 #define SCHEMA_NAME 1
  41 #define SCHEMA_SUP 2
  42 #define SCHEMA_STRUCTURAL 3
  43 #define SCHEMA_ABSTRACT 4
  44 #define SCHEMA_AUXILIARY 5
  45 #define SCHEMA_MUST 6
  46 #define SCHEMA_MAY 7
  47 #define SCHEMA_SINGLE_VALUE 8
  48 #define SCHEMA_EQUALITY 9
  49 #define SCHEMA_ORDERING 10
  50 #define SCHEMA_SUBSTR 11
  51 #define SCHEMA_SYNTAX 12
  52 #define SCHEMA_DESC 13
  53 
  54 struct schema_conv {
  55         int count;
  56         int failures;
  57 };
  58 
  59 struct schema_token {
  60         int type;
  61         char *value;
  62 };
  63 
  64 struct ldb_context *ldb_ctx;
  65 struct ldb_dn *basedn;
  66 
  67 static int check_braces(const char *string)
     /* [<][>][^][v][top][bottom][index][help] */
  68 {
  69         int b;
  70         char *c;
  71 
  72         b = 0;
  73         if ((c = strchr(string, '(')) == NULL) {
  74                 return -1;
  75         }
  76         b++;
  77         c++;
  78         while (b) {
  79                 c = strpbrk(c, "()");
  80                 if (c == NULL) return 1;
  81                 if (*c == '(') b++;
  82                 if (*c == ')') b--;
  83                 c++;
  84         }
  85         return 0;
  86 }
  87 
  88 static char *skip_spaces(char *string) {
     /* [<][>][^][v][top][bottom][index][help] */
  89         return (string + strspn(string, " \t\n"));
  90 }
  91 
  92 static int add_multi_string(struct ldb_message *msg, const char *attr, char *values)
     /* [<][>][^][v][top][bottom][index][help] */
  93 {
  94         char *c;
  95         char *s;
  96         int n;
  97 
  98         c = skip_spaces(values);
  99         while (*c) {
 100                 n = strcspn(c, " \t$");
 101                 s = talloc_strndup(msg, c, n);
 102                 if (ldb_msg_add_string(msg, attr, s) != 0) {
 103                         return -1;
 104                 }
 105                 c += n;
 106                 c += strspn(c, " \t$");
 107         }
 108 
 109         return 0;
 110 }
 111 
 112 #define MSG_ADD_STRING(a, v) do { if (ldb_msg_add_string(msg, a, v) != 0) goto failed; } while(0)
 113 #define MSG_ADD_M_STRING(a, v) do { if (add_multi_string(msg, a, v) != 0) goto failed; } while(0)
 114 
 115 static char *get_def_value(TALLOC_CTX *ctx, char **string)
     /* [<][>][^][v][top][bottom][index][help] */
 116 {
 117         char *c = *string;
 118         char *value;
 119         int n;
 120 
 121         if (*c == '\'') {
 122                 c++;
 123                 n = strcspn(c, "\'");
 124                 value = talloc_strndup(ctx, c, n);
 125                 c += n;
 126                 c++; /* skip closing \' */
 127         } else {
 128                 n = strcspn(c, " \t\n");
 129                 value = talloc_strndup(ctx, c, n);
 130                 c += n;
 131         }
 132         *string = c;
 133 
 134         return value;
 135 }
 136 
 137 static struct schema_token *get_next_schema_token(TALLOC_CTX *ctx, char **string)
     /* [<][>][^][v][top][bottom][index][help] */
 138 {
 139         char *c = skip_spaces(*string);
 140         char *type;
 141         struct schema_token *token;
 142         int n;
 143 
 144         token = talloc(ctx, struct schema_token);
 145 
 146         n = strcspn(c, " \t\n");
 147         type = talloc_strndup(token, c, n);
 148         c += n;
 149         c = skip_spaces(c);
 150 
 151         if (strcasecmp("NAME", type) == 0) {
 152                 talloc_free(type);
 153                 token->type = SCHEMA_NAME;
 154                 /* we do not support aliases so we get only the first name given and skip others */
 155                 if (*c == '(') {
 156                         char *s = strchr(c, ')');
 157                         if (s == NULL) return NULL;
 158                         s = skip_spaces(s);
 159                         *string = s;
 160 
 161                         c++;
 162                         c = skip_spaces(c);
 163                 }
 164 
 165                 token->value = get_def_value(ctx, &c);
 166 
 167                 if (*string < c) { /* single name */
 168                         c = skip_spaces(c);
 169                         *string = c;
 170                 }
 171                 return token;
 172         }
 173         if (strcasecmp("SUP", type) == 0) {
 174                 talloc_free(type);
 175                 token->type = SCHEMA_SUP;
 176 
 177                 if (*c == '(') {
 178                         c++;
 179                         n = strcspn(c, ")");
 180                         token->value = talloc_strndup(ctx, c, n);
 181                         c += n;
 182                         c++;
 183                 } else {
 184                         token->value = get_def_value(ctx, &c);
 185                 }
 186 
 187                 c = skip_spaces(c);
 188                 *string = c;
 189                 return token;
 190         }
 191 
 192         if (strcasecmp("STRUCTURAL", type) == 0) {
 193                 talloc_free(type);
 194                 token->type = SCHEMA_STRUCTURAL;
 195                 *string = c;
 196                 return token;
 197         }
 198 
 199         if (strcasecmp("ABSTRACT", type) == 0) {
 200                 talloc_free(type);
 201                 token->type = SCHEMA_ABSTRACT;
 202                 *string = c;
 203                 return token;
 204         }
 205 
 206         if (strcasecmp("AUXILIARY", type) == 0) {
 207                 talloc_free(type);
 208                 token->type = SCHEMA_AUXILIARY;
 209                 *string = c;
 210                 return token;
 211         }
 212 
 213         if (strcasecmp("MUST", type) == 0) {
 214                 talloc_free(type);
 215                 token->type = SCHEMA_MUST;
 216 
 217                 if (*c == '(') {
 218                         c++;
 219                         n = strcspn(c, ")");
 220                         token->value = talloc_strndup(ctx, c, n);
 221                         c += n;
 222                         c++;
 223                 } else {
 224                         token->value = get_def_value(ctx, &c);
 225                 }
 226 
 227                 c = skip_spaces(c);
 228                 *string = c;
 229                 return token;
 230         }
 231 
 232         if (strcasecmp("MAY", type) == 0) {
 233                 talloc_free(type);
 234                 token->type = SCHEMA_MAY;
 235 
 236                 if (*c == '(') {
 237                         c++;
 238                         n = strcspn(c, ")");
 239                         token->value = talloc_strndup(ctx, c, n);
 240                         c += n;
 241                         c++;
 242                 } else {
 243                         token->value = get_def_value(ctx, &c);
 244                 }
 245 
 246                 c = skip_spaces(c);
 247                 *string = c;
 248                 return token;
 249         }
 250 
 251         if (strcasecmp("SINGLE-VALUE", type) == 0) {
 252                 talloc_free(type);
 253                 token->type = SCHEMA_SINGLE_VALUE;
 254                 *string = c;
 255                 return token;
 256         }
 257 
 258         if (strcasecmp("EQUALITY", type) == 0) {
 259                 talloc_free(type);
 260                 token->type = SCHEMA_EQUALITY;
 261 
 262                 token->value = get_def_value(ctx, &c);
 263 
 264                 c = skip_spaces(c);
 265                 *string = c;
 266                 return token;
 267         }
 268 
 269         if (strcasecmp("ORDERING", type) == 0) {
 270                 talloc_free(type);
 271                 token->type = SCHEMA_ORDERING;
 272 
 273                 token->value = get_def_value(ctx, &c);
 274 
 275                 c = skip_spaces(c);
 276                 *string = c;
 277                 return token;
 278         }
 279 
 280         if (strcasecmp("SUBSTR", type) == 0) {
 281                 talloc_free(type);
 282                 token->type = SCHEMA_SUBSTR;
 283 
 284                 token->value = get_def_value(ctx, &c);
 285 
 286                 c = skip_spaces(c);
 287                 *string = c;
 288                 return token;
 289         }
 290 
 291         if (strcasecmp("SYNTAX", type) == 0) {
 292                 talloc_free(type);
 293                 token->type = SCHEMA_SYNTAX;
 294 
 295                 token->value = get_def_value(ctx, &c);
 296 
 297                 c = skip_spaces(c);
 298                 *string = c;
 299                 return token;
 300         }
 301 
 302         if (strcasecmp("DESC", type) == 0) {
 303                 talloc_free(type);
 304                 token->type = SCHEMA_DESC;
 305 
 306                 token->value = get_def_value(ctx, &c);
 307 
 308                 c = skip_spaces(c);
 309                 *string = c;
 310                 return token;
 311         }
 312 
 313         token->type = SCHEMA_UNKNOWN;
 314         token->value = type;
 315         if (*c == ')') {
 316                 *string = c;
 317                 return token;
 318         }
 319         if (*c == '\'') {
 320                 c = strchr(++c, '\'');
 321                 c++;
 322         } else {
 323                 c += strcspn(c, " \t\n");
 324         }
 325         c = skip_spaces(c);
 326         *string = c;
 327 
 328         return token;
 329 }
 330 
 331 static struct ldb_message *process_entry(TALLOC_CTX *mem_ctx, const char *entry)
     /* [<][>][^][v][top][bottom][index][help] */
 332 {
 333         TALLOC_CTX *ctx;
 334         struct ldb_message *msg;
 335         struct schema_token *token;
 336         char *c, *s;
 337         int n;
 338 
 339         ctx = talloc_new(mem_ctx);
 340         msg = ldb_msg_new(ctx);
 341 
 342         ldb_msg_add_string(msg, "objectClass", "top");
 343 
 344         c = talloc_strdup(ctx, entry);
 345         if (!c) return NULL;
 346 
 347         c = skip_spaces(c);
 348 
 349         switch (*c) {
 350         case 'a':
 351                 if (strncmp(c, "attributetype", 13) == 0) {
 352                         c += 13;
 353                         MSG_ADD_STRING("objectClass", "attributeSchema");
 354                         break;
 355                 }
 356                 goto failed;
 357         case 'o':
 358                 if (strncmp(c, "objectclass", 11) == 0) {
 359                         c += 11;
 360                         MSG_ADD_STRING("objectClass", "classSchema");
 361                         break;
 362                 }
 363                 goto failed;
 364         default:
 365                 goto failed;
 366         }
 367 
 368         c = strchr(c, '(');
 369         if (c == NULL) goto failed;
 370         c++;
 371 
 372         c = skip_spaces(c);
 373 
 374         /* get attributeID */
 375         n = strcspn(c, " \t");
 376         s = talloc_strndup(msg, c, n);
 377         MSG_ADD_STRING("attributeID", s);
 378         c += n;
 379         c = skip_spaces(c);     
 380 
 381         while (*c != ')') {
 382                 token = get_next_schema_token(msg, &c);
 383                 if (!token) goto failed;
 384 
 385                 switch (token->type) {
 386                 case SCHEMA_NAME:
 387                         MSG_ADD_STRING("cn", token->value);
 388                         MSG_ADD_STRING("name", token->value);
 389                         MSG_ADD_STRING("lDAPDisplayName", token->value);
 390                         msg->dn = ldb_dn_copy(msg, basedn);
 391                         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Schema,CN=Configuration", token->value);
 392                         break;
 393 
 394                 case SCHEMA_SUP:
 395                         MSG_ADD_M_STRING("subClassOf", token->value);
 396                         break;
 397 
 398                 case SCHEMA_STRUCTURAL:
 399                         MSG_ADD_STRING("objectClassCategory", "1");
 400                         break;
 401 
 402                 case SCHEMA_ABSTRACT:
 403                         MSG_ADD_STRING("objectClassCategory", "2");
 404                         break;
 405 
 406                 case SCHEMA_AUXILIARY:
 407                         MSG_ADD_STRING("objectClassCategory", "3");
 408                         break;
 409 
 410                 case SCHEMA_MUST:
 411                         MSG_ADD_M_STRING("mustContain", token->value);
 412                         break;
 413 
 414                 case SCHEMA_MAY:
 415                         MSG_ADD_M_STRING("mayContain", token->value);
 416                         break;
 417 
 418                 case SCHEMA_SINGLE_VALUE:
 419                         MSG_ADD_STRING("isSingleValued", "TRUE");
 420                         break;
 421 
 422                 case SCHEMA_EQUALITY:
 423                         /* TODO */
 424                         break;
 425 
 426                 case SCHEMA_ORDERING:
 427                         /* TODO */
 428                         break;
 429 
 430                 case SCHEMA_SUBSTR:
 431                         /* TODO */
 432                         break;
 433 
 434                 case SCHEMA_SYNTAX:
 435                 {
 436                         const struct dsdb_syntax *map = 
 437                                 find_syntax_map_by_standard_oid(token->value);
 438                         if (!map) {
 439                                 break;
 440                         }
 441                         MSG_ADD_STRING("attributeSyntax", map->attributeSyntax_oid);
 442                         break;
 443                 }
 444                 case SCHEMA_DESC:
 445                         MSG_ADD_STRING("description", token->value);
 446                         break;
 447 
 448                 default:
 449                         fprintf(stderr, "Unknown Definition: %s\n", token->value);
 450                 }
 451         }
 452 
 453         talloc_steal(mem_ctx, msg);
 454         talloc_free(ctx);
 455         return msg;
 456 
 457 failed:
 458         talloc_free(ctx);
 459         return NULL;
 460 }
 461 
 462 static struct schema_conv process_file(FILE *in, FILE *out)
     /* [<][>][^][v][top][bottom][index][help] */
 463 {
 464         TALLOC_CTX *ctx;
 465         struct schema_conv ret;
 466         char *entry;
 467         int c, t, line;
 468         struct ldb_ldif ldif;
 469 
 470         ldif.changetype = LDB_CHANGETYPE_NONE;
 471 
 472         ctx = talloc_new(NULL);
 473 
 474         ret.count = 0;
 475         ret.failures = 0;
 476         line = 0;
 477 
 478         while ((c = fgetc(in)) != EOF) {
 479                 line++;
 480                 /* fprintf(stderr, "Parsing line %d\n", line); */
 481                 if (c == '#') {
 482                         do {
 483                                 c = fgetc(in);
 484                         } while (c != EOF && c != '\n');
 485                         continue;
 486                 }
 487                 if (c == '\n') {
 488                         continue;
 489                 }
 490 
 491                 t = 0;
 492                 entry = talloc_array(ctx, char, 1024);
 493                 if (entry == NULL) exit(-1);
 494 
 495                 do { 
 496                         if (c == '\n') {
 497                                 entry[t] = '\0';        
 498                                 if (check_braces(entry) == 0) {
 499                                         ret.count++;
 500                                         ldif.msg = process_entry(ctx, entry);
 501                                         if (ldif.msg == NULL) {
 502                                                 ret.failures++;
 503                                                 fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
 504                                                 break;
 505                                         }
 506                                         ldb_ldif_write_file(ldb_ctx, out, &ldif);
 507                                         break;
 508                                 }
 509                                 line++;
 510                         } else {
 511                                 entry[t] = c;
 512                                 t++;
 513                         }
 514                         if ((t % 1023) == 0) {
 515                                 entry = talloc_realloc(ctx, entry, char, t + 1024);
 516                                 if (entry == NULL) exit(-1);
 517                         }
 518                 } while ((c = fgetc(in)) != EOF); 
 519 
 520                 if (c != '\n') {
 521                         entry[t] = '\0';
 522                         if (check_braces(entry) == 0) {
 523                                 ret.count++;
 524                                 ldif.msg = process_entry(ctx, entry);
 525                                 if (ldif.msg == NULL) {
 526                                         ret.failures++;
 527                                         fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
 528                                         break;
 529                                 }
 530                                 ldb_ldif_write_file(ldb_ctx, out, &ldif);
 531                         } else {
 532                                 fprintf(stderr, "malformed entry on line %d\n", line);
 533                                 ret.failures++;
 534                         }
 535                 }
 536         
 537                 if (c == EOF) break;
 538         }
 539 
 540         return ret;
 541 }
 542 
 543 static void usage(void)
     /* [<][>][^][v][top][bottom][index][help] */
 544 {
 545         printf("Usage: oLschema2ldif -H NONE <options>\n");
 546         printf("\nConvert OpenLDAP schema to AD-like LDIF format\n\n");
 547         printf("Options:\n");
 548         printf("  -I inputfile     inputfile of OpenLDAP style schema otherwise STDIN\n");
 549         printf("  -O outputfile    outputfile otherwise STDOUT\n");
 550         printf("  -o options       pass options like modules to activate\n");
 551         printf("              e.g: -o modules:timestamps\n");
 552         printf("\n");
 553         printf("Converts records from an openLdap formatted schema to an ldif schema\n\n");
 554         exit(1);
 555 }
 556 
 557  int main(int argc, const char **argv)
     /* [<][>][^][v][top][bottom][index][help] */
 558 {
 559         TALLOC_CTX *ctx;
 560         struct schema_conv ret;
 561         struct ldb_cmdline *options;
 562         FILE *in = stdin;
 563         FILE *out = stdout;
 564         ctx = talloc_new(NULL);
 565         ldb_ctx = ldb_init(ctx, NULL);
 566 
 567         setenv("LDB_URL", "NONE", 1);
 568         options = ldb_cmdline_process(ldb_ctx, argc, argv, usage);
 569 
 570         if (options->basedn == NULL) {
 571                 perror("Base DN not specified");
 572                 exit(1);
 573         } else {
 574                 basedn = ldb_dn_new(ctx, ldb_ctx, options->basedn);
 575                 if ( ! ldb_dn_validate(basedn)) {
 576                         perror("Malformed Base DN");
 577                         exit(1);
 578                 }
 579         }
 580 
 581         if (options->input) {
 582                 in = fopen(options->input, "r");
 583                 if (!in) {
 584                         perror(options->input);
 585                         exit(1);
 586                 }
 587         }
 588         if (options->output) {
 589                 out = fopen(options->output, "w");
 590                 if (!out) {
 591                         perror(options->output);
 592                         exit(1);
 593                 }
 594         }
 595 
 596         ret = process_file(in, out);
 597 
 598         fclose(in);
 599         fclose(out);
 600 
 601         printf("Converted %d records with %d failures\n", ret.count, ret.failures);
 602 
 603         return 0;
 604 }

/* [<][>][^][v][top][bottom][index][help] */