#!/usr/bin/perl # # $Id: pretty_schema,v 1.2 2004/09/08 20:36:00 dgregor Exp $ # # Copyright (c) 2002 Daniel J. Gregor, Jr. # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # # - Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # - Redistributions in binary form must reproduce the above # copyright notice, this list of conditions and the following # disclaimer in the documentation and/or other materials provided # with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # use Getopt::Std; $usage = "$0: usage:\n\t$0 -H \n"; if (!getopts('Hd', \%opts)) { die $usage; } $html = defined($opts{'H'}) ? 1 : 0; $debug = defined($opts{'d'}) ? 1 : 0; if (@ARGV != 1) { die $usage; } $objectclass = lc(shift(@ARGV)); # From RFC 2252 %sy = ( '1.3.6.1.4.1.1466.115.121.1.1' => 'ACI Item', '1.3.6.1.4.1.1466.115.121.1.2' => 'Access Point', '1.3.6.1.4.1.1466.115.121.1.3' => 'Attribute Type Description', '1.3.6.1.4.1.1466.115.121.1.4' => 'Audio', '1.3.6.1.4.1.1466.115.121.1.5' => 'Binary', '1.3.6.1.4.1.1466.115.121.1.6' => 'Bit String', '1.3.6.1.4.1.1466.115.121.1.7' => 'Boolean', '1.3.6.1.4.1.1466.115.121.1.8' => 'Certificate', '1.3.6.1.4.1.1466.115.121.1.9' => 'Certificate List', '1.3.6.1.4.1.1466.115.121.1.10' => 'Certificate Pair', '1.3.6.1.4.1.1466.115.121.1.11' => 'Country String', '1.3.6.1.4.1.1466.115.121.1.12' => 'DN', '1.3.6.1.4.1.1466.115.121.1.13' => 'Data Quality Syntax', '1.3.6.1.4.1.1466.115.121.1.14' => 'Delivery Method', '1.3.6.1.4.1.1466.115.121.1.15' => 'Directory String', '1.3.6.1.4.1.1466.115.121.1.16' => 'DIT Content Rule Description', '1.3.6.1.4.1.1466.115.121.1.17' => 'DIT Structure Rule Description', '1.3.6.1.4.1.1466.115.121.1.18' => 'DL Submit Permission', '1.3.6.1.4.1.1466.115.121.1.19' => 'DSA Quality Syntax', '1.3.6.1.4.1.1466.115.121.1.20' => 'DSE Type', '1.3.6.1.4.1.1466.115.121.1.21' => 'Enhanced Guide', '1.3.6.1.4.1.1466.115.121.1.22' => 'Facsimile Telephone Number', '1.3.6.1.4.1.1466.115.121.1.23' => 'Fax', '1.3.6.1.4.1.1466.115.121.1.24' => 'Generalized Time', '1.3.6.1.4.1.1466.115.121.1.25' => 'Guide', '1.3.6.1.4.1.1466.115.121.1.26' => 'IA5 String', '1.3.6.1.4.1.1466.115.121.1.27' => 'INTEGER', '1.3.6.1.4.1.1466.115.121.1.28' => 'JPEG', '1.3.6.1.4.1.1466.115.121.1.54' => 'LDAP Syntax Description', '1.3.6.1.4.1.1466.115.121.1.56' => 'LDAP Schema Definition', '1.3.6.1.4.1.1466.115.121.1.57' => 'LDAP Schema Description', '1.3.6.1.4.1.1466.115.121.1.29' => 'Master And Shadow Access Points', '1.3.6.1.4.1.1466.115.121.1.30' => 'Matching Rule Description', '1.3.6.1.4.1.1466.115.121.1.31' => 'Matching Rule Use Description', '1.3.6.1.4.1.1466.115.121.1.32' => 'Mail Preference', '1.3.6.1.4.1.1466.115.121.1.33' => 'MHS OR Address', '1.3.6.1.4.1.1466.115.121.1.55' => 'Modify Rights', '1.3.6.1.4.1.1466.115.121.1.34' => 'Name And Optional UID', '1.3.6.1.4.1.1466.115.121.1.35' => 'Name Form Description', '1.3.6.1.4.1.1466.115.121.1.36' => 'Numeric String', '1.3.6.1.4.1.1466.115.121.1.37' => 'Object Class Description', '1.3.6.1.4.1.1466.115.121.1.40' => 'Octet String', '1.3.6.1.4.1.1466.115.121.1.38' => 'OID', '1.3.6.1.4.1.1466.115.121.1.39' => 'Other Mailbox', '1.3.6.1.4.1.1466.115.121.1.41' => 'Postal Address', '1.3.6.1.4.1.1466.115.121.1.42' => 'Protocol Information', '1.3.6.1.4.1.1466.115.121.1.43' => 'Presentation Address', '1.3.6.1.4.1.1466.115.121.1.44' => 'Printable String', '1.3.6.1.4.1.1466.115.121.1.58' => 'Substring Assertion', '1.3.6.1.4.1.1466.115.121.1.45' => 'Subtree Specification', '1.3.6.1.4.1.1466.115.121.1.46' => 'Supplier Information', '1.3.6.1.4.1.1466.115.121.1.47' => 'Supplier Or Consumer', '1.3.6.1.4.1.1466.115.121.1.48' => 'Supplier And Consumer', '1.3.6.1.4.1.1466.115.121.1.49' => 'Supported Algorithm', '1.3.6.1.4.1.1466.115.121.1.50' => 'Telephone Number', '1.3.6.1.4.1.1466.115.121.1.51' => 'Teletex Terminal Identifier', '1.3.6.1.4.1.1466.115.121.1.52' => 'Telex Number', '1.3.6.1.4.1.1466.115.121.1.53' => 'UTC Time', ); while (<>) { chomp(); if (s/^objectclasses(:|=)\s*//i) { if (! m/ ^\(\s+ (\S+) \s+NAME\s+'(\S+)' (\s+DESC\s+'([^']+)')? # (\s+SUP\s+('([^']+)'|\S+))? # (\s+ABSTRACT)? # (\s+AUXILIARY)? # (\s+STRUCTURAL)? # (\s+MUST\s+(\(((\s+\S+\s+\$)*\s+\S+\s+)\)|\S+))? # (\s+MAY\s+(\(((\s+\S+\s+\$)*\s+\S+\s+)\)|\S+))? # (\s+X-ORIGIN\s+(\((\s+('[^']+'\s+)+)\)|('([^']+)'|\S+)))? # \s+\)$ /x ) { print "argh objectclasses: \"$_\"\n"; next; } $oid = $1; $name = $2; $desc = $4 || undef; $sup = $7 || $6 || undef; $abstract = defined($8) || 0; $auxiliary = defined($9) || 0; $structural = defined($10) || 0; if (defined($13)) { $must = [ split(/\$/, $13) ]; } elsif (defined($12)) { $must = [ $12 ]; } else { undef($must); } if (defined($17)) { $may = [ split(/\$/, $17) ]; } elsif (defined($16)) { $may = [ $16 ]; } else { undef($may); } $x_origin = $21 || $20 || undef; foreach $i (@$must) { $i =~ s/\s+//g; } foreach $i (@$may) { $i =~ s/\s+//g; } $oc{lc($name)} = { 'oid' => $oid, 'name' => $name, 'desc' => $desc, 'sup' => $sup, 'abstract' => $abstract, 'auxiliary' => $auxiliary, 'structural' => $structural, 'must' => $must, 'may' => $may, 'x_origin' => $x_origin, }; if ($debug) { print "\n"; print "oid: ", $oc{lc($name)}{'oid'}, "\n"; print "name: ", $oc{lc($name)}{'name'}, "\n"; print "desc: ", $oc{lc($name)}{'desc'}, "\n"; print "sup: ", $oc{lc($name)}{'sup'}, "\n"; print "abstract: ", $oc{lc($name)}{'abstract'}, "\n"; print "auxiliary: ", $oc{lc($name)}{'auxiliary'}, "\n"; print "structural: ", $oc{lc($name)}{'structural'}, "\n"; print "must: ", join(" " , @{$oc{lc($name)}{'must'}}), "\n"; print "may: ", join(" " , @{$oc{lc($name)}{'may'}}), "\n"; print "x_origin: ", $oc{lc($name)}{'x_origin'}, "\n"; } } elsif (s/^attributetypes(:|=)\s*//i) { if (! m/ ^\(\s+ (\S+) \s+NAME\s+(\(\s+([^\)]+)\s+\)|\S+) (\s+DESC\s+'([^']+)')? (\s+SUP\s+'([^']+)')? (\s+EQUALITY\s+'([^']+)')? (\s+SUBSTR\s+'([^']+)')? (\s+ORDERING\s+'([^']+)')? (\s+SYNTAX\s+'([^']+)')? (\s+SINGLE-VALUE)? (\s+NO-USER-MODIFICATION)? (\s+USAGE\s+(\S+))? (\s+X-ORIGIN\s+'([^']+)')? # \s+\)$ /x ) { print "argh attributetypes: \"$_\"\n"; next; } $oid = $1; if (defined($3)) { $names = [ split(/\s+/, $3) ]; } else { $names = [ $2 ]; } $desc = $5 || undef; $sup = $7 || undef; $equality = $9 || undef; $substr = $11 || undef; $ordering = $13 || undef; $syntax = $15 || undef; $single_value = defined($16) || 0; $no_user_modification = defined($17) || 0; $usage = $19 || undef; $x_origin = $21 || undef; foreach $i (@$names) { $i =~ s/^'//; $i =~ s/'$//; } $syntax =~ s/{\d+}//; foreach $name (@$names) { $at{lc($name)} = { 'oid' => $oid, 'names' => $names, 'desc' => $desc, 'sup' => $sup, 'equality' => $equality, 'substr' => $substr, 'ordering' => $ordering, 'syntax' => $syntax, 'single_value' => $single_value, 'no_user_modification' => $no_user_modification, 'x_origin' => $x_origin, 'usage' => $usage, }; } $name = lc($$names[0]); if ($debug) { print "\n"; print "oid: ", $at{lc($name)}{'oid'}, "\n"; print "names: ", join(" ", @{$at{lc($name)}{'names'}}), "\n"; print "desc: ", $at{lc($name)}{'desc'}, "\n"; print "sup: ", $at{lc($name)}{'sup'}, "\n"; print "equality: ", $at{lc($name)}{'equality'}, "\n"; print "substr: ", $at{lc($name)}{'substr'}, "\n"; print "ordering: ", $at{lc($name)}{'ordering'}, "\n"; print "syntax: ", $at{lc($name)}{'syntax'}, "\n"; print "single_value: ", $at{lc($name)}{'single_value'}, "\n"; print "no_user_modification: ", $at{lc($name)}{'no_user_modification'}, "\n"; print "x_origin: ", $at{lc($name)}{'x_origin'}, "\n"; print "usage: ", $at{lc($name)}{'usage'}, "\n"; } } elsif (s/^matchingrules(:|=)\s*//i) { if (! m/ ^\(\s+ (\S+) \s+NAME\s+'(\S+)' (\s*DESC\s+'([^']+)')? (\s+SYNTAX\s+'([^']+)')? \s+\)$ /x ) { print "argh: \"$_\"\n"; next; } $oid = $1; $name = $2; $desc = $4 || undef; $syntax = $6 || undef; $mr{lc($name)} = { 'oid' => $oid, 'name' => $name, 'desc' => $desc, 'syntax' => $syntax, }; if ($debug) { print "\n"; print "oid: ", $mr{lc($name)}{'oid'}, "\n"; print "name: ", $mr{lc($name)}{'name'}, "\n"; print "desc: ", $mr{lc($name)}{'desc'}, "\n"; print "syntax: ", $mr{lc($name)}{'syntax'}, "\n"; } } } if (!exists($oc{$objectclass})) { die "objectclass \"$objectclass\" not found in schema\n"; } @objectclasses = ( $objectclass ); while (defined($oc{$objectclasses[0]}{'sup'})) { unshift(@objectclasses, lc($oc{$objectclasses[0]}{'sup'})); } if ($html) { print "\n"; print "\n"; print " LDAP schema attribute report for $objectclass\n"; print "\n"; print "\n"; print "

