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