dc285df5c8e0f8ef9fba63a25388fd6a903bde6c
[ira/wip.git] / source / lib / ldb / tools / ad2oLschema.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Bartlett 2006
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, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ad2oLschema
29  *
30  *  Description: utility to convert an AD schema into the format required by OpenLDAP
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36 #include "ldb_includes.h"
37 #include "system/locale.h"
38 #include "tools/cmdline.h"
39 #include "tools/convert.h"
40
41 struct schema_conv {
42         int count;
43         int skipped;
44         int failures;
45 };
46
47 enum convert_target {
48         TARGET_OPENLDAP,
49         TARGET_FEDORA_DS
50 };
51         
52
53 static void usage(void)
54 {
55         printf("Usage: ad2oLschema <options>\n");
56         printf("\nConvert AD-like LDIF to OpenLDAP schema format\n\n");
57         printf("Options:\n");
58         printf("  -I inputfile     inputfile of mapped OIDs and skipped attributes/ObjectClasses");
59         printf("  -H url           LDB or LDAP server to read schmea from\n");
60         printf("  -O outputfile    outputfile otherwise STDOUT\n");
61         printf("  -o options       pass options like modules to activate\n");
62         printf("              e.g: -o modules:timestamps\n");
63         printf("\n");
64         printf("Converts records from an AD-like LDIF schema into an openLdap formatted schema\n\n");
65         exit(1);
66 }
67
68 static int fetch_attrs_schema(struct ldb_context *ldb, struct ldb_dn *schemadn,
69                               TALLOC_CTX *mem_ctx, 
70                               struct ldb_result **attrs_res)
71 {
72         TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
73         int ret;
74         const char *attrs[] = {
75                 "lDAPDisplayName",
76                 "isSingleValued",
77                 "attributeID",
78                 "attributeSyntax",
79                 "description",          
80                 NULL
81         };
82
83         if (!local_ctx) {
84                 return LDB_ERR_OPERATIONS_ERROR;
85         }
86         
87         /* Downlaod schema */
88         ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
89                          "objectClass=attributeSchema", 
90                          attrs, attrs_res);
91         if (ret != LDB_SUCCESS) {
92                 printf("Search failed: %s\n", ldb_errstring(ldb));
93                 return LDB_ERR_OPERATIONS_ERROR;
94         }
95         
96         return ret;
97 }
98
99 static const char *oc_attrs[] = {
100         "lDAPDisplayName",
101         "mayContain",
102         "mustContain",
103         "systemMayContain",
104         "systemMustContain",
105         "objectClassCategory",
106         "governsID",
107         "description",
108         "subClassOf",
109         NULL
110 };
111
112 static int fetch_oc_recursive(struct ldb_context *ldb, struct ldb_dn *schemadn, 
113                               TALLOC_CTX *mem_ctx, 
114                               struct ldb_result *search_from,
115                               struct ldb_result *res_list)
116 {
117         int i;
118         int ret = 0;
119         for (i=0; i < search_from->count; i++) {
120                 struct ldb_result *res;
121                 const char *name = ldb_msg_find_attr_as_string(search_from->msgs[i], 
122                                                                "lDAPDisplayname", NULL);
123
124                 ret = ldb_search_exp_fmt(ldb, mem_ctx, &res,
125                                         schemadn, LDB_SCOPE_SUBTREE, oc_attrs,
126                                         "(&(&(objectClass=classSchema)(subClassOf=%s))(!(lDAPDisplayName=%s)))",
127                                         name, name);
128                 if (ret != LDB_SUCCESS) {
129                         printf("Search failed: %s\n", ldb_errstring(ldb));
130                         return ret;
131                 }
132                 
133                 res_list->msgs = talloc_realloc(res_list, res_list->msgs, 
134                                                 struct ldb_message *, res_list->count + 2);
135                 if (!res_list->msgs) {
136                         return LDB_ERR_OPERATIONS_ERROR;
137                 }
138                 res_list->msgs[res_list->count] = talloc_move(res_list, 
139                                                               &search_from->msgs[i]);
140                 res_list->count++;
141                 res_list->msgs[res_list->count] = NULL;
142
143                 if (res->count > 0) {
144                         ret = fetch_oc_recursive(ldb, schemadn, mem_ctx, res, res_list); 
145                 }
146                 if (ret != LDB_SUCCESS) {
147                         return ret;
148                 }
149         }
150         return ret;
151 }
152
153 static int fetch_objectclass_schema(struct ldb_context *ldb, struct ldb_dn *schemadn, 
154                                     TALLOC_CTX *mem_ctx, 
155                                     struct ldb_result **objectclasses_res)
156 {
157         TALLOC_CTX *local_ctx = talloc_new(mem_ctx);
158         struct ldb_result *top_res, *ret_res;
159         int ret;
160         if (!local_ctx) {
161                 return LDB_ERR_OPERATIONS_ERROR;
162         }
163         
164         /* Downlaod 'top' */
165         ret = ldb_search(ldb, schemadn, LDB_SCOPE_SUBTREE, 
166                          "(&(objectClass=classSchema)(lDAPDisplayName=top))", 
167                          oc_attrs, &top_res);
168         if (ret != LDB_SUCCESS) {
169                 printf("Search failed: %s\n", ldb_errstring(ldb));
170                 return LDB_ERR_OPERATIONS_ERROR;
171         }
172
173         talloc_steal(local_ctx, top_res);
174
175         if (top_res->count != 1) {
176                 return LDB_ERR_OPERATIONS_ERROR;
177         }
178
179         ret_res = talloc_zero(local_ctx, struct ldb_result);
180         if (!ret_res) {
181                 return LDB_ERR_OPERATIONS_ERROR;
182         }
183
184         ret = fetch_oc_recursive(ldb, schemadn, local_ctx, top_res, ret_res); 
185
186         if (ret != LDB_SUCCESS) {
187                 printf("Search failed: %s\n", ldb_errstring(ldb));
188                 return LDB_ERR_OPERATIONS_ERROR;
189         }
190
191         *objectclasses_res = talloc_move(mem_ctx, &ret_res);
192         return ret;
193 }
194
195 static struct ldb_dn *find_schema_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx) 
196 {
197         const char *rootdse_attrs[] = {"schemaNamingContext", NULL};
198         const char *no_attrs[] = { NULL };
199         struct ldb_dn *schemadn;
200         struct ldb_dn *basedn = ldb_dn_new(mem_ctx, ldb, NULL);
201         struct ldb_result *rootdse_res;
202         struct ldb_result *schema_res;
203         int ldb_ret;
204         if (!basedn) {
205                 return NULL;
206         }
207         
208         /* Search for rootdse */
209         ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_BASE, NULL, rootdse_attrs, &rootdse_res);
210         if (ldb_ret != LDB_SUCCESS) {
211                 ldb_ret = ldb_search(ldb, basedn, LDB_SCOPE_SUBTREE, 
212                                  "(&(objectClass=dMD)(cn=Schema))", 
213                                  no_attrs, &schema_res);
214                 if (ldb_ret) {
215                         printf("cn=Schema Search failed: %s\n", ldb_errstring(ldb));
216                         return NULL;
217                 }
218
219                 talloc_steal(mem_ctx, schema_res);
220
221                 if (schema_res->count != 1) {
222                         printf("Failed to find rootDSE");
223                         return NULL;
224                 }
225                 
226                 schemadn = talloc_steal(mem_ctx, schema_res->msgs[0]->dn);
227                 talloc_free(schema_res);
228                 return schemadn;
229                 
230         }
231         
232         talloc_steal(mem_ctx, rootdse_res);
233
234         if (rootdse_res->count != 1) {
235                 printf("Failed to find rootDSE");
236                 return NULL;
237         }
238         
239         /* Locate schema */
240         schemadn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, rootdse_res->msgs[0], "schemaNamingContext");
241         if (!schemadn) {
242                 return NULL;
243         }
244
245         talloc_free(rootdse_res);
246         return schemadn;
247 }
248
249 #define IF_NULL_FAIL_RET(x) do {     \
250                 if (!x) {               \
251                         ret.failures++; \
252                         return ret;     \
253                 }                       \
254         } while (0) 
255
256
257 static struct schema_conv process_convert(struct ldb_context *ldb, enum convert_target target, FILE *in, FILE *out) 
258 {
259         /* Read list of attributes to skip, OIDs to map */
260         TALLOC_CTX *mem_ctx = talloc_new(ldb);
261         char *line;
262         const char **attrs_skip = NULL;
263         int num_skip = 0;
264         struct oid_map {
265                 char *old_oid;
266                 char *new_oid;
267         } *oid_map = NULL;
268         int num_oid_maps = 0;
269         struct attr_map {
270                 char *old_attr;
271                 char *new_attr;
272         } *attr_map = NULL;
273         int num_attr_maps = 0;  
274         struct ldb_result *attrs_res, *objectclasses_res;
275         struct ldb_dn *schemadn;
276         struct schema_conv ret;
277
278         int ldb_ret, i;
279
280         ret.count = 0;
281         ret.skipped = 0;
282         ret.failures = 0;
283
284         while ((line = afdgets(fileno(in), mem_ctx, 0))) {
285                 /* Blank Line */
286                 if (line[0] == '\0') {
287                         continue;
288                 }
289                 /* Comment */
290                 if (line[0] == '#') {
291                         continue;
292                 }
293                 if (isdigit(line[0])) {
294                         char *p = strchr(line, ':');
295                         IF_NULL_FAIL_RET(p);
296                         p[0] = '\0';
297                         p++;
298                         oid_map = talloc_realloc(mem_ctx, oid_map, struct oid_map, num_oid_maps + 2);
299                         trim_string(line, " ", " ");
300                         oid_map[num_oid_maps].old_oid = talloc_move(oid_map, &line);
301                         trim_string(p, " ", " ");
302                         oid_map[num_oid_maps].new_oid = p;
303                         num_oid_maps++;
304                         oid_map[num_oid_maps].old_oid = NULL;
305                 } else {
306                         char *p = strchr(line, ':');
307                         if (p) {
308                                 /* remap attribute/objectClass */
309                                 p[0] = '\0';
310                                 p++;
311                                 attr_map = talloc_realloc(mem_ctx, attr_map, struct attr_map, num_attr_maps + 2);
312                                 trim_string(line, " ", " ");
313                                 attr_map[num_attr_maps].old_attr = talloc_move(attr_map, &line);
314                                 trim_string(p, " ", " ");
315                                 attr_map[num_attr_maps].new_attr = p;
316                                 num_attr_maps++;
317                                 attr_map[num_attr_maps].old_attr = NULL;
318                         } else {
319                                 /* skip attribute/objectClass */
320                                 attrs_skip = talloc_realloc(mem_ctx, attrs_skip, const char *, num_skip + 2);
321                                 trim_string(line, " ", " ");
322                                 attrs_skip[num_skip] = talloc_move(attrs_skip, &line);
323                                 num_skip++;
324                                 attrs_skip[num_skip] = NULL;
325                         }
326                 }
327         }
328
329         schemadn = find_schema_dn(ldb, mem_ctx);
330         if (!schemadn) {
331                 printf("Failed to find schema DN: %s\n", ldb_errstring(ldb));
332                 ret.failures = 1;
333                 return ret;
334         }
335         
336         ldb_ret = fetch_attrs_schema(ldb, schemadn, mem_ctx, &attrs_res);
337         if (ldb_ret != LDB_SUCCESS) {
338                 printf("Failed to fetch attribute schema: %s\n", ldb_errstring(ldb));
339                 ret.failures = 1;
340                 return ret;
341         }
342         
343         switch (target) {
344         case TARGET_OPENLDAP:
345                 break;
346         case TARGET_FEDORA_DS:
347                 fprintf(out, "dn: cn=schema\n");
348                 break;
349         }
350
351         for (i=0; i < attrs_res->count; i++) {
352                 struct ldb_message *msg = attrs_res->msgs[i];
353
354                 const char *name = ldb_msg_find_attr_as_string(msg, "lDAPDisplayName", NULL);
355                 const char *description = ldb_msg_find_attr_as_string(msg, "description", NULL);
356                 const char *oid = ldb_msg_find_attr_as_string(msg, "attributeID", NULL);
357                 const char *syntax = ldb_msg_find_attr_as_string(msg, "attributeSyntax", NULL);
358                 BOOL single_value = ldb_msg_find_attr_as_bool(msg, "isSingleValued", False);
359                 const struct syntax_map *map = find_syntax_map_by_ad_oid(syntax);
360                 char *schema_entry = NULL;
361                 int j;
362
363                 if (!name) {
364                         printf("Failed to find lDAPDisplayName for schema DN: %s\n", ldb_dn_get_linearized(msg->dn));
365                         ret.failures++;
366                         continue;
367                 }
368
369                 /* We have been asked to skip some attributes/objectClasses */
370                 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
371                         ret.skipped++;
372                         continue;
373                 }
374
375                 /* We might have been asked to remap this oid, due to a conflict */
376                 for (j=0; oid && oid_map && oid_map[j].old_oid; j++) {
377                         if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
378                                 oid =  oid_map[j].new_oid;
379                                 break;
380                         }
381                 }
382                 
383                 switch (target) {
384                 case TARGET_OPENLDAP:
385                         schema_entry = talloc_asprintf(mem_ctx, 
386                                                        "attributetype (\n"
387                                                        "  %s\n", oid);
388                         break;
389                 case TARGET_FEDORA_DS:
390                         schema_entry = talloc_asprintf(mem_ctx, 
391                                                        "attributeTypes: (\n"
392                                                        "  %s\n", oid);
393                         break;
394                 }
395                 IF_NULL_FAIL_RET(schema_entry);
396
397                 /* We might have been asked to remap this name, due to a conflict */
398                 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
399                         if (strcasecmp(name, attr_map[j].old_attr) == 0) {
400                                 name =  attr_map[j].new_attr;
401                                 break;
402                         }
403                 }
404                 
405                 schema_entry = talloc_asprintf_append(schema_entry, 
406                                                       "  NAME '%s'\n", name);
407                 IF_NULL_FAIL_RET(schema_entry);
408
409                 if (description) {
410                         schema_entry = talloc_asprintf_append(schema_entry, 
411                                                               "  DESC %s\n", description);
412                         IF_NULL_FAIL_RET(schema_entry);
413                 }
414
415                 if (map) {
416                         const char *syntax_oid;
417                         if (map->equality) {
418                                 schema_entry = talloc_asprintf_append(schema_entry, 
419                                                                       "  EQUALITY %s\n", map->equality);
420                                 IF_NULL_FAIL_RET(schema_entry);
421                         }
422                         if (map->substring) {
423                                 schema_entry = talloc_asprintf_append(schema_entry, 
424                                                                       "  SUBSTR %s\n", map->substring);
425                                 IF_NULL_FAIL_RET(schema_entry);
426                         }
427                         syntax_oid = map->Standard_OID;
428                         /* We might have been asked to remap this oid,
429                          * due to a conflict, or lack of
430                          * implementation */
431                         for (j=0; syntax_oid && oid_map[j].old_oid; j++) {
432                                 if (strcasecmp(syntax_oid, oid_map[j].old_oid) == 0) {
433                                         syntax_oid =  oid_map[j].new_oid;
434                                         break;
435                                 }
436                         }
437                         schema_entry = talloc_asprintf_append(schema_entry, 
438                                                               "  SYNTAX %s\n", syntax_oid);
439                         IF_NULL_FAIL_RET(schema_entry);
440                 }
441
442                 if (single_value) {
443                         schema_entry = talloc_asprintf_append(schema_entry, 
444                                                               "  SINGLE-VALUE\n");
445                         IF_NULL_FAIL_RET(schema_entry);
446                 }
447                 
448                 schema_entry = talloc_asprintf_append(schema_entry, 
449                                                       "  )");
450
451                 switch (target) {
452                 case TARGET_OPENLDAP:
453                         fprintf(out, "%s\n\n", schema_entry);
454                         break;
455                 case TARGET_FEDORA_DS:
456                         fprintf(out, "%s\n", schema_entry);
457                         break;
458                 }
459                 ret.count++;
460         }
461
462         ldb_ret = fetch_objectclass_schema(ldb, schemadn, mem_ctx, &objectclasses_res);
463         if (ldb_ret != LDB_SUCCESS) {
464                 printf("Failed to fetch objectClass schema elements: %s\n", ldb_errstring(ldb));
465                 ret.failures = 1;
466                 return ret;
467         }
468         
469         for (i=0; i < objectclasses_res->count; i++) {
470                 struct ldb_message *msg = objectclasses_res->msgs[i];
471                 const char *name = ldb_msg_find_attr_as_string(msg, "lDAPDisplayName", NULL);
472                 const char *description = ldb_msg_find_attr_as_string(msg, "description", NULL);
473                 const char *oid = ldb_msg_find_attr_as_string(msg, "governsID", NULL);
474                 const char *subClassOf = ldb_msg_find_attr_as_string(msg, "subClassOf", NULL);
475                 int objectClassCategory = ldb_msg_find_attr_as_int(msg, "objectClassCategory", 0);
476                 struct ldb_message_element *must = ldb_msg_find_element(msg, "mustContain");
477                 struct ldb_message_element *sys_must = ldb_msg_find_element(msg, "systemMustContain");
478                 struct ldb_message_element *may = ldb_msg_find_element(msg, "mayContain");
479                 struct ldb_message_element *sys_may = ldb_msg_find_element(msg, "systemMayContain");
480                 char *schema_entry = NULL;
481                 int j;
482
483                 if (!name) {
484                         printf("Failed to find lDAPDisplayName for schema DN: %s\n", ldb_dn_get_linearized(msg->dn));
485                         ret.failures++;
486                         continue;
487                 }
488
489                 /* We have been asked to skip some attributes/objectClasses */
490                 if (attrs_skip && str_list_check_ci(attrs_skip, name)) {
491                         ret.skipped++;
492                         continue;
493                 }
494
495                 /* We might have been asked to remap this oid, due to a conflict */
496                 for (j=0; oid_map[j].old_oid; j++) {
497                         if (strcasecmp(oid, oid_map[j].old_oid) == 0) {
498                                 oid =  oid_map[j].new_oid;
499                                 break;
500                         }
501                 }
502                 
503                 switch (target) {
504                 case TARGET_OPENLDAP:
505                         schema_entry = talloc_asprintf(mem_ctx, 
506                                                        "objectclass (\n"
507                                                        "  %s\n", oid);
508                         break;
509                 case TARGET_FEDORA_DS:
510                         schema_entry = talloc_asprintf(mem_ctx, 
511                                                        "objectClasses: (\n"
512                                                        "  %s\n", oid);
513                         break;
514                 }
515                 IF_NULL_FAIL_RET(schema_entry);
516                 if (!schema_entry) {
517                         ret.failures++;
518                         break;
519                 }
520
521                 /* We might have been asked to remap this name, due to a conflict */
522                 for (j=0; name && attr_map && attr_map[j].old_attr; j++) {
523                         if (strcasecmp(name, attr_map[j].old_attr) == 0) {
524                                 name =  attr_map[j].new_attr;
525                                 break;
526                         }
527                 }
528                 
529                 schema_entry = talloc_asprintf_append(schema_entry, 
530                                                       "  NAME '%s'\n", name);
531                 IF_NULL_FAIL_RET(schema_entry);
532
533                 if (!schema_entry) return ret;
534
535                 if (description) {
536                         schema_entry = talloc_asprintf_append(schema_entry, 
537                                                               "  DESC %s\n", description);
538                         IF_NULL_FAIL_RET(schema_entry);
539                 }
540
541                 if (subClassOf) {
542                         schema_entry = talloc_asprintf_append(schema_entry, 
543                                                               "  SUP %s\n", subClassOf);
544                         IF_NULL_FAIL_RET(schema_entry);
545                 }
546                 
547                 switch (objectClassCategory) {
548                 case 1:
549                         schema_entry = talloc_asprintf_append(schema_entry, 
550                                                               "  STRUCTURAL\n");
551                         IF_NULL_FAIL_RET(schema_entry);
552                         break;
553                 case 2:
554                         schema_entry = talloc_asprintf_append(schema_entry, 
555                                                               "  ABSTRACT\n");
556                         IF_NULL_FAIL_RET(schema_entry);
557                         break;
558                 case 3:
559                         schema_entry = talloc_asprintf_append(schema_entry, 
560                                                               "  AUXILIARY\n");
561                         IF_NULL_FAIL_RET(schema_entry);
562                         break;
563                 }
564
565 #define APPEND_ATTRS(attributes) \
566                 do {                                            \
567                         int k;                                          \
568                         for (k=0; attributes && k < attributes->num_values; k++) { \
569                                 int attr_idx; \
570                                 const char *attr_name = (const char *)attributes->values[k].data;  \
571                                 /* We might have been asked to remap this name, due to a conflict */ \
572                                 for (attr_idx=0; attr_name && attr_map && attr_map[attr_idx].old_attr; attr_idx++) { \
573                                         if (strcasecmp(attr_name, attr_map[attr_idx].old_attr) == 0) { \
574                                                 attr_name =  attr_map[attr_idx].new_attr; \
575                                                 break;                  \
576                                         }                               \
577                                 }                                       \
578                                                                         \
579                                 schema_entry = talloc_asprintf_append(schema_entry, \
580                                                                       " %s", \
581                                                                       attr_name); \
582                                 IF_NULL_FAIL_RET(schema_entry);         \
583                                 if (k != (attributes->num_values - 1)) { \
584                                         schema_entry = talloc_asprintf_append(schema_entry, \
585                                                                               " $"); \
586                                         IF_NULL_FAIL_RET(schema_entry); \
587                                         if (target == TARGET_OPENLDAP && ((k+1)%5 == 0)) { \
588                                                 schema_entry = talloc_asprintf_append(schema_entry, \
589                                                                                       "\n  "); \
590                                                 IF_NULL_FAIL_RET(schema_entry); \
591                                         }                               \
592                                 }                                       \
593                         }                                               \
594                 } while (0)
595
596                 if (must || sys_must) {
597                         schema_entry = talloc_asprintf_append(schema_entry, 
598                                                               "  MUST (");
599                         IF_NULL_FAIL_RET(schema_entry);
600
601                         APPEND_ATTRS(must);
602                         if (must && sys_must) {
603                                 schema_entry = talloc_asprintf_append(schema_entry, \
604                                                                       " $"); \
605                         }
606                         APPEND_ATTRS(sys_must);
607                         
608                         schema_entry = talloc_asprintf_append(schema_entry, 
609                                                               " )\n");
610                         IF_NULL_FAIL_RET(schema_entry);
611                 }
612
613                 if (may || sys_may) {
614                         schema_entry = talloc_asprintf_append(schema_entry, 
615                                                               "  MAY (");
616                         IF_NULL_FAIL_RET(schema_entry);
617
618                         APPEND_ATTRS(may);
619                         if (may && sys_may) {
620                                 schema_entry = talloc_asprintf_append(schema_entry, \
621                                                                       " $"); \
622                         }
623                         APPEND_ATTRS(sys_may);
624                         
625                         schema_entry = talloc_asprintf_append(schema_entry, 
626                                                               " )\n");
627                         IF_NULL_FAIL_RET(schema_entry);
628                 }
629
630                 schema_entry = talloc_asprintf_append(schema_entry, 
631                                                       "  )");
632
633                 switch (target) {
634                 case TARGET_OPENLDAP:
635                         fprintf(out, "%s\n\n", schema_entry);
636                         break;
637                 case TARGET_FEDORA_DS:
638                         fprintf(out, "%s\n", schema_entry);
639                         break;
640                 }
641                 ret.count++;
642         }
643
644         return ret;
645 }
646
647  int main(int argc, const char **argv)
648 {
649         TALLOC_CTX *ctx;
650         struct ldb_cmdline *options;
651         FILE *in = stdin;
652         FILE *out = stdout;
653         struct ldb_context *ldb;
654         struct schema_conv ret;
655         const char *target_str;
656         enum convert_target target;
657
658         ldb_global_init();
659
660         ctx = talloc_new(NULL);
661         ldb = ldb_init(ctx);
662
663         options = ldb_cmdline_process(ldb, argc, argv, usage);
664
665         if (options->input) {
666                 in = fopen(options->input, "r");
667                 if (!in) {
668                         perror(options->input);
669                         exit(1);
670                 }
671         }
672         if (options->output) {
673                 out = fopen(options->output, "w");
674                 if (!out) {
675                         perror(options->output);
676                         exit(1);
677                 }
678         }
679
680         target_str = lp_parm_string(-1, "convert", "target");
681
682         if (!target_str || strcasecmp(target_str, "openldap") == 0) {
683                 target = TARGET_OPENLDAP;
684         } else if (strcasecmp(target_str, "fedora-ds") == 0) {
685                 target = TARGET_FEDORA_DS;
686         } else {
687                 printf("Unsupported target: %s\n", target_str);
688                 exit(1);
689         }
690
691         ret = process_convert(ldb, target, in, out);
692
693         fclose(in);
694         fclose(out);
695
696         printf("Converted %d records (skipped %d) with %d failures\n", ret.count, ret.skipped, ret.failures);
697
698         return 0;
699 }