root/source3/lib/ldb/tools/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/include/includes.h"
  36 #include "ldb/tools/cmdline.h"
  37 #include "ldb/tools/convert.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_string_compose(msg, basedn,
 391                                                         "CN=%s,CN=Schema,CN=Configuration",
 392                                                         token->value);
 393                         break;
 394 
 395                 case SCHEMA_SUP:
 396                         MSG_ADD_M_STRING("subClassOf", token->value);
 397                         break;
 398 
 399                 case SCHEMA_STRUCTURAL:
 400                         MSG_ADD_STRING("objectClassCategory", "1");
 401                         break;
 402 
 403                 case SCHEMA_ABSTRACT:
 404                         MSG_ADD_STRING("objectClassCategory", "2");
 405                         break;
 406 
 407                 case SCHEMA_AUXILIARY:
 408                         MSG_ADD_STRING("objectClassCategory", "3");
 409                         break;
 410 
 411                 case SCHEMA_MUST:
 412                         MSG_ADD_M_STRING("mustContain", token->value);
 413                         break;
 414 
 415                 case SCHEMA_MAY:
 416                         MSG_ADD_M_STRING("mayContain", token->value);
 417                         break;
 418 
 419                 case SCHEMA_SINGLE_VALUE:
 420                         MSG_ADD_STRING("isSingleValued", "TRUE");
 421                         break;
 422 
 423                 case SCHEMA_EQUALITY:
 424                         /* TODO */
 425                         break;
 426 
 427                 case SCHEMA_ORDERING:
 428                         /* TODO */
 429                         break;
 430 
 431                 case SCHEMA_SUBSTR:
 432                         /* TODO */
 433                         break;
 434 
 435                 case SCHEMA_SYNTAX:
 436                 {
 437                         const struct syntax_map *map = 
 438                                 find_syntax_map_by_standard_oid(token->value);
 439                         if (!map) {
 440                                 break;
 441                         }
 442                         MSG_ADD_STRING("attributeSyntax", map->AD_OID);
 443                         break;
 444                 }
 445                 case SCHEMA_DESC:
 446                         MSG_ADD_STRING("description", token->value);
 447                         break;
 448 
 449                 default:
 450                         fprintf(stderr, "Unknown Definition: %s\n", token->value);
 451                 }
 452         }
 453 
 454         talloc_steal(mem_ctx, msg);
 455         talloc_free(ctx);
 456         return msg;
 457 
 458 failed:
 459         talloc_free(ctx);
 460         return NULL;
 461 }
 462 
 463 static struct schema_conv process_file(FILE *in, FILE *out)
     /* [<][>][^][v][top][bottom][index][help] */
 464 {
 465         TALLOC_CTX *ctx;
 466         struct schema_conv ret;
 467         char *entry;
 468         int c, t, line;
 469         struct ldb_ldif ldif;
 470 
 471         ldif.changetype = LDB_CHANGETYPE_NONE;
 472 
 473         ctx = talloc_new(NULL);
 474 
 475         ret.count = 0;
 476         ret.failures = 0;
 477         line = 0;
 478 
 479         while ((c = fgetc(in)) != EOF) {
 480                 line++;
 481                 /* fprintf(stderr, "Parsing line %d\n", line); */
 482                 if (c == '#') {
 483                         do {
 484                                 c = fgetc(in);
 485                         } while (c != EOF && c != '\n');
 486                         continue;
 487                 }
 488                 if (c == '\n') {
 489                         continue;
 490                 }
 491 
 492                 t = 0;
 493                 entry = talloc_array(ctx, char, 1024);
 494                 if (entry == NULL) exit(-1);
 495 
 496                 do { 
 497                         if (c == '\n') {
 498                                 entry[t] = '\0';        
 499                                 if (check_braces(entry) == 0) {
 500                                         ret.count++;
 501                                         ldif.msg = process_entry(ctx, entry);
 502                                         if (ldif.msg == NULL) {
 503                                                 ret.failures++;
 504                                                 fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
 505                                                 break;
 506                                         }
 507                                         ldb_ldif_write_file(ldb_ctx, out, &ldif);
 508                                         break;
 509                                 }
 510                                 line++;
 511                         } else {
 512                                 entry[t] = c;
 513                                 t++;
 514                         }
 515                         if ((t % 1023) == 0) {
 516                                 entry = talloc_realloc(ctx, entry, char, t + 1024);
 517                                 if (entry == NULL) exit(-1);
 518                         }
 519                 } while ((c = fgetc(in)) != EOF); 
 520 
 521                 if (c != '\n') {
 522                         entry[t] = '\0';
 523                         if (check_braces(entry) == 0) {
 524                                 ret.count++;
 525                                 ldif.msg = process_entry(ctx, entry);
 526                                 if (ldif.msg == NULL) {
 527                                         ret.failures++;
 528                                         fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
 529                                         break;
 530                                 }
 531                                 ldb_ldif_write_file(ldb_ctx, out, &ldif);
 532                         } else {
 533                                 fprintf(stderr, "malformed entry on line %d\n", line);
 534                                 ret.failures++;
 535                         }
 536                 }
 537         
 538                 if (c == EOF) break;
 539         }
 540 
 541         return ret;
 542 }
 543 
 544 static void usage(void)
     /* [<][>][^][v][top][bottom][index][help] */
 545 {
 546         printf("Usage: oLschema2ldif -H NONE <options>\n");
 547         printf("\nConvert OpenLDAP schema to AD-like LDIF format\n\n");
 548         printf("Options:\n");
 549         printf("  -I inputfile     inputfile of OpenLDAP style schema otherwise STDIN\n");
 550         printf("  -O outputfile    outputfile otherwise STDOUT\n");
 551         printf("  -o options       pass options like modules to activate\n");
 552         printf("              e.g: -o modules:timestamps\n");
 553         printf("\n");
 554         printf("Converts records from an openLdap formatted schema to an ldif schema\n\n");
 555         exit(1);
 556 }
 557 
 558  int main(int argc, const char **argv)
     /* [<][>][^][v][top][bottom][index][help] */
 559 {
 560         TALLOC_CTX *ctx;
 561         struct schema_conv ret;
 562         struct ldb_cmdline *options;
 563         FILE *in = stdin;
 564         FILE *out = stdout;
 565         ldb_global_init();
 566 
 567         ctx = talloc_new(NULL);
 568         ldb_ctx = ldb_init(ctx);
 569 
 570         setenv("LDB_URL", "NONE", 1);
 571         options = ldb_cmdline_process(ldb_ctx, argc, argv, usage);
 572 
 573         if (options->basedn == NULL) {
 574                 perror("Base DN not specified");
 575                 exit(1);
 576         } else {
 577                 basedn = ldb_dn_explode(ctx, options->basedn);
 578                 if (basedn == NULL) {
 579                         perror("Malformed Base DN");
 580                         exit(1);
 581                 }
 582         }
 583 
 584         if (options->input) {
 585                 in = fopen(options->input, "r");
 586                 if (!in) {
 587                         perror(options->input);
 588                         exit(1);
 589                 }
 590         }
 591         if (options->output) {
 592                 out = fopen(options->output, "w");
 593                 if (!out) {
 594                         perror(options->output);
 595                         exit(1);
 596                 }
 597         }
 598 
 599         ret = process_file(in, out);
 600 
 601         fclose(in);
 602         fclose(out);
 603 
 604         printf("Converted %d records with %d failures\n", ret.count, ret.failures);
 605 
 606         return 0;
 607 }

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