4 Copyright (C) Simo Sorce 2005
6 ** NOTE! The following LGPL license applies to the ldb
7 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
27 * Component: oLschema2ldif
29 * Description: utility to convert an OpenLDAP schema into AD LDIF
36 #include "tools/cmdline.h"
37 #include "dsdb/samdb/samdb.h"
39 #define SCHEMA_UNKNOWN 0
42 #define SCHEMA_STRUCTURAL 3
43 #define SCHEMA_ABSTRACT 4
44 #define SCHEMA_AUXILIARY 5
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
64 struct ldb_context
*ldb_ctx
;
65 struct ldb_dn
*basedn
;
67 static int check_braces(const char *string
)
73 if ((c
= strchr(string
, '(')) == NULL
) {
80 if (c
== NULL
) return 1;
88 static char *skip_spaces(char *string
) {
89 return (string
+ strspn(string
, " \t\n"));
92 static int add_multi_string(struct ldb_message
*msg
, const char *attr
, char *values
)
98 c
= skip_spaces(values
);
100 n
= strcspn(c
, " \t$");
101 s
= talloc_strndup(msg
, c
, n
);
102 if (ldb_msg_add_string(msg
, attr
, s
) != 0) {
106 c
+= strspn(c
, " \t$");
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)
115 static char *get_def_value(TALLOC_CTX
*ctx
, char **string
)
123 n
= strcspn(c
, "\'");
124 value
= talloc_strndup(ctx
, c
, n
);
126 c
++; /* skip closing \' */
128 n
= strcspn(c
, " \t\n");
129 value
= talloc_strndup(ctx
, c
, n
);
137 static struct schema_token
*get_next_schema_token(TALLOC_CTX
*ctx
, char **string
)
139 char *c
= skip_spaces(*string
);
141 struct schema_token
*token
;
144 token
= talloc(ctx
, struct schema_token
);
146 n
= strcspn(c
, " \t\n");
147 type
= talloc_strndup(token
, c
, n
);
151 if (strcasecmp("NAME", type
) == 0) {
153 token
->type
= SCHEMA_NAME
;
154 /* we do not support aliases so we get only the first name given and skip others */
156 char *s
= strchr(c
, ')');
157 if (s
== NULL
) return NULL
;
165 token
->value
= get_def_value(ctx
, &c
);
167 if (*string
< c
) { /* single name */
173 if (strcasecmp("SUP", type
) == 0) {
175 token
->type
= SCHEMA_SUP
;
180 token
->value
= talloc_strndup(ctx
, c
, n
);
184 token
->value
= get_def_value(ctx
, &c
);
192 if (strcasecmp("STRUCTURAL", type
) == 0) {
194 token
->type
= SCHEMA_STRUCTURAL
;
199 if (strcasecmp("ABSTRACT", type
) == 0) {
201 token
->type
= SCHEMA_ABSTRACT
;
206 if (strcasecmp("AUXILIARY", type
) == 0) {
208 token
->type
= SCHEMA_AUXILIARY
;
213 if (strcasecmp("MUST", type
) == 0) {
215 token
->type
= SCHEMA_MUST
;
220 token
->value
= talloc_strndup(ctx
, c
, n
);
224 token
->value
= get_def_value(ctx
, &c
);
232 if (strcasecmp("MAY", type
) == 0) {
234 token
->type
= SCHEMA_MAY
;
239 token
->value
= talloc_strndup(ctx
, c
, n
);
243 token
->value
= get_def_value(ctx
, &c
);
251 if (strcasecmp("SINGLE-VALUE", type
) == 0) {
253 token
->type
= SCHEMA_SINGLE_VALUE
;
258 if (strcasecmp("EQUALITY", type
) == 0) {
260 token
->type
= SCHEMA_EQUALITY
;
262 token
->value
= get_def_value(ctx
, &c
);
269 if (strcasecmp("ORDERING", type
) == 0) {
271 token
->type
= SCHEMA_ORDERING
;
273 token
->value
= get_def_value(ctx
, &c
);
280 if (strcasecmp("SUBSTR", type
) == 0) {
282 token
->type
= SCHEMA_SUBSTR
;
284 token
->value
= get_def_value(ctx
, &c
);
291 if (strcasecmp("SYNTAX", type
) == 0) {
293 token
->type
= SCHEMA_SYNTAX
;
295 token
->value
= get_def_value(ctx
, &c
);
302 if (strcasecmp("DESC", type
) == 0) {
304 token
->type
= SCHEMA_DESC
;
306 token
->value
= get_def_value(ctx
, &c
);
313 token
->type
= SCHEMA_UNKNOWN
;
320 c
= strchr(++c
, '\'');
323 c
+= strcspn(c
, " \t\n");
331 static struct ldb_message
*process_entry(TALLOC_CTX
*mem_ctx
, const char *entry
)
334 struct ldb_message
*msg
;
335 struct schema_token
*token
;
339 ctx
= talloc_new(mem_ctx
);
340 msg
= ldb_msg_new(ctx
);
342 ldb_msg_add_string(msg
, "objectClass", "top");
344 c
= talloc_strdup(ctx
, entry
);
351 if (strncmp(c
, "attributetype", 13) == 0) {
353 MSG_ADD_STRING("objectClass", "attributeSchema");
358 if (strncmp(c
, "objectclass", 11) == 0) {
360 MSG_ADD_STRING("objectClass", "classSchema");
369 if (c
== NULL
) goto failed
;
374 /* get attributeID */
375 n
= strcspn(c
, " \t");
376 s
= talloc_strndup(msg
, c
, n
);
377 MSG_ADD_STRING("attributeID", s
);
382 token
= get_next_schema_token(msg
, &c
);
383 if (!token
) goto failed
;
385 switch (token
->type
) {
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
);
395 MSG_ADD_M_STRING("subClassOf", token
->value
);
398 case SCHEMA_STRUCTURAL
:
399 MSG_ADD_STRING("objectClassCategory", "1");
402 case SCHEMA_ABSTRACT
:
403 MSG_ADD_STRING("objectClassCategory", "2");
406 case SCHEMA_AUXILIARY
:
407 MSG_ADD_STRING("objectClassCategory", "3");
411 MSG_ADD_M_STRING("mustContain", token
->value
);
415 MSG_ADD_M_STRING("mayContain", token
->value
);
418 case SCHEMA_SINGLE_VALUE
:
419 MSG_ADD_STRING("isSingleValued", "TRUE");
422 case SCHEMA_EQUALITY
:
426 case SCHEMA_ORDERING
:
436 const struct dsdb_syntax
*map
=
437 find_syntax_map_by_standard_oid(token
->value
);
441 MSG_ADD_STRING("attributeSyntax", map
->attributeSyntax_oid
);
445 MSG_ADD_STRING("description", token
->value
);
449 fprintf(stderr
, "Unknown Definition: %s\n", token
->value
);
453 talloc_steal(mem_ctx
, msg
);
462 static struct schema_conv
process_file(FILE *in
, FILE *out
)
465 struct schema_conv ret
;
468 struct ldb_ldif ldif
;
470 ldif
.changetype
= LDB_CHANGETYPE_NONE
;
472 ctx
= talloc_new(NULL
);
478 while ((c
= fgetc(in
)) != EOF
) {
480 /* fprintf(stderr, "Parsing line %d\n", line); */
484 } while (c
!= EOF
&& c
!= '\n');
492 entry
= talloc_array(ctx
, char, 1024);
493 if (entry
== NULL
) exit(-1);
498 if (check_braces(entry
) == 0) {
500 ldif
.msg
= process_entry(ctx
, entry
);
501 if (ldif
.msg
== NULL
) {
503 fprintf(stderr
, "No valid msg from entry \n[%s]\n at line %d\n", entry
, line
);
506 ldb_ldif_write_file(ldb_ctx
, out
, &ldif
);
514 if ((t
% 1023) == 0) {
515 entry
= talloc_realloc(ctx
, entry
, char, t
+ 1024);
516 if (entry
== NULL
) exit(-1);
518 } while ((c
= fgetc(in
)) != EOF
);
522 if (check_braces(entry
) == 0) {
524 ldif
.msg
= process_entry(ctx
, entry
);
525 if (ldif
.msg
== NULL
) {
527 fprintf(stderr
, "No valid msg from entry \n[%s]\n at line %d\n", entry
, line
);
530 ldb_ldif_write_file(ldb_ctx
, out
, &ldif
);
532 fprintf(stderr
, "malformed entry on line %d\n", line
);
543 static void usage(void)
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");
553 printf("Converts records from an openLdap formatted schema to an ldif schema\n\n");
557 int main(int argc
, const char **argv
)
560 struct schema_conv ret
;
561 struct ldb_cmdline
*options
;
564 ctx
= talloc_new(NULL
);
565 ldb_ctx
= ldb_init(ctx
, NULL
);
567 setenv("LDB_URL", "NONE", 1);
568 options
= ldb_cmdline_process(ldb_ctx
, argc
, argv
, usage
);
570 if (options
->basedn
== NULL
) {
571 perror("Base DN not specified");
574 basedn
= ldb_dn_new(ctx
, ldb_ctx
, options
->basedn
);
575 if ( ! ldb_dn_validate(basedn
)) {
576 perror("Malformed Base DN");
581 if (options
->input
) {
582 in
= fopen(options
->input
, "r");
584 perror(options
->input
);
588 if (options
->output
) {
589 out
= fopen(options
->output
, "w");
591 perror(options
->output
);
596 ret
= process_file(in
, out
);
601 printf("Converted %d records with %d failures\n", ret
.count
, ret
.failures
);