LDAP schema attribute report for $objectclass

\n"; print " \n"; } output( "--heading", "Description", "Name(s)", "Required", "Object Class", "Syntax", "Single-value", ); foreach $i (@objectclasses) { if (defined($oc{$i}{'may'})) { foreach $a (@{$oc{$i}{'may'}}) { output( $at{lc($a)}{'desc'}, join("/", @{$at{lc($a)}{'names'}}), "no", $oc{$i}{'name'}, $sy{$at{lc($a)}{'syntax'}}, ($at{lc($a)}{'single_value'} ? "yes" : "no"), ); } } if (defined($oc{$i}{'must'})) { foreach $a (@{$oc{$i}{'must'}}) { output( $at{lc($a)}{'desc'}, join("/", @{$at{lc($a)}{'names'}}), "yes", $oc{$i}{'name'}, $sy{$at{lc($a)}{'syntax'}}, ($at{lc($a)}{'single_value'} ? "yes" : "no"), ); } } } if ($html) { print "
\n"; print "\n"; print "\n"; } sub output { if ($html) { if (@_ > 0 && $html && $_[0] eq "--heading") { shift(@_); $datatag = "TH"; } else { $datatag = "TD"; } print(" \n"); foreach $q (@_) { print(" <$datatag>", $q , "\n"); } print(" \n"); } else { print(join(",", @_), "\n"); } }