root/source4/utils/ad2oLschema.c

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

DEFINITIONS

This source file includes following definitions.
  1. usage
  2. find_schema_dn
  3. process_convert
  4. main

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Andrew Bartlett 2006-2008
   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: ad2oLschema
  28  *
  29  *  Description: utility to convert an AD schema into the format required by OpenLDAP
  30  *
  31  *  Author: Andrew Bartlett
  32  */
  33 
  34 #include "includes.h"
  35 #include "ldb.h"
  36 #include "system/locale.h"
  37 #include "lib/ldb/tools/cmdline.h"
  38 #include "param/param.h"
  39 #include "lib/cmdline/popt_common.h"
  40 #include "dsdb/samdb/samdb.h"
  41 
  42 struct schema_conv {
  43         int count;
  44         int skipped;
  45         int failures;
  46 };
  47         
  48 
  49 static void usage(void)
     /* [<][>][^][v][top][bottom][index][help] */
  50 {
  51         printf("Usage: ad2oLschema <options>\n");
  52         printf("\nConvert AD-like LDIF to OpenLDAP schema format\n\n");
  53         printf("Options:\n");
  54         printf("  -I inputfile     inputfile of mapped OIDs and skipped attributes/ObjectClasses");
  55         printf("  -H url           LDB or LDAP server to read schmea from\n");
  56         printf("  -O outputfile    outputfile otherwise STDOUT\n");
  57         printf("  -o options       pass options like modules to activate\n");
  58         printf("              e.g: -o modules:timestamps\n");
  59         printf("\n");
  60         printf("Converts records from an AD-like LDIF schema into an openLdap formatted schema\n\n");
  61         exit(1);
  62 }
  63 
  64 static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) 
     /* [<][>][^][v][top][bottom][index][help] */
  65 {
  66         const char *rootdse_attrs[] = {"schemaNamingContext", NULL};
  67         struct ldb_dn *schemadn;
  68         struct ldb_dn *basedn = ldb_dn_new(mem_ctx, ldb, NULL);
  69         struct ldb_result *rootdse_res;
  70         struct ldb_result *schema_res;
  71         int ldb_ret;
  72         
  73         if (!basedn) {
  74                 return NULL;
  75         }
  76         
  77         /* Search for rootdse */
  78         ldb_ret = ldb_search(ldb, mem_ctx, &rootdse_res,
  79                              basedn, LDB_SCOPE_BASE, rootdse_attrs, NULL);
  80         if (ldb_ret != LDB_SUCCESS) {
  81                 ldb_ret = ldb_search(ldb, mem_ctx, &schema_res, basedn, LDB_SCOPE_SUBTREE,
  82                                      NULL, "(&(objectClass=dMD)(cn=Schema))");
  83                 if (ldb_ret) {
  84                         printf("cn=Schema Search failed: %s\n", ldb_errstring(ldb));
  85                         return NULL;
  86                 }
  87 
  88                 if (schema_res->count != 1) {
  89                         talloc_free(schema_res);
  90                         printf("Failed to find rootDSE");
  91                         return NULL;
  92                 }
  93                 
  94                 schemadn = talloc_steal(mem_ctx, schema_res->msgs[0]->dn);
  95                 talloc_free(schema_res);
  96                 return schemadn;
  97         }
  98         
  99         if (rootdse_res->count != 1) {
 100                 printf("Failed to find rootDSE");
 101                 talloc_free(rootdse_res);
 102                 return NULL;
 103         }
 104         
 105         /* Locate schema */
 106         schemadn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
 107         talloc_free(rootdse_res);
 108 
 109         if (!schemadn) {
 110                 return NULL;
 111         }
 112 
 113         return schemadn;
 114 }
 115 
 116 
 117 static struct schema_conv process_convert(struct ldb_context *ldb, enum dsdb_schema_convert_target target, FILE *in, FILE *out) 
     /* [<][>][^][v][top][bottom][index][help] */
 118 {
 119         /* Read list of attributes to skip, OIDs to map */
 120         TALLOC_CTX *mem_ctx = talloc_new(ldb);
 121         char *line;
 122         const char **attrs_skip = NULL;
 123         int num_skip = 0;
 124         struct oid_map {
 125                 char *old_oid;
 126                 char *new_oid;
 127         } *oid_map = NULL;
 128         int num_oid_maps = 0;
 129         struct attr_map {
 130                 char *old_attr;
 131                 char *new_attr;
 132         } *attr_map = NULL;
 133         int num_attr_maps = 0;  
 134         struct dsdb_class *objectclass;
 135         struct dsdb_attribute *attribute;
 136         struct ldb_dn *schemadn;
 137         struct schema_conv ret;
 138         struct dsdb_schema *schema;
 139         const char *seperator;
 140         char *error_string;
 141 
 142         int ldb_ret;
 143 
 144         ret.count = 0;
 145         ret.skipped = 0;
 146         ret.failures = 0;
 147 
 148         while ((line = afdgets(fileno(in), mem_ctx, 0))) {
 149                 /* Blank Line */
 150                 if (line[0] == '\0') {
 151                         continue;
 152                 }
 153                 /* Comment */
 154                 if (line[0] == '#') {
 155                         continue;
 156                 }
 157                 if (isdigit(line[0])) {
 158                         char *p = strchr(line, ':');
 159                         if (!p) {
 160                                 ret.failures++;
 161                                 return ret;
 162                         }
 163                         p[0] = '\0';
 164                         p++;
 165                         oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
 166                         trim_string(line, " ", " ");
 167                         oid_map[num_oid_maps].old_oid = talloc_move(oid_map, &line);
 168                         trim_string(p, " ", " ");
 169                         oid_map[num_oid_maps].new_oid = p;
 170                         num_oid_maps++;
 171                         oid_map[num_oid_maps].old_oid = NULL;
 172                 } else {
 173                         char *p = strchr(line, ':');
 174                         if (p) {
 175                                 /* remap attribute/objectClass */
 176                                 p[0] = '\0';
 177                                 p++;
 178                                 attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2);
 179                                 trim_string(line, " ", " ");
 180                                 attr_map[num_attr_maps].old_attr = talloc_move(attr_map, &line);
 181                                 trim_string(p, " ", " ");
 182                                 attr_map[num_attr_maps].new_attr = p;
 183                                 num_attr_maps++;
 184                                 attr_map[num_attr_maps].old_attr = NULL;
 185                         } else {
 186                                 /* skip attribute/objectClass */
 187                                 attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
 188                                 trim_string(line, " ", " ");
 189                                 attrs_skip[num_skip] = talloc_move(attrs_skip, &line);
 190                                 num_skip++;
 191                                 attrs_skip[num_skip] = NULL;
 192                         }
 193                 }
 194         }
 195 
 196         schemadn = find_schema_dn(ldb, mem_ctx);
 197         if (!schemadn) {
 198                 printf("Failed to find schema DN: %s\n", ldb_errstring(ldb));
 199                 ret.failures = 1;
 200                 return ret;
 201         }
 202         
 203         ldb_ret = dsdb_schema_from_schema_dn(mem_ctx, ldb,
 204                                              lp_iconv_convenience(cmdline_lp_ctx),
 205                                              schemadn, &schema, &error_string);
 206         if (ldb_ret != LDB_SUCCESS) {
 207                 printf("Failed to load schema: %s\n", error_string);
 208                 ret.failures = 1;
 209                 return ret;
 210         }
 211 
 212         switch (target) {
 213         case TARGET_OPENLDAP:
 214                 seperator = "\n  ";
 215                 break;
 216         case TARGET_FEDORA_DS:
 217                 seperator = "\n  ";
 218                 fprintf(out, "dn: cn=schema\n");
 219                 break;
 220         }
 221 
 222         for (attribute=schema->attributes; attribute; attribute = attribute->next) {
 223                 const char *name = attribute->lDAPDisplayName;
 224                 const char *oid = attribute->attributeID_oid;
 225                 const char *syntax = attribute->attributeSyntax_oid;
 226                 const char *equality = NULL, *substring = NULL;
 227                 bool single_value = attribute->isSingleValued;
 228 
 229                 char *schema_entry = NULL;
 230                 int j;
 231 
 232                 /* We have been asked to skip some attributes/objectClasses */
 233                 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
 234                         ret.skipped++;
 235                         continue;
 236                 }
 237 
 238                 /* We might have been asked to remap this oid, due to a conflict */
 239                 for (j=0; oid && oid_map && oid_map[j].old_oid; j++) {
 240                         if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
 241                                 oid =  oid_map[j].new_oid;
 242                                 break;
 243                         }
 244                 }
 245                 
 246                 if (attribute->syntax) {
 247                         /* We might have been asked to remap this oid,
 248                          * due to a conflict, or lack of
 249                          * implementation */
 250                         syntax = attribute->syntax->ldap_oid;
 251                         /* We might have been asked to remap this oid, due to a conflict */
 252                         for (j=0; syntax && oid_map && oid_map[j].old_oid; j++) {
 253                                 if (strcasecmp(syntax, oid_map[j].old_oid) == 0) {
 254                                         syntax =  oid_map[j].new_oid;
 255                                         break;
 256                                 }
 257                         }
 258                         
 259                         equality = attribute->syntax->equality;
 260                         substring = attribute->syntax->substring;
 261                 }
 262 
 263                 /* We might have been asked to remap this name, due to a conflict */
 264                 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
 265                         if (strcasecmp(name, attr_map[j].old_attr) == 0) {
 266                                 name =  attr_map[j].new_attr;
 267                                 break;
 268                         }
 269                 }
 270                 
 271                 schema_entry = schema_attribute_description(mem_ctx, 
 272                                                             target, 
 273                                                             seperator, 
 274                                                             oid, 
 275                                                             name, 
 276                                                             equality, 
 277                                                             substring, 
 278                                                             syntax, 
 279                                                             single_value, 
 280                                                             false,
 281                                                             NULL, NULL,
 282                                                             NULL, NULL,
 283                                                             false, false);
 284 
 285                 if (schema_entry == NULL) {
 286                         ret.failures++;
 287                         return ret;
 288                 }
 289 
 290                 switch (target) {
 291                 case TARGET_OPENLDAP:
 292                         fprintf(out, "attributetype %s\n\n", schema_entry);
 293                         break;
 294                 case TARGET_FEDORA_DS:
 295                         fprintf(out, "attributeTypes: %s\n", schema_entry);
 296                         break;
 297                 }
 298                 ret.count++;
 299         }
 300 
 301         /* This is already sorted to have 'top' and similar classes first */
 302         for (objectclass=schema->classes; objectclass; objectclass = objectclass->next) {
 303                 const char *name = objectclass->lDAPDisplayName;
 304                 const char *oid = objectclass->governsID_oid;
 305                 const char *subClassOf = objectclass->subClassOf;
 306                 int objectClassCategory = objectclass->objectClassCategory;
 307                 const char **must;
 308                 const char **may;
 309                 char *schema_entry = NULL;
 310                 const char *objectclass_name_as_list[] = {
 311                         objectclass->lDAPDisplayName,
 312                         NULL
 313                 };
 314                 int j;
 315                 int attr_idx;
 316                 
 317                 /* We have been asked to skip some attributes/objectClasses */
 318                 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
 319                         ret.skipped++;
 320                         continue;
 321                 }
 322 
 323                 /* We might have been asked to remap this oid, due to a conflict */
 324                 for (j=0; oid_map && oid_map[j].old_oid; j++) {
 325                         if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
 326                                 oid =  oid_map[j].new_oid;
 327                                 break;
 328                         }
 329                 }
 330                 
 331                 /* We might have been asked to remap this name, due to a conflict */
 332                 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
 333                         if (strcasecmp(name, attr_map[j].old_attr) == 0) {
 334                                 name =  attr_map[j].new_attr;
 335                                 break;
 336                         }
 337                 }
 338                 
 339                 may = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MAY);
 340 
 341                 for (j=0; may && may[j]; j++) {
 342                         /* We might have been asked to remap this name, due to a conflict */ 
 343                         for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) { 
 344                                 if (strcasecmp(may[j], attr_map[attr_idx].old_attr) == 0) { 
 345                                         may[j] =  attr_map[attr_idx].new_attr; 
 346                                         break;                          
 347                                 }                                       
 348                         }                                               
 349                 }
 350 
 351                 must = dsdb_full_attribute_list(mem_ctx, schema, objectclass_name_as_list, DSDB_SCHEMA_ALL_MUST);
 352 
 353                 for (j=0; must && must[j]; j++) {
 354                         /* We might have been asked to remap this name, due to a conflict */ 
 355                         for (attr_idx=0; attr_map && attr_map[attr_idx].old_attr; attr_idx++) { 
 356                                 if (strcasecmp(must[j], attr_map[attr_idx].old_attr) == 0) { 
 357                                         must[j] =  attr_map[attr_idx].new_attr; 
 358                                         break;                          
 359                                 }                                       
 360                         }                                               
 361                 }
 362 
 363                 schema_entry = schema_class_description(mem_ctx, target, 
 364                                                         seperator,
 365                                                         oid, 
 366                                                         name,
 367                                                         NULL, 
 368                                                         subClassOf,
 369                                                         objectClassCategory,
 370                                                         must,
 371                                                         may,
 372                                                         NULL);
 373                 if (schema_entry == NULL) {
 374                         ret.failures++;
 375                         return ret;
 376                 }
 377 
 378                 switch (target) {
 379                 case TARGET_OPENLDAP:
 380                         fprintf(out, "objectclass %s\n\n", schema_entry);
 381                         break;
 382                 case TARGET_FEDORA_DS:
 383                         fprintf(out, "objectClasses: %s\n", schema_entry);
 384                         break;
 385                 }
 386                 ret.count++;
 387         }
 388 
 389         return ret;
 390 }
 391 
 392  int main(int argc, const char **argv)
     /* [<][>][^][v][top][bottom][index][help] */
 393 {
 394         TALLOC_CTX *ctx;
 395         struct ldb_cmdline *options;
 396         FILE *in = stdin;
 397         FILE *out = stdout;
 398         struct ldb_context *ldb;
 399         struct schema_conv ret;
 400         const char *target_str;
 401         enum dsdb_schema_convert_target target;
 402 
 403         ctx = talloc_new(NULL);
 404         ldb = ldb_init(ctx, NULL);
 405 
 406         options = ldb_cmdline_process(ldb, argc, argv, usage);
 407 
 408         if (options->input) {
 409                 in = fopen(options->input, "r");
 410                 if (!in) {
 411                         perror(options->input);
 412                         exit(1);
 413                 }
 414         }
 415         if (options->output) {
 416                 out = fopen(options->output, "w");
 417                 if (!out) {
 418                         perror(options->output);
 419                         exit(1);
 420                 }
 421         }
 422 
 423         target_str = lp_parm_string(cmdline_lp_ctx, NULL, "convert", "target");
 424 
 425         if (!target_str || strcasecmp(target_str, "openldap") == 0) {
 426                 target = TARGET_OPENLDAP;
 427         } else if (strcasecmp(target_str, "fedora-ds") == 0) {
 428                 target = TARGET_FEDORA_DS;
 429         } else {
 430                 printf("Unsupported target: %s\n", target_str);
 431                 exit(1);
 432         }
 433 
 434         ret = process_convert(ldb, target, in, out);
 435 
 436         fclose(in);
 437         fclose(out);
 438 
 439         printf("Converted %d records (skipped %d) with %d failures\n", ret.count, ret.skipped, ret.failures);
 440 
 441         return 0;
 442 }

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