s4:utils/oLschema2ldif.c - remove (now) unused variables
[samba.git] / source4 / utils / oLschema2ldif.c
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 #include "../lib/crypto/sha256.h"
39 #include "../librpc/gen_ndr/ndr_misc.h"
40
41 #define SCHEMA_UNKNOWN 0
42 #define SCHEMA_NAME 1
43 #define SCHEMA_SUP 2
44 #define SCHEMA_STRUCTURAL 3
45 #define SCHEMA_ABSTRACT 4
46 #define SCHEMA_AUXILIARY 5
47 #define SCHEMA_MUST 6
48 #define SCHEMA_MAY 7
49 #define SCHEMA_SINGLE_VALUE 8
50 #define SCHEMA_EQUALITY 9
51 #define SCHEMA_ORDERING 10
52 #define SCHEMA_SUBSTR 11
53 #define SCHEMA_SYNTAX 12
54 #define SCHEMA_DESC 13
55
56 struct schema_conv {
57         int count;
58         int failures;
59 };
60
61 struct schema_token {
62         int type;
63         char *value;
64 };
65
66 struct ldb_context *ldb_ctx;
67 struct ldb_dn *basedn;
68
69 static int check_braces(const char *string)
70 {
71         int b;
72         char *c;
73
74         b = 0;
75         if ((c = strchr(string, '(')) == NULL) {
76                 return -1;
77         }
78         b++;
79         c++;
80         while (b) {
81                 c = strpbrk(c, "()");
82                 if (c == NULL) return 1;
83                 if (*c == '(') b++;
84                 if (*c == ')') b--;
85                 c++;
86         }
87         return 0;
88 }
89
90 static char *skip_spaces(char *string) {
91         return (string + strspn(string, " \t\n"));
92 }
93
94 static int add_multi_string(struct ldb_message *msg, const char *attr, char *values)
95 {
96         char *c;
97         char *s;
98         int n;
99
100         c = skip_spaces(values);
101         while (*c) {
102                 n = strcspn(c, " \t$");
103                 s = talloc_strndup(msg, c, n);
104                 if (ldb_msg_add_string(msg, attr, s) != 0) {
105                         return -1;
106                 }
107                 c += n;
108                 c += strspn(c, " \t$");
109         }
110
111         return 0;
112 }
113
114 #define MSG_ADD_STRING(a, v) do { if (ldb_msg_add_string(msg, a, v) != 0) goto failed; } while(0)
115 #define MSG_ADD_M_STRING(a, v) do { if (add_multi_string(msg, a, v) != 0) goto failed; } while(0)
116
117 static char *get_def_value(TALLOC_CTX *ctx, char **string)
118 {
119         char *c = *string;
120         char *value;
121         int n;
122
123         if (*c == '\'') {
124                 c++;
125                 n = strcspn(c, "\'");
126                 value = talloc_strndup(ctx, c, n);
127                 c += n;
128                 c++; /* skip closing \' */
129         } else {
130                 n = strcspn(c, " \t\n");
131                 value = talloc_strndup(ctx, c, n);
132                 c += n;
133         }
134         *string = c;
135
136         return value;
137 }
138
139 static struct schema_token *get_next_schema_token(TALLOC_CTX *ctx, char **string)
140 {
141         char *c = skip_spaces(*string);
142         char *type;
143         struct schema_token *token;
144         int n;
145
146         token = talloc(ctx, struct schema_token);
147
148         n = strcspn(c, " \t\n");
149         type = talloc_strndup(token, c, n);
150         c += n;
151         c = skip_spaces(c);
152
153         if (strcasecmp("NAME", type) == 0) {
154                 talloc_free(type);
155                 token->type = SCHEMA_NAME;
156                 /* we do not support aliases so we get only the first name given and skip others */
157                 if (*c == '(') {
158                         char *s = strchr(c, ')');
159                         if (s == NULL) return NULL;
160                         s = skip_spaces(s);
161                         *string = s;
162
163                         c++;
164                         c = skip_spaces(c);
165                 }
166
167                 token->value = get_def_value(ctx, &c);
168
169                 if (*string < c) { /* single name */
170                         c = skip_spaces(c);
171                         *string = c;
172                 }
173                 return token;
174         }
175         if (strcasecmp("SUP", type) == 0) {
176                 talloc_free(type);
177                 token->type = SCHEMA_SUP;
178
179                 if (*c == '(') {
180                         c++;
181                         n = strcspn(c, ")");
182                         token->value = talloc_strndup(ctx, c, n);
183                         c += n;
184                         c++;
185                 } else {
186                         token->value = get_def_value(ctx, &c);
187                 }
188
189                 c = skip_spaces(c);
190                 *string = c;
191                 return token;
192         }
193
194         if (strcasecmp("STRUCTURAL", type) == 0) {
195                 talloc_free(type);
196                 token->type = SCHEMA_STRUCTURAL;
197                 *string = c;
198                 return token;
199         }
200
201         if (strcasecmp("ABSTRACT", type) == 0) {
202                 talloc_free(type);
203                 token->type = SCHEMA_ABSTRACT;
204                 *string = c;
205                 return token;
206         }
207
208         if (strcasecmp("AUXILIARY", type) == 0) {
209                 talloc_free(type);
210                 token->type = SCHEMA_AUXILIARY;
211                 *string = c;
212                 return token;
213         }
214
215         if (strcasecmp("MUST", type) == 0) {
216                 talloc_free(type);
217                 token->type = SCHEMA_MUST;
218
219                 if (*c == '(') {
220                         c++;
221                         n = strcspn(c, ")");
222                         token->value = talloc_strndup(ctx, c, n);
223                         c += n;
224                         c++;
225                 } else {
226                         token->value = get_def_value(ctx, &c);
227                 }
228
229                 c = skip_spaces(c);
230                 *string = c;
231                 return token;
232         }
233
234         if (strcasecmp("MAY", type) == 0) {
235                 talloc_free(type);
236                 token->type = SCHEMA_MAY;
237
238                 if (*c == '(') {
239                         c++;
240                         n = strcspn(c, ")");
241                         token->value = talloc_strndup(ctx, c, n);
242                         c += n;
243                         c++;
244                 } else {
245                         token->value = get_def_value(ctx, &c);
246                 }
247
248                 c = skip_spaces(c);
249                 *string = c;
250                 return token;
251         }
252
253         if (strcasecmp("SINGLE-VALUE", type) == 0) {
254                 talloc_free(type);
255                 token->type = SCHEMA_SINGLE_VALUE;
256                 *string = c;
257                 return token;
258         }
259
260         if (strcasecmp("EQUALITY", type) == 0) {
261                 talloc_free(type);
262                 token->type = SCHEMA_EQUALITY;
263
264                 token->value = get_def_value(ctx, &c);
265
266                 c = skip_spaces(c);
267                 *string = c;
268                 return token;
269         }
270
271         if (strcasecmp("ORDERING", type) == 0) {
272                 talloc_free(type);
273                 token->type = SCHEMA_ORDERING;
274
275                 token->value = get_def_value(ctx, &c);
276
277                 c = skip_spaces(c);
278                 *string = c;
279                 return token;
280         }
281
282         if (strcasecmp("SUBSTR", type) == 0) {
283                 talloc_free(type);
284                 token->type = SCHEMA_SUBSTR;
285
286                 token->value = get_def_value(ctx, &c);
287
288                 c = skip_spaces(c);
289                 *string = c;
290                 return token;
291         }
292
293         if (strcasecmp("SYNTAX", type) == 0) {
294                 talloc_free(type);
295                 token->type = SCHEMA_SYNTAX;
296
297                 token->value = get_def_value(ctx, &c);
298
299                 c = skip_spaces(c);
300                 *string = c;
301                 return token;
302         }
303
304         if (strcasecmp("DESC", type) == 0) {
305                 talloc_free(type);
306                 token->type = SCHEMA_DESC;
307
308                 token->value = get_def_value(ctx, &c);
309
310                 c = skip_spaces(c);
311                 *string = c;
312                 return token;
313         }
314
315         token->type = SCHEMA_UNKNOWN;
316         token->value = type;
317         if (*c == ')') {
318                 *string = c;
319                 return token;
320         }
321         if (*c == '\'') {
322                 c = strchr(++c, '\'');
323                 c++;
324         } else {
325                 c += strcspn(c, " \t\n");
326         }
327         c = skip_spaces(c);
328         *string = c;
329
330         return token;
331 }
332
333 static struct ldb_message *process_entry(TALLOC_CTX *mem_ctx, const char *entry)
334 {
335         TALLOC_CTX *ctx;
336         struct ldb_message *msg;
337         struct schema_token *token;
338         char *c, *s;
339         int n;
340
341         SHA256_CTX sha256_context;
342         uint8_t digest[SHA256_DIGEST_LENGTH];
343
344         struct GUID guid;
345
346         bool isAttribute = false;
347         bool single_valued = false;
348
349         ctx = talloc_new(mem_ctx);
350         msg = ldb_msg_new(ctx);
351
352         ldb_msg_add_string(msg, "objectClass", "top");
353
354         c = talloc_strdup(ctx, entry);
355         if (!c) return NULL;
356
357         c = skip_spaces(c);
358
359         switch (*c) {
360         case 'a':
361                 if (strncmp(c, "attributetype", 13) == 0) {
362                         c += 13;
363                         MSG_ADD_STRING("objectClass", "attributeSchema");
364                         isAttribute = true;
365                         break;
366                 }
367                 goto failed;
368         case 'o':
369                 if (strncmp(c, "objectclass", 11) == 0) {
370                         c += 11;
371                         MSG_ADD_STRING("objectClass", "classSchema");
372                         break;
373                 }
374                 goto failed;
375         default:
376                 goto failed;
377         }
378
379         c = strchr(c, '(');
380         if (c == NULL) goto failed;
381         c++;
382
383         c = skip_spaces(c);
384
385         /* get attributeID */
386         n = strcspn(c, " \t");
387         s = talloc_strndup(msg, c, n);
388         if (isAttribute) {
389                 MSG_ADD_STRING("attributeID", s);
390         } else {
391                 MSG_ADD_STRING("governsID", s);
392         }
393
394         SHA256_Init(&sha256_context);
395         SHA256_Update(&sha256_context, (uint8_t*)s, strlen(s));
396         SHA256_Final(digest, &sha256_context);
397
398         memcpy(&guid, digest, sizeof(struct GUID));
399
400         if (dsdb_msg_add_guid(msg, &guid, "schemaIdGuid") != 0) {
401                 goto failed;
402         }
403
404         c += n;
405         c = skip_spaces(c);     
406
407         while (*c != ')') {
408                 token = get_next_schema_token(msg, &c);
409                 if (!token) goto failed;
410
411                 switch (token->type) {
412                 case SCHEMA_NAME:
413                         MSG_ADD_STRING("cn", token->value);
414                         MSG_ADD_STRING("name", token->value);
415                         MSG_ADD_STRING("lDAPDisplayName", token->value);
416                         msg->dn = ldb_dn_copy(msg, basedn);
417                         ldb_dn_add_child_fmt(msg->dn, "CN=%s,CN=Schema,CN=Configuration", token->value);
418                         break;
419
420                 case SCHEMA_SUP:
421                         MSG_ADD_M_STRING("subClassOf", token->value);
422                         break;
423
424                 case SCHEMA_STRUCTURAL:
425                         MSG_ADD_STRING("objectClassCategory", "1");
426                         break;
427
428                 case SCHEMA_ABSTRACT:
429                         MSG_ADD_STRING("objectClassCategory", "2");
430                         break;
431
432                 case SCHEMA_AUXILIARY:
433                         MSG_ADD_STRING("objectClassCategory", "3");
434                         break;
435
436                 case SCHEMA_MUST:
437                         MSG_ADD_M_STRING("mustContain", token->value);
438                         break;
439
440                 case SCHEMA_MAY:
441                         MSG_ADD_M_STRING("mayContain", token->value);
442                         break;
443
444                 case SCHEMA_SINGLE_VALUE:
445                         single_valued = true;
446                         break;
447
448                 case SCHEMA_EQUALITY:
449                         /* TODO */
450                         break;
451
452                 case SCHEMA_ORDERING:
453                         /* TODO */
454                         break;
455
456                 case SCHEMA_SUBSTR:
457                         /* TODO */
458                         break;
459
460                 case SCHEMA_SYNTAX:
461                 {
462                         char *syntax_oid;
463                         const struct dsdb_syntax *map;
464                         char *oMSyntax;
465
466                         n = strcspn(token->value, "{");
467                         syntax_oid = talloc_strndup(ctx, token->value, n);
468
469                         map = find_syntax_map_by_standard_oid(syntax_oid);
470                         if (!map) {
471                                 break;
472                         }
473
474                         MSG_ADD_STRING("attributeSyntax", map->attributeSyntax_oid);
475
476                         oMSyntax = talloc_asprintf(msg, "%d", map->oMSyntax);
477                         MSG_ADD_STRING("oMSyntax", oMSyntax);
478
479                         break;
480                 }
481                 case SCHEMA_DESC:
482                         MSG_ADD_STRING("description", token->value);
483                         break;
484
485                 default:
486                         fprintf(stderr, "Unknown Definition: %s\n", token->value);
487                 }
488         }
489
490         if (isAttribute) {
491                 MSG_ADD_STRING("isSingleValued", single_valued ? "TRUE" : "FALSE");
492         } else {
493                 MSG_ADD_STRING("defaultObjectCategory", ldb_dn_get_linearized(msg->dn));
494         }
495
496         talloc_steal(mem_ctx, msg);
497         talloc_free(ctx);
498         return msg;
499
500 failed:
501         talloc_free(ctx);
502         return NULL;
503 }
504
505 static struct schema_conv process_file(FILE *in, FILE *out)
506 {
507         TALLOC_CTX *ctx;
508         struct schema_conv ret;
509         char *entry;
510         int c, t, line;
511         struct ldb_ldif ldif;
512
513         ldif.changetype = LDB_CHANGETYPE_NONE;
514
515         ctx = talloc_new(NULL);
516
517         ret.count = 0;
518         ret.failures = 0;
519         line = 0;
520
521         while ((c = fgetc(in)) != EOF) {
522                 line++;
523                 /* fprintf(stderr, "Parsing line %d\n", line); */
524                 if (c == '#') {
525                         do {
526                                 c = fgetc(in);
527                         } while (c != EOF && c != '\n');
528                         continue;
529                 }
530                 if (c == '\n') {
531                         continue;
532                 }
533
534                 t = 0;
535                 entry = talloc_array(ctx, char, 1024);
536                 if (entry == NULL) exit(-1);
537
538                 do { 
539                         if (c == '\n') {
540                                 entry[t] = '\0';        
541                                 if (check_braces(entry) == 0) {
542                                         ret.count++;
543                                         ldif.msg = process_entry(ctx, entry);
544                                         if (ldif.msg == NULL) {
545                                                 ret.failures++;
546                                                 fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
547                                                 break;
548                                         }
549                                         ldb_ldif_write_file(ldb_ctx, out, &ldif);
550                                         break;
551                                 }
552                                 line++;
553                         } else {
554                                 entry[t] = c;
555                                 t++;
556                         }
557                         if ((t % 1023) == 0) {
558                                 entry = talloc_realloc(ctx, entry, char, t + 1024);
559                                 if (entry == NULL) exit(-1);
560                         }
561                 } while ((c = fgetc(in)) != EOF); 
562
563                 if (c != '\n') {
564                         entry[t] = '\0';
565                         if (check_braces(entry) == 0) {
566                                 ret.count++;
567                                 ldif.msg = process_entry(ctx, entry);
568                                 if (ldif.msg == NULL) {
569                                         ret.failures++;
570                                         fprintf(stderr, "No valid msg from entry \n[%s]\n at line %d\n", entry, line);
571                                         break;
572                                 }
573                                 ldb_ldif_write_file(ldb_ctx, out, &ldif);
574                         } else {
575                                 fprintf(stderr, "malformed entry on line %d\n", line);
576                                 ret.failures++;
577                         }
578                 }
579         
580                 if (c == EOF) break;
581         }
582
583         return ret;
584 }
585
586 static void usage(void)
587 {
588         printf("Usage: oLschema2ldif -H NONE <options>\n");
589         printf("\nConvert OpenLDAP schema to AD-like LDIF format\n\n");
590         printf("Options:\n");
591         printf("  -I inputfile     inputfile of OpenLDAP style schema otherwise STDIN\n");
592         printf("  -O outputfile    outputfile otherwise STDOUT\n");
593         printf("  -o options       pass options like modules to activate\n");
594         printf("              e.g: -o modules:timestamps\n");
595         printf("\n");
596         printf("Converts records from an openLdap formatted schema to an ldif schema\n\n");
597         exit(1);
598 }
599
600  int main(int argc, const char **argv)
601 {
602         TALLOC_CTX *ctx;
603         struct schema_conv ret;
604         struct ldb_cmdline *options;
605         FILE *in = stdin;
606         FILE *out = stdout;
607         ctx = talloc_new(NULL);
608         ldb_ctx = ldb_init(ctx, NULL);
609
610         setenv("LDB_URL", "NONE", 1);
611         options = ldb_cmdline_process(ldb_ctx, argc, argv, usage);
612
613         if (options->basedn == NULL) {
614                 perror("Base DN not specified");
615                 exit(1);
616         } else {
617                 basedn = ldb_dn_new(ctx, ldb_ctx, options->basedn);
618                 if ( ! ldb_dn_validate(basedn)) {
619                         perror("Malformed Base DN");
620                         exit(1);
621                 }
622         }
623
624         if (options->input) {
625                 in = fopen(options->input, "r");
626                 if (!in) {
627                         perror(options->input);
628                         exit(1);
629                 }
630         }
631         if (options->output) {
632                 out = fopen(options->output, "w");
633                 if (!out) {
634                         perror(options->output);
635                         exit(1);
636                 }
637         }
638
639         ret = process_file(in, out);
640
641         fclose(in);
642         fclose(out);
643
644         printf("Converted %d records with %d failures\n", ret.count, ret.failures);
645
646         return 0;
647 }