Use library for subunit test functions.
[jra/samba/.git] / testprogs / ejs / minschema.js
1 #!/bin/sh
2 exec smbscript "$0" ${1+"$@"}
3 /*
4   work out the minimal schema for a set of objectclasses 
5 */
6
7 libinclude("base.js");
8
9 var ldb = ldb_init();
10
11 var options = GetOptions(ARGV, 
12                          "POPT_AUTOHELP",
13                          "POPT_COMMON_SAMBA",
14                          "POPT_COMMON_CREDENTIALS",
15                          "verbose",
16                          "classes",
17                          "attributes",
18                          "subschema",
19                          "subschema-auto");
20 if (options == undefined) {
21    println("Failed to parse options");
22    return -1;
23 }
24 verbose = options["verbose"];
25 dump_all = "yes";
26 dump_classes = options["classes"];
27 dump_attributes = options["attributes"];
28 dump_subschema = options["subschema"];
29 dump_subschema_auto = options["subschema-auto"];
30
31 if (dump_classes != undefined) {
32         dump_all = undefined;
33 }
34 if (dump_attributes != undefined) {
35         dump_all = undefined;
36 }
37 if (dump_subschema != undefined) {
38         dump_all = undefined;
39 }
40 if (dump_subschema_auto != undefined) {
41         dump_all = undefined;
42         dump_subschema = "yes";
43 }
44 if (dump_all != undefined) {
45         dump_classes = "yes";
46         dump_attributes = "yes";
47         dump_subschema = "yes";
48         dump_subschema_auto = "yes";
49 }
50
51 if (options.ARGV.length != 2) {
52    println("Usage: minschema.js <URL> <classfile>");
53    return -1;
54 }
55
56 var url = options.ARGV[0];
57 var classfile = options.ARGV[1];
58
59 /* use command line creds if available */
60 ldb.credentials = options.get_credentials();
61
62 var ok = ldb.connect(url);
63 assert(ok);
64
65 objectclasses = new Object();
66 attributes = new Object();
67 rootDse = new Object();
68
69 objectclasses_expanded = new Object();
70
71 /* the attributes we need for objectclasses */
72 class_attrs = new Array("objectClass",
73                         "subClassOf",
74                         "governsID",
75                         "possSuperiors",
76                         "possibleInferiors",
77                         "mayContain",
78                         "mustContain",
79                         "auxiliaryClass",
80                         "rDNAttID",
81                         "showInAdvancedViewOnly",
82                         "adminDisplayName",
83                         "adminDescription",
84                         "objectClassCategory",
85                         "lDAPDisplayName",
86                         "schemaIDGUID",
87                         "systemOnly",
88                         "systemPossSuperiors",
89                         "systemMayContain",
90                         "systemMustContain",
91                         "systemAuxiliaryClass",
92                         "defaultSecurityDescriptor",
93                         "systemFlags",
94                         "defaultHidingValue",
95                         "defaultObjectCategory",
96
97                         /* this attributes are not used by w2k3 */
98                         "schemaFlagsEx",
99                         "msDs-IntId",
100                         "msDs-Schema-Extensions",
101                         "classDisplayName",
102                         "isDefunct");
103
104
105 attrib_attrs = new Array("objectClass",
106                          "attributeID",
107                          "attributeSyntax",
108                          "isSingleValued",
109                          "rangeLower",
110                          "rangeUpper",
111                          "mAPIID",
112                          "linkID",
113                          "showInAdvancedViewOnly",
114                          "adminDisplayName",
115                          "oMObjectClass",
116                          "adminDescription",
117                          "oMSyntax",
118                          "searchFlags",
119                          "extendedCharsAllowed",
120                          "lDAPDisplayName",
121                          "schemaIDGUID",
122                          "attributeSecurityGUID",
123                          "systemOnly",
124                          "systemFlags",
125                          "isMemberOfPartialAttributeSet",
126
127                          /* this attributes are not used by w2k3 */
128                          "schemaFlagsEx",
129                          "msDs-IntId",
130                          "msDs-Schema-Extensions",
131                          "classDisplayName",
132                          "isEphemeral",
133                          "isDefunct");
134
135 /*
136   notes:
137
138   objectClassCategory 
139       1: structural
140       2: abstract
141       3: auxiliary
142 */
143
144
145 /*
146   print only if verbose is set
147 */
148 function dprintf() {
149         if (verbose != undefined) {
150                 print(vsprintf(arguments));
151         }
152 }
153
154 function get_object_cn(ldb, name) {
155         var attrs = new Array("cn");
156
157         var res = ldb.search(sprintf("(ldapDisplayName=%s)", name), rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, attrs);
158         assert(res != undefined);
159         assert(res.msgs.length == 1);
160
161         var cn = res.msgs[0]["cn"];
162         assert(cn != undefined);
163         if (typeof(cn) == "string") {
164                 return cn;
165         }
166         return cn[0];
167 }
168 /*
169   create an objectclass object
170 */
171 function obj_objectClass(ldb, name) {
172         var o = new Object();
173         o.name = name;
174         o.cn = get_object_cn(ldb, name);
175         return o;
176 }
177
178 /*
179   create an attribute object
180 */
181 function obj_attribute(ldb, name) {
182         var o = new Object();
183         o.name = name;
184         o.cn = get_object_cn(ldb, name);
185         return o;
186 }
187
188
189 syntaxmap = new Object();
190
191 syntaxmap['2.5.5.1']  = '1.3.6.1.4.1.1466.115.121.1.12';
192 syntaxmap['2.5.5.2']  = '1.3.6.1.4.1.1466.115.121.1.38';
193 syntaxmap['2.5.5.3']  = '1.2.840.113556.1.4.1362';
194 syntaxmap['2.5.5.4']  = '1.2.840.113556.1.4.905';
195 syntaxmap['2.5.5.5']  = '1.3.6.1.4.1.1466.115.121.1.26';
196 syntaxmap['2.5.5.6']  = '1.3.6.1.4.1.1466.115.121.1.36';
197 syntaxmap['2.5.5.7']  = '1.2.840.113556.1.4.903';
198 syntaxmap['2.5.5.8']  = '1.3.6.1.4.1.1466.115.121.1.7';
199 syntaxmap['2.5.5.9']  = '1.3.6.1.4.1.1466.115.121.1.27';
200 syntaxmap['2.5.5.10'] = '1.3.6.1.4.1.1466.115.121.1.40';
201 syntaxmap['2.5.5.11'] = '1.3.6.1.4.1.1466.115.121.1.24';
202 syntaxmap['2.5.5.12'] = '1.3.6.1.4.1.1466.115.121.1.15';
203 syntaxmap['2.5.5.13'] = '1.3.6.1.4.1.1466.115.121.1.43';
204 syntaxmap['2.5.5.14'] = '1.2.840.113556.1.4.904';
205 syntaxmap['2.5.5.15'] = '1.2.840.113556.1.4.907';
206 syntaxmap['2.5.5.16'] = '1.2.840.113556.1.4.906';
207 syntaxmap['2.5.5.17'] = '1.3.6.1.4.1.1466.115.121.1.40';
208
209 /*
210   map some attribute syntaxes from some apparently MS specific
211   syntaxes to the standard syntaxes
212 */
213 function map_attribute_syntax(s) {
214         if (syntaxmap[s] != undefined) {
215                 return syntaxmap[s];
216         }
217         return s;
218 }
219
220
221 /*
222   fix a string DN to use ${SCHEMADN}
223 */
224 function fix_dn(dn) {
225         var s = strstr(dn, rootDse.schemaNamingContext);
226         if (s == NULL) {
227                 return dn;
228         }
229         return substr(dn, 0, strlen(dn) - strlen(s)) + "${SCHEMADN}";
230 }
231
232 /*
233   dump an object as ldif
234 */
235 function write_ldif_one(o, attrs) {
236         var i;
237         printf("dn: CN=%s,${SCHEMADN}\n", o.cn);
238         for (i=0;i<attrs.length;i++) {
239                 var a = attrs[i];
240                 if (o[a] == undefined) {
241                         continue;
242                 }
243                 /* special case for oMObjectClass, which is a binary object */
244                 if (a == "oMObjectClass") {
245                         printf("%s:: %s\n", a, o[a]);
246                         continue;
247                 }
248                 var v = o[a];
249                 if (typeof(v) == "string") {
250                         v = new Array(v);
251                 }
252                 var j;
253                 for (j=0;j<v.length;j++) {
254                         printf("%s: %s\n", a, fix_dn(v[j]));
255                 }
256         }
257         printf("\n");
258 }
259
260 /*
261   dump an array of objects as ldif
262 */
263 function write_ldif(o, attrs) {
264         var i;
265         for (i in o) {
266                 write_ldif_one(o[i], attrs);
267         }
268 }
269
270
271 /*
272   create a testDN based an an example DN
273   the idea is to ensure we obey any structural rules
274 */
275 function create_testdn(exampleDN) {
276         var a = split(",", exampleDN);
277         a[0] = "CN=TestDN";
278         return join(",", a);
279 }
280
281 /*
282   find the properties of an objectclass
283  */
284 function find_objectclass_properties(ldb, o) {
285         var res = ldb.search(
286                 sprintf("(ldapDisplayName=%s)", o.name),
287                 rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, class_attrs);
288         assert(res != undefined);
289         assert(res.msgs.length == 1);
290         var msg = res.msgs[0];
291         var a;
292         for (a in msg) {
293                 o[a] = msg[a];
294         }
295 }
296
297 /*
298   find the properties of an attribute
299  */
300 function find_attribute_properties(ldb, o) {
301         var res = ldb.search(
302                 sprintf("(ldapDisplayName=%s)", o.name),
303                 rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, attrib_attrs);
304         assert(res != undefined);
305         assert(res.msgs.length == 1);
306         var msg = res.msgs[0];
307         var a;
308         for (a in msg) {
309                 /* special case for oMObjectClass, which is a binary object */
310                 if (a == "oMObjectClass") {
311                         o[a] = ldb.encode(msg[a]);
312                         continue;
313                 }
314                 o[a] = msg[a];
315         }
316 }
317
318 /*
319   find the auto-created properties of an objectclass. Only works for classes
320   that can be created using just a DN and the objectclass
321  */
322 function find_objectclass_auto(ldb, o) {
323         if (o["exampleDN"] == undefined) {
324                 return;
325         }
326         var testdn = create_testdn(o.exampleDN);
327         var ok;
328
329         dprintf("testdn is '%s'\n", testdn);
330
331         var ldif = "dn: " + testdn;
332         ldif = ldif + "\nobjectClass: " + o.name;
333         ok = ldb.add(ldif);
334         if (ok.error != 0) {
335                 dprintf("error adding %s: %s\n", o.name, ok.errstr);
336                 dprintf("%s\n", ldif);
337                 return;
338         }
339
340         var res = ldb.search("", testdn, ldb.SCOPE_BASE);
341         ok = ldb.del(testdn);
342         assert(ok.error == 0);
343
344         var a;
345         for (a in res.msgs[0]) {
346                 attributes[a].autocreate = true;
347         }
348 }
349
350
351 /*
352   look at auxiliary information from a class to intuit the existance of more
353   classes needed for a minimal schema
354 */
355 function expand_objectclass(ldb, o) {
356         var attrs = new Array("auxiliaryClass", "systemAuxiliaryClass",
357                               "possSuperiors", "systemPossSuperiors",
358                               "subClassOf");
359         var res = ldb.search(
360                 sprintf("(&(objectClass=classSchema)(ldapDisplayName=%s))", o.name),
361                 rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, attrs);
362         var a;
363         dprintf("Expanding class %s\n", o.name);
364         assert(res != undefined);
365         assert(res.msgs.length == 1);
366         var msg = res.msgs[0];
367         for (a=0;a<attrs.length;a++) {
368                 var aname = attrs[a];
369                 if (msg[aname] == undefined) {
370                         continue;
371                 }
372                 var list = msg[aname];
373                 if (typeof(list) == "string") {
374                         list = new Array(msg[aname]);
375                 }
376                 var i;
377                 for (i=0;i<list.length;i++) {
378                         var name = list[i];
379                         if (objectclasses[name] == undefined) {
380                                 dprintf("Found new objectclass '%s'\n", name);
381                                 objectclasses[name] = obj_objectClass(ldb, name);
382                         }
383                 }
384         }
385 }
386
387
388 /*
389   add the must and may attributes from an objectclass to the full list
390   of attributes
391 */
392 function add_objectclass_attributes(ldb, class) {
393         var attrs = new Array("mustContain", "systemMustContain", 
394                               "mayContain", "systemMayContain");
395         var i;
396         for (i=0;i<attrs.length;i++) {
397                 var aname = attrs[i];
398                 if (class[aname] == undefined) {
399                         continue;
400                 }
401                 var alist = class[aname];
402                 if (typeof(alist) == "string") {
403                         alist = new Array(alist);
404                 }
405                 var j;
406                 var len = alist.length;
407                 for (j=0;j<len;j++) {
408                         var a = alist[j];
409                         if (attributes[a] == undefined) {
410                                 attributes[a] = obj_attribute(ldb, a);
411                         }
412                 }
413         }
414 }
415
416
417 /*
418   process an individual record, working out what attributes it has
419 */
420 function walk_dn(ldb, dn) {
421         /* get a list of all possible attributes for this object */
422         var attrs = new Array("allowedAttributes");
423         var res = ldb.search("objectClass=*", dn, ldb.SCOPE_BASE, attrs);
424         if (res.error != 0) {
425                 dprintf("Unable to fetch allowedAttributes for '%s' - %s\n", 
426                        dn, res.errstr);
427                 return;
428         }
429         var allattrs = res.msgs[0].allowedAttributes;
430         res = ldb.search("objectClass=*", dn, ldb.SCOPE_BASE, allattrs);
431         if (res.error != 0) {
432                 dprintf("Unable to fetch all attributes for '%s' - %s\n", 
433                        dn, res.errstr);
434                 return;
435         }
436         var a;
437         var msg = res.msgs[0];
438         for (a in msg) {
439                 if (attributes[a] == undefined) {
440                         attributes[a] = obj_attribute(ldb, a);
441                 }
442         }
443 }
444
445 /*
446   walk a naming context, looking for all records
447 */
448 function walk_naming_context(ldb, namingContext) {
449         var attrs = new Array("objectClass");
450         var res = ldb.search("objectClass=*", namingContext, ldb.SCOPE_DEFAULT, attrs);
451         if (res.error != 0) {
452                 dprintf("Unable to fetch objectClasses for '%s' - %s\n", 
453                        namingContext, res.errstr);
454                 return;
455         }
456         var r;
457         for (r=0;r<res.msgs.length;r++) {
458                 var msg = res.msgs[r].objectClass;
459                 var c;
460                 for (c=0;c<msg.length;c++) {
461                         var objectClass = msg[c];
462                         if (objectclasses[objectClass] == undefined) {
463                                 objectclasses[objectClass] = obj_objectClass(ldb, objectClass);
464                                 objectclasses[objectClass].exampleDN = res.msgs[r].dn;
465                         }
466                 }
467                 walk_dn(ldb, res.msgs[r].dn);
468         }
469 }
470
471 /*
472   trim the may attributes for an objectClass
473 */
474 function trim_objectclass_attributes(ldb, class) {
475         var i,j,n;
476
477         /* trim possibleInferiors,
478          * include only the classes we extracted */
479         var possinf = class["possibleInferiors"];
480         if (possinf != undefined) {
481                 var newpossinf = new Array();
482                 if (typeof(possinf) == "string") {
483                         possinf = new Array(possinf);
484                 }
485                 n = 0;
486                 for (j = 0;j < possinf.length; j++) {
487                         var x = possinf[j];
488                         if (objectclasses[x] != undefined) {
489                                 newpossinf[n] = x;
490                                 n++;
491                         }
492                 }
493                 class["possibleInferiors"] = newpossinf;
494         }
495
496         /* trim systemMayContain,
497          * remove duplicates */
498         var sysmay = class["systemMayContain"];
499         if (sysmay != undefined) {
500                 var newsysmay = new Array();
501                 if (typeof(sysmay) == "string") {
502                         sysmay = new Array(sysmay);
503                 }
504                 for (j = 0;j < sysmay.length; j++) {
505                         var x = sysmay[j];
506                         var dup = false;
507                         if (newsysmay[0] == undefined) {
508                                 newsysmay[0] = x;
509                         } else {
510                                 for (n = 0; n < newsysmay.length; n++) {
511                                         if (newsysmay[n] == x) {
512                                                 dup = true;
513                                         }
514                                 }
515                                 if (dup == false) {
516                                         newsysmay[n] = x;
517                                 }
518                         }
519                 }
520                 class["systemMayContain"] = newsysmay;
521         }
522
523         /* trim mayContain,
524          * remove duplicates */
525         var may = class["mayContain"];
526         if (may != undefined) {
527                 var newmay = new Array();
528                 if (typeof(may) == "string") {
529                         may = new Array(may);
530                 }
531                 for (j = 0;j < may.length; j++) {
532                         var x = may[j];
533                         var dup = false;
534                         if (newmay[0] == undefined) {
535                                 newmay[0] = x;
536                         } else {
537                                 for (n = 0; n < newmay.length; n++) {
538                                         if (newmay[n] == x) {
539                                                 dup = true;
540                                         }
541                                 }
542                                 if (dup == false) {
543                                         newmay[n] = x;
544                                 }
545                         }
546                 }
547                 class["mayContain"] = newmay;
548         }
549 }
550
551 /*
552   load the basic attributes of an objectClass
553 */
554 function build_objectclass(ldb, name) {
555         var attrs = new Array("name");
556         var res = ldb.search(
557                 sprintf("(&(objectClass=classSchema)(ldapDisplayName=%s))", name),
558                 rootDse.schemaNamingContext, ldb.SCOPE_SUBTREE, attrs);
559         if (res.error != 0) {
560                 dprintf("unknown class '%s'\n", name);
561                 return undefined;
562         }
563         if (res.msgs.length == 0) {
564                 dprintf("unknown class '%s'\n", name);
565                 return undefined;
566         }
567         return obj_objectClass(ldb, name);
568 }
569
570 /*
571   append 2 lists
572 */
573 function list_append(a1, a2) {
574         var i;
575         if (a1 == undefined) {
576                 return a2;
577         }
578         if (a2 == undefined) {
579                 return a1;
580         }
581         for (i=0;i<a2.length;i++) {
582                 a1[a1.length] = a2[i];
583         }
584         return a1;
585 }
586
587 /*
588   form a coalesced attribute list
589 */
590 function attribute_list(class, attr1, attr2) {
591         var a1 = class[attr1];
592         var a2 = class[attr2];
593         if (typeof(a1) == "string") {
594                 a1 = new Array(a1);
595         }
596         if (typeof(a2) == "string") {
597                 a2 = new Array(a2);
598         }
599         return list_append(a1, a2);
600 }
601
602 /*
603   write out a list in aggregate form
604 */
605 function aggregate_list(name, list) {
606         if (list == undefined) {
607                 return;
608         }
609         var i;
610         printf("%s ( ", name);
611         for (i=0;i<list.length;i++) {
612                 printf("%s ", list[i]);
613                 if (i < (list.length - 1)) {
614                         printf("$ ");
615                 }
616         }
617         printf(") ");
618 }
619
620 /*
621   write the aggregate record for an objectclass
622 */
623 function write_aggregate_objectclass(class) {
624         printf("objectClasses: ( %s NAME '%s' ", class.governsID, class.name);
625         if (class['subClassOf'] != undefined) {
626                 printf("SUP %s ", class['subClassOf']);
627         }
628         if (class.objectClassCategory == 1) {
629                 printf("STRUCTURAL ");
630         } else if (class.objectClassCategory == 2) {
631                 printf("ABSTRACT ");
632         } else if (class.objectClassCategory == 3) {
633                 printf("AUXILIARY ");
634         }
635
636         var list;
637
638         list = attribute_list(class, "systemMustContain", "mustContain");
639         aggregate_list("MUST", list);
640
641         list = attribute_list(class, "systemMayContain", "mayContain");
642         aggregate_list("MAY", list);
643
644         printf(")\n");
645 }
646
647
648 /*
649   write the aggregate record for an ditcontentrule
650 */
651 function write_aggregate_ditcontentrule(class) {
652         var list = attribute_list(class, "auxiliaryClass", "systemAuxiliaryClass");
653         var i;
654         if (list == undefined) {
655                 return;
656         }
657
658         printf("dITContentRules: ( %s NAME '%s' ", class.governsID, class.name);
659
660         aggregate_list("AUX", list);
661
662         var may_list = undefined;
663         var must_list = undefined;
664
665         for (i=0;i<list.length;i++) {
666                 var c = list[i];
667                 var list2;
668                 list2 = attribute_list(objectclasses[c], 
669                                        "mayContain", "systemMayContain");
670                 may_list = list_append(may_list, list2);
671                 list2 = attribute_list(objectclasses[c], 
672                                        "mustContain", "systemMustContain");
673                 must_list = list_append(must_list, list2);
674         }
675
676         aggregate_list("MUST", must_list);
677         aggregate_list("MAY", may_list);
678
679         printf(")\n");
680 }
681
682 /*
683   write the aggregate record for an attribute
684 */
685 function write_aggregate_attribute(attrib) {
686         printf("attributeTypes: ( %s NAME '%s' SYNTAX '%s' ", 
687                attrib.attributeID, attrib.name, 
688                map_attribute_syntax(attrib.attributeSyntax));
689         if (attrib['isSingleValued'] == "TRUE") {
690                 printf("SINGLE-VALUE ");
691         }
692         if (attrib['systemOnly'] == "TRUE") {
693                 printf("NO-USER-MODIFICATION ");
694         }
695
696         printf(")\n");
697 }
698
699
700 /*
701   write the aggregate record
702 */
703 function write_aggregate() {
704         printf("dn: CN=Aggregate,${SCHEMADN}\n");
705         print("objectClass: top
706 objectClass: subSchema
707 ");
708         if (dump_subschema_auto == undefined) {
709                 return; 
710         }
711
712         for (i in objectclasses) {
713                 write_aggregate_objectclass(objectclasses[i]);
714         }
715         for (i in attributes) {
716                 write_aggregate_attribute(attributes[i]);
717         }
718         for (i in objectclasses) {
719                 write_aggregate_ditcontentrule(objectclasses[i]);
720         }
721 }
722
723 /*
724   load a list from a file
725 */
726 function load_list(file) {
727         var sys = sys_init();
728         var s = sys.file_load(file);
729         var a = split("\n", s);
730         return a;
731 }
732
733 /* get the rootDSE */
734 var res = ldb.search("", "", ldb.SCOPE_BASE);
735 rootDse = res.msgs[0];
736
737 /* load the list of classes we are interested in */
738 var classes = load_list(classfile);
739 var i;
740 for (i=0;i<classes.length;i++) {
741         var classname = classes[i];
742         var class = build_objectclass(ldb, classname);
743         if (class != undefined) {
744                 objectclasses[classname] = class;
745         }
746 }
747
748
749 /*
750   expand the objectclass list as needed
751 */
752 var num_classes = 0;
753 var expanded = 0;
754 /* calculate the actual number of classes */
755 for (i in objectclasses) {
756         num_classes++;
757 }
758 /* so EJS do not have while nor the break statement
759    cannot find any other way than doing more loops
760    than necessary to recursively expand all classes
761  */
762 var inf;
763 for (inf = 0;inf < 500; inf++) {
764         if (expanded < num_classes) {
765                 for (i in objectclasses) {
766                         var n = objectclasses[i];
767                         if (objectclasses_expanded[i] != "DONE") {
768                                 expand_objectclass(ldb, objectclasses[i]);
769                                 objectclasses_expanded[i] = "DONE";
770                                 expanded++;
771                         }
772                 }
773                 /* recalculate the actual number of classes */
774                 num_classes = 0;
775                 for (i in objectclasses) {
776                         num_classes++;
777                 }
778         }
779 }
780
781 /*
782   find objectclass properties
783 */
784 for (i in objectclasses) {
785         find_objectclass_properties(ldb, objectclasses[i]);
786 }
787
788 /*
789   form the full list of attributes
790 */
791 for (i in objectclasses) {
792         add_objectclass_attributes(ldb, objectclasses[i]);
793 }
794
795 /* and attribute properties */
796 for (i in attributes) {
797         find_attribute_properties(ldb, attributes[i]);
798 }
799
800 /*
801   trim the 'may' attribute lists to those really needed
802 */
803 for (i in objectclasses) {
804         trim_objectclass_attributes(ldb, objectclasses[i]);
805 }
806
807 /*
808   dump an ldif form of the attributes and objectclasses
809 */
810 if (dump_attributes != undefined) {
811         write_ldif(attributes, attrib_attrs);
812 }
813 if (dump_classes != undefined) {
814         write_ldif(objectclasses, class_attrs);
815 }
816 if (dump_subschema != undefined) {
817         write_aggregate();
818 }
819
820 if (verbose == undefined) {
821         exit(0);
822 }
823
824 /*
825   dump list of objectclasses
826 */
827 printf("objectClasses:\n")
828 for (i in objectclasses) {
829         printf("\t%s\n", i);
830 }
831 printf("attributes:\n")
832 for (i in attributes) {
833         printf("\t%s\n", i);
834 }
835
836 printf("autocreated attributes:\n");
837 for (i in attributes) {
838         if (attributes[i].autocreate == true) {
839                 printf("\t%s\n", i);
840         }
841 }
842
843 return 0;