summaryrefslogtreecommitdiffstats
path: root/examples/LDAP/ol-schema-migrate.pl
diff options
context:
space:
mode:
Diffstat (limited to 'examples/LDAP/ol-schema-migrate.pl')
-rwxr-xr-xexamples/LDAP/ol-schema-migrate.pl384
1 files changed, 384 insertions, 0 deletions
diff --git a/examples/LDAP/ol-schema-migrate.pl b/examples/LDAP/ol-schema-migrate.pl
new file mode 100755
index 00000000000..12392cb4cd0
--- /dev/null
+++ b/examples/LDAP/ol-schema-migrate.pl
@@ -0,0 +1,384 @@
+#!/usr/bin/perl -w
+#
+# Convert OpenLDAP schema files into Fedora DS format with RFC2252 compliant printing
+#
+# First Release : Mike Jackson <mj@sci.fi> 14 June 2005
+# http://www.netauth.com/~jacksonm/ldap/ol-schema-migrate.pl
+# Professional LDAP consulting for large and small projects
+#
+# - 6 Dec 2005
+# - objectclass element ordering
+#
+# Second Release : Alyseo <info@alyseo.com> 05 Februrary 2006
+# Francois Billard <francois@alyseo.com>
+# Yacine Kheddache <yacine@alyseo.com>
+# http://www.alyseo.com/
+#
+# - 05 Februrary 2006
+# - parsing improvement to accept non-RFC compliant schemas (like ISPMAN)
+# - adding RFC element : Usage, No-user-modification, collective keywords
+# - 08 Februrary 2006
+# - adding help & usage
+# - now this script can also beautify your schemas: "-b"
+# - count attributes and objects class: "-c"
+# - display items that can not be converted (empty OID...): "-d"
+# - 15 February 2006
+# - adding workaround for Fedora DS bug 181465:
+# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=181465
+# - adding duplicated OID check: "-d"
+# Useful to manually correct nasty schemas like:
+# https://sourceforge.net/tracker/?func=detail&atid=108390&aid=1429276&group_id=8390
+# - 13 September 2007
+# Based on Samba Team GPL Compliance Officer request, license has been updated from
+# GPL to GPLv3+
+#
+# - Fedora DS bug you need to correct by hand :
+# https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=179956
+#
+# GPLv3+ license
+#
+
+my $optionCount = 0;
+my $optionPrint = 0;
+my $optionBadEntries = 0;
+my $optionHelp = 0;
+my $filename = "" ;
+
+foreach (@ARGV) {
+ $optionHelp = 1 if ( /^-h$/);
+ $optionCount = 1 if ( /^-c$/);
+ $optionPrint = 1 if ( /^-b$/);
+ $optionBadEntries = 1 if ( /^-d$/);
+ $filename = $_ if ( ! /^-b$/ && ! /^-c$/ && ! /^-d$/);
+}
+
+die "Usage : ol-schema-migrate-v2.pl [ -c ] [ -b ] [ -d ] schema\n" .
+ " -c\tcount attribute and object class\n" .
+ " -b\tconvert and beautify your schema\n" .
+ " -d\tdisplay unrecognized elements, find empty and duplicated OID\n" .
+ " -h\tthis help\n" if ($filename eq "" || ($optionHelp || (!$optionCount && !$optionPrint && !$optionBadEntries)));
+
+if($optionCount) {
+ print "Schema verification counters:\n";
+ my $ldapdata = &getSourceFile($filename);
+ print "".(defined($ldapdata->{attributes}) ? @{$ldapdata->{attributes}} : 0) . " attributes\n";
+ print "".(defined($ldapdata->{objectclass}) ? @{$ldapdata->{objectclass}} : 0) . " object classes\n\n"
+}
+
+if($optionPrint) {
+ my $ldapdata = &getSourceFile($filename);
+ &printit($ldapdata);
+}
+
+if($optionBadEntries) {
+ print "Display unrecognized entries:\n";
+ my $ldapdata = &getSourceFile($filename);
+ my $errorsAttr = 0;
+ my $errorsObjc = 0;
+ my $errorsDup = 0;
+ my $emptyOid = 0;
+ my %dup;
+
+ foreach (@{$ldapdata->{attributes}}) {
+ my $attr = $_;
+
+ push @{$dup{$attr->{OID}}{attr}}, {NAME => $attr->{NAME}, LINENUMBER => $attr->{LINENUMBER}};
+
+ $attr->{DATA} =~ s/\n/ /g;
+ $attr->{DATA} =~ s/\r//g;
+ $attr->{DATA} =~ s/attribute[t|T]ypes?:?\s*\(//;
+ $attr->{DATA} =~ s/\Q$attr->{OID}// if(defined $attr->{OID});
+ $attr->{DATA} =~ s/NAME\s*\Q$attr->{NAME}// if(defined $attr->{NAME});
+ $attr->{DATA} =~ s/DESC\s*'\Q$attr->{DESC}'// if(defined $attr->{DESC});
+ $attr->{DATA} =~ s/$attr->{OBSOLETE}// if(defined $attr->{OBSOLETE});
+ $attr->{DATA} =~ s/SUP\s*\Q$attr->{SUP}// if(defined $attr->{SUP});
+ $attr->{DATA} =~ s/EQUALITY\s*\Q$attr->{EQUALITY}// if(defined $attr->{EQUALITY});
+ $attr->{DATA} =~ s/ORDERING\s*\Q$attr->{ORDERING}// if(defined $attr->{ORDERING});
+ $attr->{DATA} =~ s/SUBSTR\s*\Q$attr->{SUBSTR}// if(defined $attr->{SUBSTR});
+ $attr->{DATA} =~ s/SYNTAX\s*\Q$attr->{SYNTAX}// if(defined $attr->{SYNTAX});
+ $attr->{DATA} =~ s/SINGLE-VALUE// if(defined $attr->{SINGLEVALUE});
+ $attr->{DATA} =~ s/NO-USER-MODIFICATION// if(defined $attr->{NOUSERMOD});
+ $attr->{DATA} =~ s/COLLECTIVE// if(defined $attr->{COLLECTIVE});
+ $attr->{DATA} =~ s/USAGE\s*\Q$attr->{USAGE}// if(defined $attr->{USAGE});
+ $attr->{DATA} =~ s/\)\s$//;
+ $attr->{DATA} =~ s/^\s+(\S)/\n$1/ ;
+ $attr->{DATA} =~ s/(\S)\s+$/$1\n/;
+ do {
+ $errorsAttr ++;
+ do { $emptyOid ++;
+ print "Warning : no OID for attributes element at line $attr->{LINENUMBER} \n";
+ } if( !defined($attr->{OID}));
+ print "### Unknow element embedded in ATTRIBUTE at line $attr->{LINENUMBER} :\n$attr->{DATA}\n"
+ } if($attr->{DATA} =~ /\w/);
+ }
+
+ foreach (@{$ldapdata->{objectclass}}) {
+ my $objc = $_;
+ push @{$dup{$objc->{OID}}{objc}} , {NAME => $objc->{NAME}, LINENUMBER => $objc->{LINENUMBER}};
+ $objc->{DATA} =~ s/\n/ /g;
+ $objc->{DATA} =~ s/\r//g;
+ $objc->{DATA} =~ s/^object[c|C]lasse?s?:?\s*\(?//;
+ $objc->{DATA} =~ s/\Q$objc->{OID}// if(defined $objc->{OID});
+ $objc->{DATA} =~ s/NAME\s*\Q$objc->{NAME}\E// if(defined $objc->{NAME});
+ $objc->{DATA} =~ s/DESC\s*'\Q$objc->{DESC}\E'// if(defined $objc->{DESC});
+ $objc->{DATA} =~ s/OBSOLETE// if(defined $objc->{OBSOLETE});
+ $objc->{DATA} =~ s/SUP\s*\Q$objc->{SUP}// if(defined $objc->{SUP});
+ $objc->{DATA} =~ s/\Q$objc->{TYPE}// if(defined $objc->{TYPE});
+ $objc->{DATA} =~ s/MUST\s*\Q$objc->{MUST}\E\s*// if(defined $objc->{MUST});
+ $objc->{DATA} =~ s/MUST\s*\(?\s*\Q$objc->{MUST}\E\s*\)?// if(defined $objc->{MUST});
+ $objc->{DATA} =~ s/MAY\s*\Q$objc->{MAY}\E// if(defined $objc->{MAY});
+ $objc->{DATA} =~ s/\)\s$//;
+ $objc->{DATA} =~ s/^\s+(\S)/\n$1/ ;
+ $objc->{DATA} =~ s/(\S)\s+$/$1\n/;
+
+ do {
+ print "#" x 80 ."\n";
+ $errorsObjc ++;
+ do { $emptyOid++ ;
+ print "Warning : no OID for object class element at line $objc->{LINENUMBER} \n";
+ } if( $objc->{OID} eq "");
+ print "### Unknow element embedded in OBJECT CLASS at line $objc->{LINENUMBER} :\n$objc->{DATA}\n"
+ } if($objc->{DATA} =~ /\w/);
+ }
+
+ my $nbDup = 0;
+ foreach (keys %dup) {
+ my $sumOid = 0;
+ $sumOid += @{$dup{$_}{attr}} if(defined (@{$dup{$_}{attr}}));
+ $sumOid += @{$dup{$_}{objc}} if(defined (@{$dup{$_}{objc}}));
+ if( $sumOid > 1 && $_ ne "") {
+ $nbDup ++;
+ print "#" x 80 ."\n";
+ print "Duplicate OID founds : $_\n";
+ foreach (@{$dup{$_}{attr}}) {
+
+ print "Attribute : $_->{NAME} (line : $_->{LINENUMBER})\n";
+ }
+ foreach (@{$dup{$_}{objc}}) {
+ print "Object class : $_->{NAME} (line : $_->{LINENUMBER})\n";
+ }
+
+ }
+ }
+
+ print "\n$errorsAttr errors detected in ATTRIBUTES list\n";
+ print "$errorsObjc errors detected in OBJECT CLASS list\n";
+ print "$nbDup duplicate OID founds\n";
+ print "$emptyOid empty OID fields founds\n\n";
+
+}
+
+
+sub printit {
+ my $ldapdata = shift;
+ &printSeparator;
+ print "dn: cn=schema\n";
+ &printSeparator;
+
+ # print elements in RFC2252 order
+
+ foreach (@{$ldapdata->{attributes}}) {
+ my $attr = $_;
+ print "attributeTypes: (\n";
+ print " $attr->{OID}\n";
+ print " NAME $attr->{NAME}\n";
+ print " DESC '$attr->{DESC}'\n" if(defined $attr->{DESC});
+ print " OBSOLETE\n" if(defined $attr->{OBSOLETE});
+ print " SUP $attr->{SUP}\n" if(defined $attr->{SUP});
+ print " EQUALITY $attr->{EQUALITY}\n" if(defined $attr->{EQUALITY});
+ print " ORDERING $attr->{ORDERING}\n" if(defined $attr->{ORDERING});
+ print " SUBSTR $attr->{SUBSTR}\n" if(defined $attr->{SUBSTR});
+ print " SYNTAX $attr->{SYNTAX}\n" if(defined $attr->{SYNTAX});
+ print " SINGLE-VALUE\n" if(defined $attr->{SINGLEVALUE});
+ print " NO-USER-MODIFICATION\n" if(defined $attr->{NOUSERMOD});
+ print " COLLECTIVE\n" if(defined $attr->{COLLECTIVE});
+ print " USAGE $attr->{USAGE}\n" if(defined $attr->{USAGE});
+ print " )\n";
+ &printSeparator;
+ }
+
+ foreach (@{$ldapdata->{objectclass}}) {
+ my $objc = $_;
+ # next 3 lines : Fedora DS space sensitive bug workaround
+ $objc->{SUP} =~ s/^\(\s*(.*?)\s*\)$/\( $1 \)/ if (defined $objc->{SUP});
+ $objc->{MUST} =~ s/^\(\s*(.*?)\s*\)$/\( $1 \)/ if (defined $objc->{MUST});
+ $objc->{MAY} =~ s/^\(\s*(.*?)\s*\)$/\( $1 \)/ if (defined $objc->{MAY});
+
+ print "objectClasses: (\n";
+ print " $objc->{OID}\n";
+ print " NAME $objc->{NAME}\n";
+ print " DESC '$objc->{DESC}'\n" if(defined $objc->{DESC});
+ print " OBSOLETE\n" if(defined $objc->{OBSOLETE});
+ print " SUP $objc->{SUP}\n" if(defined $objc->{SUP});
+ print " $objc->{TYPE}\n" if(defined $objc->{TYPE});
+ print " MUST $objc->{MUST}\n" if(defined $objc->{MUST});
+ print " MAY $objc->{MAY}\n" if(defined $objc->{MAY});
+ print " )\n";
+ &printSeparator;
+ }
+}
+
+sub printSeparator {
+ print "#\n";
+ print "#" x 80 . "\n";
+ print "#\n";
+}
+
+sub getSourceFile {
+ my @data = &getFile(shift);
+ my %result;
+ my $result = \%result;
+ my @allattrs;
+ my @allattrsLineNumber;
+ my @allobjc;
+ my @allobjcLineNumber;
+ my $at = 0;
+ my $oc = 0;
+ my $at_string;
+ my $oc_string;
+ my $idx = 0;
+ my $beginParenthesis = 0;
+ my $endParenthesis = 0;
+ my $lineNumber = 0;
+ for(@data) {
+ $lineNumber++;
+ next if (/^\s*\#/); # skip comments
+
+ if($at) {
+ s/ +/ /; # remove embedded tabs
+ s/\t/ /; # remove multiple spaces after the $ sign
+
+ $at_string .= $_;
+ $beginParenthesis = 0; # Use best matching elements
+ $endParenthesis = 0;
+ for(my $i=0;$ i < length($at_string); $i++) {
+ $beginParenthesis++ if(substr ($at_string,$i,1) eq "(");
+ $endParenthesis++ if(substr ($at_string,$i,1) eq ")");
+ }
+ if($beginParenthesis == $endParenthesis) {
+ push @allattrs, $at_string;
+ $at = 0;
+ $at_string = "";
+ $endParenthesis = 0;
+ $beginParenthesis = 0;
+ }
+ }
+
+ if (/^attribute[t|T]ype/) {
+ my $line = $_;
+ push @allattrsLineNumber, $lineNumber; # keep starting line number
+ for(my $i=0;$ i < length($line); $i++) {
+ $beginParenthesis++ if(substr ($line, $i, 1) eq "(");
+ $endParenthesis++ if(substr ($line, $i, 1) eq ")");
+ }
+ if($beginParenthesis == $endParenthesis && $beginParenthesis != 0) {
+ push @allattrs, $line;
+ $endParenthesis = 0;
+ $beginParenthesis = 0;
+ } else {
+ $at_string = $line;
+ $at = 1;
+ }
+ }
+
+ #####################################
+
+ if($oc) {
+ s/ +/ /;
+ s/\t/ /;
+
+ $oc_string .= $_;
+ $endParenthesis = 0; # best methode to accept an elements :
+ $beginParenthesis = 0; # left parenthesis sum == right parenthesis sum, so we are sure to
+ for(my $i=0;$ i < length($oc_string); $i++) { # have an element.
+ $beginParenthesis++ if(substr ($oc_string, $i, 1) eq "(");
+ $endParenthesis++ if(substr ($oc_string, $i, 1) eq ")");
+ }
+ if($beginParenthesis == $endParenthesis) {
+ push @allobjc, $oc_string;
+ $oc = 0;
+ $oc_string = "";
+ $endParenthesis = 0;
+ $beginParenthesis = 0;
+ }
+ }
+
+ if (/^object[c|C]lass/) {
+ my $line = $_;
+ push @allobjcLineNumber, $lineNumber; # keep starting line number
+ for(my $i=0;$ i < length($line); $i++) {
+ $beginParenthesis++ if(substr ($line, $i, 1) eq "(");
+ $endParenthesis++ if(substr ($line, $i, 1) eq ")");
+ }
+ if($beginParenthesis == $endParenthesis && $beginParenthesis != 0) {
+ push @allobjc, $line;
+ $endParenthesis = 0;
+ $beginParenthesis = 0;
+ } else {
+ $oc_string = $line;
+ $oc = 1;
+ }
+ }
+ }
+
+ # Parsing attribute elements
+
+ for(@allattrs) {
+ s/\n/ /g;
+ s/\r//g;
+ s/ +/ /g;
+ s/\t/ /g;
+ $result->{attributes}->[$idx]->{DATA} = $_ if($optionBadEntries); # keep original data
+ $result->{attributes}->[$idx]->{LINENUMBER} = $allattrsLineNumber[$idx];
+ $result->{attributes}->[$idx]->{OID} = $1 if (m/^attribute[t|T]ypes?:?\s*\(?\s*([\.\d]*?)\s+/);
+ $result->{attributes}->[$idx]->{NAME} = $1 if (m/NAME\s+('.*?')\s*/ || m/NAME\s+(\(.*?\))/);
+ $result->{attributes}->[$idx]->{DESC} = $1 if (m/DESC\s+'(.*?)'\s*/);
+ $result->{attributes}->[$idx]->{OBSOLETE} = "OBSOLETE" if (m/OBSOLETE/);
+ $result->{attributes}->[$idx]->{SUP} = $1 if (m/SUP\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{EQUALITY} = $1 if (m/EQUALITY\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{ORDERING} = $1 if (m/ORDERING\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{SUBSTR} = $1 if (m/SUBSTR\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{SYNTAX} = $1 if (m/SYNTAX\s+(.*?)(\s|\))/);
+ $result->{attributes}->[$idx]->{SINGLEVALUE} = "SINGLE-VALUE" if (m/SINGLE-VALUE/);
+ $result->{attributes}->[$idx]->{COLLECTIVE} = "COLLECTIVE" if (m/COLLECTIVE/);
+ $result->{attributes}->[$idx]->{USAGE} = $1 if (m/USAGE\s+(.*?)\s/);
+ $result->{attributes}->[$idx]->{NOUSERMOD} = "NO-USER-MODIFICATION" if (m/NO-USER-MODIFICATION/);
+ $idx ++;
+ }
+
+ $idx = 0;
+
+ # Parsing object class elements
+
+ for(@allobjc) {
+ s/\n/ /g;
+ s/\r//g;
+ s/ +/ /g;
+ s/\t/ /g;
+ $result->{objectclass}->[$idx]->{DATA} = $_ if($optionBadEntries); # keep original data
+ $result->{objectclass}->[$idx]->{LINENUMBER} = $allobjcLineNumber[$idx];
+ $result->{objectclass}->[$idx]->{OID} = $1 if (m/^object[c|C]lasse?s?:?\s*\(?\s*([\.\d]*?)\s+/);
+ $result->{objectclass}->[$idx]->{NAME} = $1 if (m/NAME\s+('.*?')\s*/ || m/NAME\s+(\(.*?\))/);
+ $result->{objectclass}->[$idx]->{DESC} = $1 if (m/DESC\s+'(.*?)'\s*/);
+ $result->{objectclass}->[$idx]->{OBSOLETE} = "OBSOLETE" if (m/OBSOLETE/);
+ $result->{objectclass}->[$idx]->{SUP} = $1 if (m/SUP\s+([^()]+?)\s/ || m/SUP\s+(\(.+?\))\s/);
+ $result->{objectclass}->[$idx]->{TYPE} = $1 if (m/((?:STRUCTURAL)|(?:AUXILIARY)|(?:ABSTRACT))/);
+ $result->{objectclass}->[$idx]->{MUST} = $1 if (m/MUST\s+(\w+)\)?/ || m/MUST\s+(\(.*?\))(\s|\))/s);
+ $result->{objectclass}->[$idx]->{MAY} = $1 if (m/MAY\s+(\w+)\)?/ || m/MAY\s+(\(.*?\))(\s|\))/s);
+
+ $idx++;
+ }
+
+ return $result;
+}
+
+sub getFile {
+ my @data;
+ my $file = shift;
+ die "File not found : $file\n" if(! -e $file);
+ open FH, $file;
+ @data = <FH>;
+ close FH;
+ @data;
+}
+