~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/utils/oLschema2ldif.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

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