diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | component_versions.mk | 8 | ||||
-rw-r--r-- | components.mk | 30 | ||||
-rw-r--r-- | ldap/admin/src/Makefile | 2 | ||||
-rwxr-xr-x | ldap/admin/src/logconv.pl | 1595 | ||||
-rw-r--r-- | ldap/cm/Makefile | 9 | ||||
-rw-r--r-- | ldap/servers/slapd/tools/Makefile | 9 | ||||
-rw-r--r-- | ldap/servers/slapd/tools/dbscan.c | 800 |
8 files changed, 2405 insertions, 50 deletions
@@ -86,7 +86,7 @@ help: components: $(ADMINUTIL_DEP) $(NSPR_DEP) $(ARLIB_DEP) $(DBM_DEP) $(SECURITY_DEP) $(SVRCORE_DEP) \ $(ICU_DEP) $(SETUPSDK_DEP) $(LDAPSDK_DEP) $(DB_LIB_DEP) $(SASL_DEP) $(PEER_DEP) \ - $(DSRK_DEP) $(AXIS_DEP) $(DSMLJAR_DEP) + $(AXIS_DEP) $(DSMLJAR_DEP) -@echo "The components are up to date" ifeq ($(BUILD_JAVA_CODE),1) diff --git a/component_versions.mk b/component_versions.mk index ab368795..2cdd46b3 100644 --- a/component_versions.mk +++ b/component_versions.mk @@ -55,14 +55,6 @@ ifndef LDAPCOMP_DIR LDAPCOMP_DIR=ldapsdk50 endif -# DSRK -ifndef DSRK_RELDATE - DSRK_RELDATE = 20041029 -endif -ifndef DSRKCOMP_DIR - DSRKCOMP_DIR=dsrk70 -endif - # CRIMSONJAR ifndef CRIMSONJAR_VERSION CRIMSONJAR_VERSION = 1.1.3 diff --git a/components.mk b/components.mk index 8fab4bad..7f222b4e 100644 --- a/components.mk +++ b/components.mk @@ -533,36 +533,6 @@ endif then echo "Error: could not get component LDAPSDK file $@" ; \ fi -#################################################### -# DSRK -#################################################### -ifndef DSRK_VERSION - DSRK_VERSION = $(DSRK_RELDATE)$(SEC_SUFFIX) -endif -ifndef DSRK_SBC -# DSRK_SBC = $(COMPONENTS_DIR_DEV) -DSRK_SBC = $(COMPONENTS_DIR) -endif - -DSRK_RELEASE = $(DSRK_SBC)/dsrk/$(DSRKCOMP_DIR)/$(DSRK_VERSION)/$(NSOBJDIR_NAME) -DSRK_FILES = bin,perl -DSRK_BUILD_DIR = $(NSCP_DISTDIR)/dsrk -DSRK_DEP = $(DSRK_BUILD_DIR)/bin/n$(DSRKCOMP_DIR) - -ifndef DSRK_PULL_METHOD -DSRK_PULL_METHOD = $(COMPONENT_PULL_METHOD) -endif - -$(DSRK_DEP): $(NSCP_DISTDIR_FULL_RTL) -ifdef COMPONENT_DEPS - $(FTP_PULL) -method $(DSRK_PULL_METHOD) \ - -objdir $(DSRK_BUILD_DIR) -componentdir $(DSRK_RELEASE) \ - -files $(DSRK_FILES) -endif - -@if [ ! -d $@ ] ; \ - then echo "Error: could not get component DSRK file $@" ; \ - fi - # apache-axis java classes ####################################### AXIS = axis-bin-$(AXIS_VERSION).zip AXIS_FILES = $(AXIS) diff --git a/ldap/admin/src/Makefile b/ldap/admin/src/Makefile index 93bf167a..dacce7c8 100644 --- a/ldap/admin/src/Makefile +++ b/ldap/admin/src/Makefile @@ -180,7 +180,7 @@ BINS = $(addprefix $(BINDIR)/, $(PROGS)) endif ALLOBJS = $(addprefix $(OBJDEST)/, $(OBJECTS)) -PERL_SCRIPTS = migrateTo4 uname.lib Cgi.pm migrateInstance getConfigInfo migrateLocalDB migratePwdFile ds_viewlog.pl upgradeServer updatedsgw +PERL_SCRIPTS = migrateTo4 uname.lib Cgi.pm migrateInstance getConfigInfo migrateLocalDB migratePwdFile ds_viewlog.pl upgradeServer updatedsgw logconv.pl PERL_SCRIPTS_DEST = $(addprefix $(BINDIR)/, $(PERL_SCRIPTS)) diff --git a/ldap/admin/src/logconv.pl b/ldap/admin/src/logconv.pl new file mode 100755 index 00000000..0d41cfb0 --- /dev/null +++ b/ldap/admin/src/logconv.pl @@ -0,0 +1,1595 @@ +#!/usr/bin/env perl + +# +# BEGIN COPYRIGHT BLOCK +# Copyright 2001 Sun Microsystems, Inc. +# Portions copyright 1999, 2001 Netscape Communications Corporation. +# All rights reserved. +# END COPYRIGHT BLOCK +# + +# +# Check for usage +# +use Time::Local; + +if ($#ARGV < 0){; +&displayUsage; +} + +####################################### +# # +# parse commandline switches # +# # +####################################### + +$x = "0"; +$fc = 0; +$sn = 0; +$manager = "cn=directory manager"; +$logversion = "6.0"; +$sizeCount = "20"; +$startFlag = 0; +$startTime = 0; +$endFlag = 0; +$endTime = 0; + +while ($sn <= $#ARGV) +{ + if ("$ARGV[$sn]" eq "-d") + { + $manager = $ARGV[++$sn]; + } + elsif ("$ARGV[$sn]" eq "-v") + { + print "Netscape Access Log Analyzer v$logversion\n";; + exit (0); + } + elsif ("$ARGV[$sn]" eq "-V") + { + $verb = "yes"; + } + elsif ("$ARGV[$sn]" eq "-X"){ + $exclude[$x] = $ARGV[++$sn]; + $x++; + } + elsif ("$ARGV[$sn]" eq "-s") + { + $sizeCount = $ARGV[++$sn]; + } + elsif ("$ARGV[$sn]" eq "-S") + { + $startTime = $ARGV[++$sn]; + } + elsif ("$ARGV[$sn]" eq "-E") + { + $endTime = $ARGV[++$sn]; + } + elsif ("$ARGV[$sn]" eq "-h") + { + &displayUsage; + } + elsif ("$ARGV[$sn]" =~ m/^-/){ + $usage = $ARGV[$sn]; + } + else + { + $files[$fc] = $ARGV[$sn]; + $fc++; + } + $sn++; +} + +if ($sizeCount eq "all"){$sizeCount = "100000";} + +####################################### +# # +# Initialize Arrays and variables # +# # +####################################### + +print "\nNetscape Access Log Analyzer $logversion\n"; +print "\nCommand : logconv.pl @ARGV\n\n"; + +$dirmgr = "0"; +$notes = "0"; +$vlvnotes= "0"; +$search = "0"; +$fdtake = "0"; +$fdreturn = "0"; +$highfd = "0"; +$bind = "0"; +$unbind = "0"; +$anony = "0"; +$mod = "0"; +$delete = "0"; +$add = "0"; +$modrdn = "0"; +$restarts = "0"; +$resource = "0"; +$broken = "0"; +$vlv = "0"; +$version2 = "0"; +$version3 = "0"; +$sortvlv = "0"; +$reset = "0"; +$vet = "0"; +$v = "0"; +$errorck = "0"; +$errorsucc = "0"; +$sslconn = "0"; +$sslClientBind = "0"; +$sslClientFailed = "0"; +$objectclass= "0"; +$nc = "0"; +$no = "0"; +$nt = "0"; +$nb = "0"; +$bc = "0"; +$fcc = "0"; +$nent = "0"; +$allOps = "0"; +$allResults = "0"; +$bpc = "0"; +$bpo = "0"; +$bpi = 0; +$abandon = "0"; +$mmasterop = "0"; +$extendedop = "0"; +$sasl = "0"; +$internal = "0"; +$entryOp = "0"; +$referral = "0"; +$anyAttrs = "0"; +$persistent = "0"; +$sconn = "0"; +$dconn = "0"; +$aconn = "0"; +$mconn = "0"; +$mdconn = "0"; +$bconn = "0"; +$ubconn = "0"; +$econn = "0"; +$connectionCount = "0"; +$timerange = 0; +$simConnection = 0; +$maxsimConnection = 0; + +$err[0] = "Successful Operations\n"; +$err[1] = "Operations Error(s)\n"; +$err[2] = "Protocal Errors\n"; +$err[3] = "Time Limit Exceeded\n"; +$err[4] = "Size Limit Exceeded\n"; +$err[5] = "Compare False\n"; +$err[6] = "Compare True\n"; +$err[7] = "Strong Authentication Not Supported\n"; +$err[8] = "Strong Authentication Required\n"; +$err[9] = "Partial Results\n"; +$err[10] = "Referral Received\n"; +$err[11] = "Administrative Limit Exceeded (Look Through Limit)\n"; +$err[12] = "Unavailable Critical Extension\n"; +$err[13] = "Confidentiality Required\n"; +$err[14] = "SASL Bind in Progress\n"; +$err[16] = "No Such Attribute\n"; +$err[17] = "Undefined Type\n"; +$err[18] = "Inappropriate Matching\n"; +$err[19] = "Constraint Violation\n"; +$err[20] = "Type or Value Exists\n"; +$err[21] = "Invalid Syntax\n"; +$err[32] = "No Such Object\n"; +$err[33] = "Alias Problem\n"; +$err[34] = "Invalid DN Syntax\n"; +$err[35] = "Is Leaf\n"; +$err[36] = "Alias Deref Problem\n"; +$err[48] = "Inappropriate Authentication (No password presented, etc)\n"; +$err[49] = "Invalid Credentials (Bad Password)\n"; +$err[50] = "Insufficent (write) Privledges\n"; +$err[51] = "Busy\n"; +$err[52] = "Unavailable\n"; +$err[53] = "Unwilling To Perform\n"; +$err[54] = "Loop Detected\n"; +$err[60] = "Sort Control Missing\n"; +$err[61] = "Index Range Error\n"; +$err[64] = "Naming Violation\n"; +$err[65] = "Objectclass Violation\n"; +$err[66] = "Not Allowed on Non Leaf\n"; +$err[67] = "Not Allowed on RDN\n"; +$err[68] = "Already Exists\n"; +$err[69] = "No Objectclass Mods\n"; +$err[70] = "Results Too Large\n"; +$err[71] = "Effect Multiple DSA's\n"; +$err[80] = "Other :-)\n"; +$err[81] = "Server Down\n"; +$err[82] = "Local Error\n"; +$err[83] = "Encoding Error\n"; +$err[84] = "Decoding Error\n"; +$err[85] = "Timeout\n"; +$err[86] = "Authentication Unknown\n"; +$err[87] = "Filter Error\n"; +$err[88] = "User Canceled\n"; +$err[89] = "Parameter Error\n"; +$err[90] = "No Memory\n"; +$err[91] = "Connect Error\n"; +$err[92] = "Not Supported\n"; +$err[93] = "Control Not Found\n"; +$err[94] = "No Results Returned\n"; +$err[95] = "More Results To Return\n"; +$err[96] = "Client Loop\n"; +$err[97] = "Referral Limit Exceeded\n"; + + +$conn{"A1"} = "A1"; +$conn{"B1"} = "B1"; +$conn{"B4"} = "B4"; +$conn{"T1"} = "T1"; +$conn{"T2"} = "T2"; +$conn{"B2"} = "B2"; +$conn{"B3"} = "B3"; +$conn{"R1"} = "R1"; +$conn{"P1"} = "P1"; +$conn{"P2"} = "P2"; +$conn{"U1"} = "U1"; + +$connmsg{"A1"} = "Client Aborted Connections"; +$connmsg{"B1"} = "Bad Ber Tag Encountered"; +$connmsg{"B4"} = "Server failed to flush data (response) back to Client"; +$connmsg{"T1"} = "Idle Timeout Exceeded"; +$connmsg{"T2"} = "IO Block Timeout Exceeded or NTSSL Timeout"; +$connmsg{"B2"} = "Ber Too Big"; +$connmsg{"B3"} = "Ber Peek"; +$connmsg{"R1"} = "Revents"; +$connmsg{"P1"} = "Plugin"; +$connmsg{"P2"} = "Poll"; +$connmsg{"U1"} = "Cleanly Closed Connections"; + +%monthname = ( + "Jan" => 1, + "Feb" => 2, + "Mar" => 3, + "Apr" => 4, + "May" => 5, + "Jun" => 6, + "Jul" => 7, + "Aug" => 8, + "Sep" => 9, + "Oct" => 10, + "Nov" => 11, + "Dec" => 12, + +); + +########################################## +# # +# Parse Access Logs # +# # +########################################## + +if ($files[$#files] =~ m/access.rotationinfo/) { $fc--; } + +print "Processing $fc Access Log(s)...\n\n"; + +print "Filename\t\t\tTotal Lines\tLines processed\n"; +print "---------------------------------------------------------------\n"; +for ($count=0; $count < $fc; $count++){ + $logsize = `wc -l $files[$count]`; + $logsize =~ /([0-9]+)/; + $ff="";$iff=""; + print sprintf "%-30s %7s",$files[$count],$1; +open(LOG,"$files[$count]") || die "Error: Can't open file $infile: $!"; + +$firstline = "yes"; +while (<LOG>) { + unless ($endFlag) { + if ($firstline eq "yes"){ + if (/^\[/) { + $tline = $_; + $firstline = "no"; + } + $ff++;$iff++; + } elsif (/^\[/ && $firstline eq "no"){ + &parseLine($tline); + $tline = $_; + } else { + $tline = $tline . $_; + $tline =~ s/\n//; + } + } +} +&parseLine($tline); +close (LOG); +print sprintf "\t\t%10s\n",--$ff; +} + +$notes = $notes - $vlvnotes; +if ($notes < 0){ $notes = "0";} + +$allOps = $search + $mod + $add + $delete + $modrdn + $bind + $extendedop; + +##################################### +# # +# Display Basic Results # +# # +##################################### + + +print "\n\n----------- Access Log Output ------------\n"; +if ($startTime) {print "\nStart of Log: $start\n";} +if ($endTime) {print "\nEnd of Log: $end\n";} +print "\nRestarts: $restarts\n"; +print "\n"; +print "Total Connections: $connectionCount\n"; +print "Peak Concurrent Connections: $maxsimConnection\n"; +print "Total Operations: $allOps\n"; +print "Total Results: $allResults\n"; +if ($allOps ne "0"){ + print sprintf "Overall Performance: %.1f%\n\n" , ($perf = ($tmp = ($allResults / $allOps)*100) > 100 ? 100.0 : $tmp) ; + } +else { + print "Overall Performance: No Operations to evaluate\n\n"; +} +print "Searches: $search\n"; +print "Modifications: $mod\n"; +print "Adds: $add\n"; +print "Deletes: $delete\n"; +print "Mod RDNs: $modrdn\n"; +print "\n"; +print "6.x Stats \n"; +print "Persistent Searches: $persistent\n"; +print "Internal Operations: $internal\n"; +print "Entry Operations: $entryOp\n"; +print "Extended Operations: $extendedop\n"; +print "Abandoned Requests: $abandon\n"; +print "Smart Referrals Received: $referral\n"; +print "\n"; +print "VLV Operations: $vlv\n"; +print "VLV Unindexed Searches: $vlvnotes\n"; +print "SORT Operations: $sortvlv\n"; +print "SSL Connections: $sslconn\n"; +print "\n"; +print "Entire Search Base Queries: $objectclass\n"; +print "Unindexed Searches: $notes\n"; +if ($verb eq "yes" || $usage =~ /u/){ +if ($notes > 0){ + $ns = "1"; + for ($n = 0; $n <= $#notesEtime; $n++){ + @alreadyseenDN = (); + print "\n Unindexed Search #".$ns."\n"; + $ns++; + print " - Date/Time: $notesTime[$n]\n"; + print " - Connection Number: $notesConn[$n]\n"; + print " - Operation Number: $notesOp[$n]\n"; + print " - Etime: $notesEtime[$n]\n"; + print " - Nentries: $notesNentries[$n]\n"; + print " - IP Address: $conn_hash{$notesConn[$n]}\n"; + print " - Search Base: $notesBase[$n]\n"; + print " - Scope: $notesScope[$n]\n"; + for ($nn = 0; $nn <= $bc; $nn++){ + if ($notesConn[$n] eq $bindInfo[$nn][1]) { + + ## Here, we check if the bindDN is already printed. + ## If not, we print it and push it to @alreadyseenDN. + ## So, in the beginning, we iterate thru @alreadyseenDN + + for ($j=0, $DNisThere=0; $j <=$#alreadyseenDN; $j++) { + if ($alreadyseenDN[$j] eq $bindInfo[$nn][0]) { + $DNisThere = 1; + } + } + unless ($DNisThere) { + print " - Bind DN: $bindInfo[$nn][0]\n"; + push @alreadyseenDN, $bindInfo[$nn][0]; + } + } + } + for ($nnn = 0; $nnn <= $fcc; $nnn++){ + if ($notesConn[$n] eq $filterInfo[$nnn][1] && $notesOp[$n] eq $filterInfo[$nnn][2]){ + print " - Search Filter: $filterInfo[$nnn][0]\n"; + } + } + } +} + +} + +print "\n"; +print "FDs Taken: $fdtake\n"; +print "FDs Returned: $fdreturn\n"; +print "Highest FD Taken: $highfd\n\n"; +print "Broken Pipes: $broken\n"; +if ($broken > 0){ + foreach $key (sort { $rc{$b} <=> $rc{$a} } keys %rc) { + if ($rc{$key} > 0){ + if ($conn{$key} eq ""){$conn{$key} = "** Unknown **";} + push @etext, sprintf " - %-4s (%2s) %-40s\n",$rc{$key},$conn{$key},$connmsg{$key +}; + } + } + print @etext; + print "\n"; +} + +print "Connections Reset By Peer: $reset\n"; +if ($reset > 0){ + foreach $key (sort { $src{$b} <=> $src{$a} } keys %src) { + if ($src{$key} > 0){ + if ($conn{$key} eq ""){$conn{$key} = "** Unknown **";} + push @retext, sprintf " - %-4s (%2s) %-40s\n",$src{$key},$conn{$key},$connmsg{$key +}; + } + } + print @retext; + print "\n"; +} + +print "Resource Unavailable: $resource\n"; +if ($resource > 0){ + foreach $key (sort { $rsrc{$b} <=> $rsrc{$a} } keys %rsrc) { + if ($rsrc{$key} > 0){ + if ($conn{$key} eq ""){$conn{$key} = "** Resource Issue **";} + push @rtext, sprintf " - %-4s (%2s) %-40s\n",$rsrc{$key},$conn{$key},$connmsg{$key}; + } + } + print @rtext; +} +print "\n"; +print "Binds: $bind\n"; +print "Unbinds: $unbind\n"; +print "\n LDAP v2 Binds: $version2\n"; +print " LDAP v3 Binds: $version3\n"; +print " SSL Client Binds: $sslClientBind\n"; +print " Failed SSL Client Binds: $sslClientFailed\n"; +print " SASL Binds: $sasl\n"; +if ($sasl > 0){ + foreach $saslb ( sort {$saslmech{$b} <=> $saslmech{$a} } (keys %saslmech) ){ + printf " %-4s %-12s\n",$saslmech{$saslb}, $saslb; + } +} + +print "\n Directory Manager Binds: $dirmgr\n"; +print " Anonymous Binds: $anony\n"; +$other = $bind -($dirmgr + $anony); +print " Other Binds: $other"; + +if ($verb eq "yes" || $usage =~ /y/){ +print "\n\n----- Connection Latency Details -----\n\n"; +print " (in seconds)\t\t<=1\t2\t3\t4-5\t6-10\t11-15\t>15\n"; +print " --------------------------------------------------------------------------\n"; +print " (# of connections)\t"; +for ($i=0; $i <=$#latency; $i++) { + print "$latency[$i]\t"; +} +} + +if ($verb eq "yes" || $usage =~ /p/){ +print "\n\n----- Current Open Connection IDs ----- \n\n"; +for ($i=0; $i <= $#openConnection ; $i++) { + if ($openConnection[$i]) { + print "\t$i\n"; + } +} +} + +################################### +# # +# Display Error Codes # +# # +################################### + +if ($usage =~ /e/i || $verb eq "yes"){ +print "\n\n----- Errors -----\n"; + +%er = sort( {$b <=> $a} %er); +for ($i = 0; $i<98; $i++){ + if ($err[$i] ne "" && $er[$i] >0) { + push @errtext, sprintf "%-8s %12s %-25s","err=$i",$er[$i],$err[$i]; + } +} + +for ($i = 0; $i < $#errtext; $i++){ + + for ($ii = 0; $ii < $#errtext; $ii++){ + $yy="0"; + $zz="0"; + while ($errtext[$ii] =~ /(\w+)\s/g){ + $errornum[$yy]="$1"; + $yy++; + } + while ($errtext[$ii+1] =~ /(\w+)\s/g){ + $errornum2[$zz]="$1"; + $zz++; + } + + if ($errornum2[1] > $errornum[1]){ + $tmp = $errtext[$ii]; + $errtext[$ii] = $errtext[$ii+1]; + $errtext[$ii+1] = $tmp; + } + } +} + +for ($i = 0; $i <= $#errtext; $i++){ + $errtext[$i] =~ s/\n//g; + print "\n" . $errtext[$i]; +} + +} + +#################################### +# # +# Print Failed Logins # +# # +#################################### + +if ($verb eq "yes" || $usage =~ /f/i ){ +if ($bpc > 0){ +print "\n\n----- Top $sizeCount Failed Logins ------\n\n"; + +if ($ds6x eq "true"){ + $eloop = "0"; + foreach $dsbp (sort { $ds6xbadpwd{$b} <=> $ds6xbadpwd{$a} } keys %ds6xbadpwd) { + if ($eloop > $sizeCount){ last; } + printf "%-4s %-40s\n", $ds6xbadpwd{$dsbp}, $dsbp; + } + +} else { +for ($ii =0 ; $ii < $bpc; $ii++){ + for ($i = 0; $i < $bc; $i++){ + if ($badPasswordConn[$ii] eq $bindInfo[$i][1] && $badPasswordOp[$ii] eq $bindInfo[$i][2] ){ + $badPassword{ "$bindInfo[$i][0]" } = $badPassword{ "$bindInfo[$i][0]" } + 1; + } + } +} + +# sort the new list of $badPassword{} + +$bpTotal = "0"; +$bpCount = "0"; +foreach $badpw (sort {$badPassword{$b} <=> $badPassword{$a} } keys %badPassword){ + if ($bpCount > $sizeCount){ last;} + $bpCount++; + $bpTotal = $bpTotal + $badPassword{"$badpw"}; + printf "%-4s %-40s\n", $badPassword{"$badpw"}, $badpw; +} + +print "\nFrom the IP address(s) :\n\n"; +for ($i=0; $i<$bpi; $i++) { + print "\t\t$badPasswordIp[$i]\n"; +} + +if ($bpTotal > $bpc){ + print "\n** Warning : Wrongly reported failed login attempts : ". ($bpTotal - $bpc) . "\n"; +} +} # this ends the if $ds6x = true + +} + +} + + +#################################### +# # +# Print Connection Codes # +# # +#################################### + + +if ($concount > 0){ +if ($usage =~ /c/i || $verb eq "yes"){ + print "\n\n----- Total Connection Codes -----\n\n"; + + foreach $key (sort { $conncount{$b} <=> $conncount{$a} } keys %conncount) { + if ($conncount{$key} > 0){ + push @conntext, sprintf "%-4s %6s %-40s\n",$conn{ $key },$conncount{$key},$connmsg{ $key }; + } + } +print @conntext; +} + +} + +######################################## +# # +# Gather and Process all unique IPs # +# # +######################################## + +if ($usage =~ /i/i || $verb eq "yes"){ +@ipkeys = keys %ip_hash; +@exxCount = keys %exCount; +$ip_count = ($#ipkeys + 1)-($#exxCount + 1); +if ($ip_count > 0){ + print "\n\n----- Top $sizeCount Clients -----\n\n"; + print "Number of Clients: $ip_count\n\n"; + + foreach $key (sort { $ip_hash{$b}{"count"} <=> $ip_hash{$a}{"count"} } keys %ip_hash) { + $exc = "no"; + if ($ccount > $sizeCount){ last;} + $ccount++; + for ($xxx =0; $xxx <= $#exclude; $xxx++){ + if ($exclude[$xxx] eq $key){$exc = "yes";} + } + if ($exc ne "yes"){ + if ($ip_hash{ $key }{"count"} eq ""){$ip_hash{ $key }{"count"} = "*";} + printf "%-6s %-17s\n", $ip_hash{ $key }{"count"}, $key; + } + + if ($exc ne "yes"){ + foreach $code (sort { $ip_hash{ $key }{$b} <=> $ip_hash{ $key }{$a} } keys %{$ip_hash{ $key }}) { + if ($code eq 'count' ) { next; } + printf "\t\t %6s - %3s %s\n", $ip_hash{ $key }{ $code }, $code, $connmsg{ $code }; + } + } + + if ($exc ne "yes"){ print "\n";} + } +} +} + + + +################################### +# # +# Gather All unique Bind DN's # +# # +################################### + +if ($usage =~ /b/i || $verb eq "yes"){ +@bindkeys = keys %bindlist; +$bind_count = $#bindkeys + 1; +if ($bind_count > 0){ + print "\n----- Top $sizeCount Bind DN's -----\n\n"; + print "Number of Unique Bind DN's: $bind_count\n\n"; + + $bindcount = 0; + + foreach $dn (sort { $bindlist{$b} <=> $bindlist{$a} } keys %bindlist) { + if ($bindcount < $sizeCount){ + printf "%-8s %-40s\n", $bindlist{ $dn },$dn; + } + $bindcount++; + } +} + +} + + +######################################### +# # +# Gather and process search bases # +# # +######################################### + +if ($usage =~ /a/i || $verb eq "yes"){ +@basekeys = keys %base; +$base_count = $#basekeys + 1; +if ($base_count > 0){ + print "\n\n----- Top $sizeCount Search Bases -----\n\n"; + print "Number of Unique Search Bases: $base_count\n\n"; + + $basecount = 0; + + foreach $bas (sort { $base{$b} <=> $base{$a} } keys %base) { + if ($basecount < $sizeCount){ + printf "%-8s %-40s\n", $base{ $bas },$bas; + } + $basecount++; + } +} + +} + +######################################### +# # +# Gather and process search filters # +# # +######################################### + +if ($usage =~ /l/ || $verb eq "yes"){ + +@filterkeys = keys %filter; +$filter_count = $#filterkeys + 1; +if ($filter_count > 0){ + print "\n\n----- Top $sizeCount Search Filters -----\n"; + print "\nNumber of Unique Search Filters: $filter_count\n\n"; + + $filtercount = 0; + + foreach $filt (sort { $filter{$b} <=> $filter{$a} } keys %filter){ + if ($filtercount < $sizeCount){ + printf "%-8s %-40s\n", $filter{$filt}, $filt; + } + $filtercount++; + } +} + +} + +######################################### +# # +# Gather and Process the unique etimes # +# # +######################################### + + +# +# print most often etimes +# + +if ($usage =~ /t/i || $verb eq "yes"){ +print "\n\n----- Top $sizeCount Most Frequent etimes -----\n\n"; +$eloop = 0; +foreach $et (sort { $etime{$b} <=> $etime{$a} } keys %etime) { + if ($eloop == $sizeCount) { last; } + if ($retime ne "2"){ + $first = $et; + $retime = "2"; + } + printf "%-8s %-12s\n", $etime{ $et }, "etime=$et"; + $eloop++; +} + +# +# print longest etimes +# + +print "\n\n----- Top $sizeCount Longest etimes -----\n\n"; +$eloop = 0; +foreach $et (sort { $b <=> $a } (keys %etime)) { + if ($eloop == $sizeCount) { last; } + printf "%-12s %-10s\n","etime=$et",$etime{ $et }; + $eloop++; +} + +} + +####################################### +# # +# Gather and Process unique nentries # +# # +####################################### + + +if ($usage =~ /n/i || $verb eq "yes"){ +print "\n\n----- Top $sizeCount Largest nentries -----\n\n"; +$eloop = 0; +foreach $nentry (sort { $b <=> $a } (keys %nentries)){ + if ($eloop == $sizeCount) { last; } + printf "%-18s %12s\n","nentries=$nentry", $nentries{ $nentry }; + $eloop++; +} + +print "\n\n----- Top $sizeCount Most returned nentries -----\n\n"; +$eloop = 0; +foreach $nentry (sort { $nentries{$b} <=> $nentries{$a} } (keys %nentries)){ + if ($eloop == $sizeCount) { last; } + printf "%-12s %-14s\n", $nentries{ $nentry }, "nentries=$nentry"; + $eloop++; +} + +print "\n"; +} + + +############################################### +# # +# Gather and process extended operations 6.x # +# # +############################################### + +if ($usage =~ /x/i || $verb eq "yes"){ + +if ($extendedop > 0){ +print "\n\n----- 6.x Extended Operations -----\n\n"; +foreach $oids (sort { $oid{$b} <=> $oid{$a} } (keys %oid) ){ + + if ($oids eq "2.16.840.1.113730.3.5.1"){ $oidmessage = "Transaction Request"} + elsif ($oids eq "2.16.840.1.113730.3.5.2"){ $oidmessage = "Transaction Response"} + elsif ($oids eq "2.16.840.1.113730.3.5.3"){ $oidmessage = "Start Replication Request (incremental update)"} + elsif ($oids eq "2.16.840.1.113730.3.5.4"){ $oidmessage = "Replication Response"} + elsif ($oids eq "2.16.840.1.113730.3.5.5"){ $oidmessage = "End Replication Request (incremental update)"} + elsif ($oids eq "2.16.840.1.113730.3.5.6"){ $oidmessage = "Replication Entry Request"} + elsif ($oids eq "2.16.840.1.113730.3.5.7"){ $oidmessage = "Start Bulk Import"} + elsif ($oids eq "2.16.840.1.113730.3.5.8"){ $oidmessage = "Finished Bulk Import"} + elsif ($oids eq "2.16.840.1.113730.3.6.1"){ $oidmessage = "Incremental Update Replication Protocol"} + elsif ($oids eq "2.16.840.1.113730.3.6.2"){ $oidmessage = "Total Update Replication Protocol (Initialization)"} + elsif ($oids eq "2.16.840.1.113730.3.5.9"){ $oidmessage = "Digest Authentication (iWS 6.x)"} + else {$oidmessage = "Other"} + + printf "%-6s %-23s %-60s\n", $oid{ $oids }, $oids, $oidmessage; +} +} + +} + +############################################ +# +# Print most commonly requested attributes +# +############################################ + +if ($usage =~ /r/i || $verb eq "yes"){ +if ($anyAttrs > 0){ +print "\n\n----- Top $sizeCount Most Requested Attributes -----\n\n"; +$eloop = "0"; +foreach $mostAttr (sort { $attr{$b} <=> $attr{$a} } (keys %attr) ){ + if ($eloop eq $sizeCount){ last; } + printf "%-10s %-19s\n", $attr{$mostAttr}, $mostAttr; + $eloop++; +} +} + +} + +################################# +# +# abandoned operation stats +# +################################# + +if ($usage =~ /g/i || $verb eq "yes"){ +$acTotal = $sconn + $dconn + $mconn + $aconn + $mdconn + $bconn + $ubconn + $econn; +if ($verb eq "yes" && $ac > 0 && $acTotal > 0){ + +print "\n\n----- Abandon Request Stats -----\n\n"; + + for ($g = 0; $g < $ac; $g++){ + for ($sc = 0; $sc < $sconn; $sc++){ + if ($srchConn[$sc] eq $targetConn[$g] && $srchOp[$sc] eq $targetOp[$g] ){ + print " - SRCH conn=$targetConn[$g] op=$targetOp[$g] msgid=$msgid[$g] client=$conn_hash{$targetConn[$g]}\n"; + } + } + for ($dc = 0; $dc < $dconn; $dc++){ + if ($delConn[$dc] eq $targetConn[$g] && $delOp[$dc] eq $targetOp[$g]){ + print " - DEL conn=$targetConn[$g] op=$targetOp[$g] msgid=$msgid[$g] client=$conn_hash{$targetConn[$g]}\n"; + } + } + for ($adc = 0; $adc < $aconn; $adc++){ + if ($addConn[$adc] eq $targetConn[$g] && $addOp[$adc] eq $targetOp[$g]){ + print " - ADD conn=$targetConn[$g] op=$targetOp[$g] msgid=$msgid[$g] client=$conn_hash{$targetConn[$g]}\n"; + } + } + for ($mc = 0; $mc < $mconn; $mc++){ + if ($modConn[$mc] eq $targetConn[$g] && $modOp[$mc] eq $targetOp[$g]){ + print " - MOD conn=$targetConn[$g] op=$targetOp[$g] msgid=$msgid[$g] client=$conn_hash{$targetConn[$g]}\n"; + } + } + for ($mdc = 0; $mdc < $mdconn; $mdc++){ + if ($modrdnConn[$mdc] eq $targetConn[$g] && $modrdnOp[$mdc] eq $targetOp[$g]){ + print " - MODRDN conn=$targetConn[$g] op=$targetOp[$g] msgid=$msgid[$g] client=$conn_hash{$targetConn[$g]}\n"; + } + } + for ($bcb = 0; $bcb < $bconn; $bcb++){ + if ($bindConn[$bcb] eq $targetConn[$g] && $bindOp[$bcb] eq $targetOp[$g]){ + print " - BIND conn=$targetConn[$g] op=$targetOp[$g] msgid=$msgid[$g] client=$conn_hash{$targetConn[$g]}\n"; + } + } + for ($ubc = 0; $ubc < $ubconn; $ubc++){ + if ($unbindConn[$ubc] eq $targetConn[$g] && $unbindOp[$ubc] eq $targetOp[$g]){ + print " - UNBIND conn=$targetConn[$g] op=$targetOp[$g] msgid=$msgid[$g] client=$conn_hash{$targetConn[$g]}\n"; + } + } + for ($ec = 0; $ec < $econn; $ec++){ + if ($extConn[$ec] eq $targetConn[$g] && $extOp[$ec] eq $targetOp[$g]){ + print " - EXT conn=$targetConn[$g] op=$targetOp[$g] msgid=$msgid[$g] client=$conn_hash{$targetConn[$g]}\n"; + } + } + + + } +} + +} + + + +print "\n"; + +####################################### +# # +# Recommendations # +# # +####################################### + +if ($usage =~ /j/i || $verb eq "yes"){ +print "\n----- Recommendations -----\n"; +$recCount = "1"; +if ($notes > 0){ + print "\n $recCount. You have unindexed searches, this can be caused from a search on an unindexed attribute, or your returned results exceeded the allidsthreshold. Unindexed searches are not recommended. To refuse unindexed searches, switch \'nsslapd-require-index\' to \'on\' under your database entry (e.g. cn=UserRoot,cn=ldbm database,cn=plugins,cn=config).\n"; + $recCount++; + } + +if ($conncount{"T1"} > 0){ + print "\n $recCount. You have some connections that are are being closed by the idletimeout setting. You may want to increase the idletimeout if it is set low.\n"; + $recCount++; + } + +if ($conncount{"T2"} > 0){ + print "\n $recCount. You have some coonections that are being closed by the ioblocktimeout setting. You may want to increase the ioblocktimeout.\n"; + $recCount++; + } + +# compare binds to unbinds, if the difference is more than 30% of the binds, then report a issue + +if (($bind - $unbind) > ($bind*.3)){ + print "\n $recCount. You have a significant difference between binds and unbinds. You may want to investigate this difference.\n"; + $recCount++; + } + +# compare fds taken and return, if the difference is more than 30% report a issue + +if (($fdtaken -$fdreturn) > ($fdtaken*.3)){ + print "\n $recCount. You have a significant difference between file descriptors taken and file descriptors returned. You may want to investigate this difference.\n"; + $recCount++; + } + +if ($dirmgr > ($bind *.2)){ + print "\n $recCount. You have a high number of Directory Manager binds. The Directory Manager account should only be used under certain circumstances. Avoid using this account for client applications.\n"; + $recCount++; + } + +if ($errorck > $errorsucc){ + print "\n $recCount. You have more unsuccessful operations than successful operations. You should investigate this difference.\n"; + $recCount++; + } + +if ($conncount{"U1"} < ($concount - $conncount{"U1"})){ + print "\n $recCount. You have more abnormal connection codes than cleanly closed connections. You may want to investigate this difference.\n"; + $recCount++; + } + +if ($first > 0){ + print "\n $recCount. You have a majority of etimes that are greater than zero, you may want to investigate this performance problem.\n"; + $recCount++; + } + +if ($objectclass > ($search *.25)){ + print "\n $recCount. You have a high number of searches that query the entire search base. Although this is not necessarily bad, it could be resource intensive if the search base contains many entries.\n"; + $recCount++; + } + +if ($recCount == 1){ + print "\nNone.\n"; + } +} + +print "\n"; + +# dispaly usage + +sub displayUsage { + + print "Usage:\n\n"; + + print " ./logconv.pl [-h] [-d <rootDN>] [-s <size limit>] [-v] [-V]\n"; + print " [-S <start time>] [-E <end time>]\n"; + print " [-efcibaltnxgju] [ access log ... ... ]\n\n"; + + print "- Commandline Switches:\n\n"; + + print " -h help/usage\n"; + print " -d <Directory Managers DN> DEFAULT -> cn=directory manager\n"; + print " -s <Number of results to return per catagory> DEFAULT -> 20\n"; + print " -X <IP address to exclude from connection stats> E.g. Load balancers\n"; + print " -v show version of tool\n"; + print " -S <time to begin analyzing logfile from>\n"; + print " E.g. [28/Mar/2002:13:14:22 -0800]\n"; + print " -E <time to stop analyzing logfile>\n"; + print " E.g. [28/Mar/2002:13:24:62 -0800]\n"; + print " -V <enable verbose output - includes all stats listed below>\n"; + print " -[efcibaltnxgju]\n\n"; + + print " e Error Code stats\n"; + print " f Failed Login Stats\n"; + print " c Connection Code Stats\n"; + print " i Client Stats\n"; + print " b Bind Stats\n"; + print " a Search Base Stats\n"; + print " l Search Filter Stats\n"; + print " t Etime Stats\n"; + print " n Nentries Stats\n"; + print " x Extended Operations\n"; + print " r Most Requested Attribute Stats\n"; + print " g Abandoned Operation Stats\n"; + print " j Recommendations\n"; + print " u Unindexed Search Stats\n"; + print " y Connection Latency Stats\n"; + print " p Open Connection ID Stats\n\n"; + + print " Examples:\n\n"; + + print " ./logconv.pl -s 10 -V access\n\n"; + + print " ./logconv.pl -d cn=dm /export/server4/slapd-host/logs/access*\n\n"; + + print " ./logconv.pl -s 50 -ibgju access*\n\n"; + + print " ./logconv.pl -S \"\[28/Mar/2002:13:14:22 -0800\]\" -E \"\[28/Mar/2002:13:50:05 -0800\]\" -e access\n\n"; + + exit 1; +} + +###################################################### +# +# Parsing Routine That Does The Actual Parsing Work +# +###################################################### + +sub parseLine { +local $_ = $tline; + +if ($startTime && !$startFlag) { + if (index($_, $startTime) == 0) { + $startFlag = 1; + ($start) = $startTime =~ /\D*(\S*)/; + } else { + return; + } +} + +if ($endTime && !$endFlag) { + if (index($_, $endTime) == 0) { + $endFlag = 1; + ($end) = $endTime =~ /\D*(\S*)/; + } +} + +$ff++; +$iff++; +if ($iff >= 1000){ print STDERR sprintf" %10s Lines Processed\n",$ff; $iff="0";} + +if (m/ RESULT err/){$allResults++;} +if (m/ SRCH/){ + $search++; + if ($_ =~ / attrs=\"(.*)\"/i){ + $anyAttrs++; + $attrs = $1 . " "; + while ($attrs =~ /(\S+)\s/g){ + $attr{$1}++; + } + } + if (/ attrs=ALL/){ + $attr{"All Attributes"}++; + $anyAttrs++; + } + + if ($verb eq "yes"){ + if ($_ =~ /conn= *([0-9]+)/i){ $srchConn[$sconn] = $1;} + if ($_ =~ /op= *([0-9]+)/i){ $srchOp[$sconn] = $1;} + $sconn++; + } + + ##### This to get the Base and Scope value + ##### just in case this happens to be an + ##### unindexed search.... + + if ($_ =~ /base=\"(.*)\" scope=(\d) filter/) { + $tmpBase = $1; + $tmpScope = $2; + } +} +if (m/ DEL/){ + $delete++; + if ($verb eq "yes"){ + if ($_ =~ /conn= *([0-9]+)/i){ $delConn[$dconn] = $1;} + if ($_ =~ /op= *([0-9]+)/i){ $delOp[$dconn] = $1;} + $dconn++; + } +} +if (m/ MOD/){ + $mod++; + if ($verb eq "yes"){ + if ($_ =~ /conn= *([0-9]+)/i){ $modConn[$mconn] = $1;} + if ($_ =~ /op= *([0-9]+)/i){ $modOp[$mconn] = $1; } + $mconn++; + } +} +if (m/ ADD/){ + $add++; + if ($verb eq "yes"){ + if ($_ =~ /conn= *([0-9]+)/i){ $addConn[$aconn] = $1; } + if ($_ =~ /op= *([0-9]+)/i){ $addOp[$aconn] = $1; } + $aconn++; + } +} +if (m/ MODRDN/){ + $modrdn++; + if ($verb eq "yes"){ + if ($_ =~ /conn= *([0-9]+)/i){ $modrdnConn[$mdconn] = $1; } + if ($_ =~ /op= *([0-9]+)/i){ $modrdnOp[$mdconn] = $1; } + $mdconn++; + } +} +if (m/ ABANDON /){ + $abandon++; + $allResults++; + if ($_ =~ /targetop= *([0-9a-zA-Z]+)/i ){ + $targetOp[$ac] = $1; + if ($_ =~ /conn= *([0-9]+)/i){ $targetConn[$ac] = $1; } + if ($_ =~ /msgid= *([0-9]+)/i){ $msgid[$ac] = $1;} + $ac++; + } +} +if (m/ VLV /){ + if ($_ =~ /conn= *([0-9]+)/i){ $vlvconn[$vlv] = $1;} + if ($_ =~ /op= *([0-9]+)/i){ $vlvop[$vlv] = $1;} + $vlv++; +} +if (m/ SORT /){$sortvlv++} +if (m/ version=2/){$version2++} +if (m/ version=3/){$version3++} +if (m/ conn=0 fd=/){$restarts++} +if (m/ SSL connection from/){$sslconn++;} +if (m/ connection from/){ + $exc = "no"; + if ($_ =~ /connection from *([0-9\.]+)/i ){ + for ($xxx =0; $xxx <= $#exclude; $xxx++){ + if ($exclude[$xxx] eq $1){$exc = "yes";} + } + if ($exc ne "yes"){ $connectionCount++;} + } + $simConnection++; + if ($simConnection > $maxsimConnection) { + $maxsimConnection = $simConnection; + } + + ($connID) = $_ =~ /conn=(\d*)\s/; + $openConnection[$connID]++; + ($time, $tzone) = split (' ', $_); + ($date, $hr, $min, $sec) = split (':', $time); + ($day, $mon, $yr) = split ('/', $date); + $day =~ s/\[//; + $start_time_of_connection[$connID] = timegm($sec, $min, $hours, $day, $monthname{$mon}, $yr); +} + +if (m/ SSL client bound as /){$sslClientBind++;} +if (m/ SSL failed to map client certificate to LDAP DN/){$sslClientFailed++;} +if (m/ fd=/ && m/slot=/){$fdtake++} +if (m/ fd=/ && m/closed/){ + $fdreturn++; + $simConnection--; + + ($connID) = $_ =~ /conn=(\d*)\s/; + $openConnection[$connID]--; + ($time, $tzone) = split (' ', $_); + ($date, $hr, $min, $sec) = split (':', $time); + ($day, $mon, $yr) = split ('/', $date); + $day =~ s/\[//; + $end_time_of_connection[$connID] = timegm($sec, $min, $hours, $day, $monthname{$mon}, $yr); + $diff = $end_time_of_connection[$connID] - $start_time_of_connection[$connID]; + $start_time_of_connection[$connID] = $end_time_of_connection[$connID] = 0; + if ($diff <= 1) { $latency[0]++;} + if ($diff == 2) { $latency[1]++;} + if ($diff == 3) { $latency[2]++;} + if ($diff >= 4 && $diff <=5 ) { $latency[3]++;} + if ($diff >= 6 && $diff <=10 ) { $latency[4]++;} + if ($diff >= 11 && $diff <=15 ) { $latency[5]++;} + if ($diff >= 16) { $latency[6] ++;} +} +if (m/ BIND/){ + $bind++; + if ($verb eq "yes"){ + if ($_ =~ /conn= *([0-9]+)/i){ $bindConn[$bconn] = $1; } + if ($_ =~ /op= *([0-9]+)/i){ $bindOp[$bconn] = $1; } + $bconn++; + } +} +if (m/ BIND/ && m/$manager/i){$dirmgr++} +if (m/ BIND/ && m/dn=""/){$anony++; $bindlist{"Anonymous Binds"}++;} +if (m/ UNBIND/){ + $unbind++; + if ($verb eq "yes"){ + if ($_ =~ /conn= *([0-9]+)/i){ $unbindConn[$ubconn] = $1; } + if ($_ =~ /op= *([0-9]+)/i){ $unbindOp[$ubconn] = $1; } + $ubconn++; + } +} +if (m/ notes=U/){ + if ($_ =~ /conn= *([0-9]+)/i){ + $con = $1; + if ($_ =~ /op= *([0-9]+)/i){ $op = $1;} + } + for ($i=0; $i <= $vlv;$i++){ + if ($vlvconn[$i] eq $con && $vlvop[$i] eq $op){ $vlvnotes++; $v="1";} + } + $notes++; + if ($usage =~ /u/ || $verb eq "yes"){ + if ($v eq "0" ){ + if ($_ =~ /etime= *([0-9]+)/i ) { + $notesEtime[$vet]=$1; + $vet++; + } + if ($_ =~ /conn= *([0-9]+)/i){ + $notesConn[$nc]=$1; + $nc++; + } + if ($_ =~ /op= *([0-9]+)/i){ + $notesOp[$no]=$1; + $no++; + } + if ($_ =~ / *([0-9a-z:\/]+)/i){ + $notesTime[$nt] = $1; + $nt++; + } + $notesBase[$nb] = $tmpBase; + $notesScope[$nb] = $tmpScope; + $nb++; + } + if ($_ =~ /nentries= *([0-9]+)/i ){ + $notesNentries[$nent] = $1; + $nent++; + } + } + $v = "0"; +} + +if (m/ closed error 32/){ + $broken++; + if (m/- T1/){ $rc{"T1"}++ } + elsif (m/- T2/){ $rc{"T2"}++ } + elsif (m/- A1/){ $rc{"A1"}++ } + elsif (m/- B1/){ $rc{"B1"}++ } + elsif (m/- B4/){ $rc{"B4"}++ } + elsif (m/- B2/){ $rc{"B2"}++ } + elsif (m/- B3/){ $rc{"B3"}++ } + elsif (m/- R1/){ $rc{"R1"}++ } + elsif (m/- P1/){ $rc{"P1"}++ } + elsif (m/- P1/){ $rc{"P2"}++ } + elsif (m/- U1/){ $rc{"U1"}++ } + else { $rc{"other"}++; } +} +if (m/ closed error 131/ || m/ closed error -5961/){ + $reset++; + if (m/- T1/){ $src{"T1"}++ } + elsif (m/- T2/){ $src{"T2"}++ } + elsif (m/- A1/){ $src{"A1"}++ } + elsif (m/- B1/){ $src{"B1"}++ } + elsif (m/- B4/){ $src{"B4"}++ } + elsif (m/- B2/){ $src{"B2"}++ } + elsif (m/- B3/){ $src{"B3"}++ } + elsif (m/- R1/){ $src{"R1"}++ } + elsif (m/- P1/){ $src{"P1"}++ } + elsif (m/- P1/){ $src{"P2"}++ } + elsif (m/- U1/){ $src{"U1"}++ } + else { $src{"other"}++ } +} + +if (m/ closed error 11/){ + $resource++; + if (m/- T1/){ $rsrc{"T1"}++ } + elsif (m/- T2/){ $rsrc{"T2"}++ } + elsif (m/- A1/){ $rsrc{"A1"}++ } + elsif (m/- B1/){ $rsrc{"B1"}++ } + elsif (m/- B4/){ $rsrc{"B4"}++ } + elsif (m/- B2/){ $rsrc{"B2"}++ } + elsif (m/- B3/){ $rsrc{"B3"}++ } + elsif (m/- R1/){ $rsrc{"R1"}++ } + elsif (m/- P1/){ $rsrc{"P1"}++ } + elsif (m/- P1/){ $rsrc{"P2"}++ } + elsif (m/- U1/){ $rsrc{"U1"}++ } + else { $rsrc{"other"}++ } +} + +if ($usage =~ /g/ || $usage =~ /c/ || $usage =~ /i/ || $verb eq "yes"){ + +$exc = "no"; + +if ($_ =~ /connection from *([0-9\.]+)/i ) { + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($1 eq $exclude[$xxx]){ + $exc = "yes"; + $exCount{$1}++; + } + } + $ip = $1; + $ip_hash{$ip}{"count"}++; + if ($_ =~ /conn= *([0-9]+)/i ){ + if ($exc ne "yes"){ $ip_hash2{$ip} = sprintf "%-12s %18s\n",$1,$ip;} + $conn_hash{$1} = $ip; + + } + +} +if (m/- A1/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"A1"}++; + $conncount{"A1"}++; + $concount++; + } + } +} +if (m/- B1/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"B1"}++; + $conncount{"B1"}++; + $concount++; + } + } +} +if (m/- B4/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"B4"}++; + $conncount{"B4"}++; + $concount++; + } + } +} +if (m/- T1/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"T1"}++; + $conncount{"T1"}++; + $concount++; + } + } +} +if (m/- T2/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"T2"}++; + $conncount{"T2"}++; + $concount++; + } + } +} +if (m/- B2/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"B2"}++; + $conncount{"B2"}++; + $concount++; + } + } +} +if (m/- B2/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"B2"}++; + $conncount{"B2"}++; + $concount++; + } + } +} +if (m/- B3/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"B3"}++; + $conncount{"B3"}++; + $concount++; + } + } +} +if (m/- R1/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"R1"}++; + $conncount{"R1"}++; + $concount++; + } + } +} +if (m/- P1/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"P1"}++; + $conncount{"P1"}++; + $concount++; + } + } +} +if (m/- P2/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"P2"}++; + $conncount{"P2"}++; + $concount++; + } + } +} +if (m/- U1/){ + if ($_ =~ /conn= *([0-9]+)/i) { + $exc = "no"; + $ip = $conn_hash{$1}; + if ($ip eq ""){$ip = "Unknown Host";} + for ($xxx = 0; $xxx <= $#exclude; $xxx++){ + if ($ip eq $exclude[$xxx]){$exc = "yes";} + } + if ($exc ne "yes"){ + $ip_hash{$ip}{"U1"}++; + $conncount{"U1"}++; + $concount++; + } + } + +} + +} +if ($_ =~ /err= *([0-9]+)/i){ + $er[$1]++; + if ($1 ne "0"){ $errorck++;} + else { $errorsucc++;} +} +if ($_ =~ /etime= *([0-9]+)/i ) { $etime{$1}++;} +if ($_ =~ / tag=101 nentries= *([0-9]+)/i ) {$nentries{$1}++} +if ($_ =~ / tag=111 nentries= *([0-9]+)/i ) {$nentries{$1}++} +if ($_ =~ / tag=100 nentries= *([0-9]+)/i ) {$nentries{$1}++} +if ($_ =~ / tag=115 nentries= *([0-9]+)/i ) {$nentries{$1}++} +if (m/objectclass=\*/i || m/objectclass=top/i ){ + if (m/ scope=2 /){ $objectclass++;} +} + +if (m/ EXT oid=/){ + $extendedop++; + if ($_ =~ /oid=\" *([0-9\.]+)/i ){ $oid{$1}++; } + if ($verb eq "yes"){ + if ($_ =~ /conn= *([0-9]+)/i){ $extConn[$econn] = $1; } + if ($_ =~ /op= *([0-9]+)/i){ $extOp[$econn] = $1; } + $econn++; + } +} + +if (m/ BIND/ && $_ =~ /dn=\"(.*)\" method/i ){ + if ($1 ne ""){ + $tmpp = $1; + $tmpp =~ tr/A-Z/a-z/; + $bindlist{$tmpp} = $bindlist{$tmpp} + 1; + + $bindInfo[$bc][0] = $tmpp; + if ($_ =~ /conn= *([0-9]+)/i) { $bindInfo[$bc][1] = $1; } + if ($_ =~ /op= *([0-9]+)/i) { $bindInfo[$bc][2] = $1; } + $bc++; + } +} + +if ($usage =~ /l/ || $verb eq "yes"){ +if (/ SRCH / && / attrs=/ && $_ =~ /filter=\"(.*)\" /i ){ + $tmpp = $1; + $tmpp =~ tr/A-Z/a-z/; + $tmpp =~ s/\\22/\"/g; + $filter{$tmpp} = $filter{$tmpp} + 1; + $filterInfo[$fcc][0] = $tmpp; + if ($_ =~ /conn= *([0-9]+)/i) { $filterInfo[$fcc][1] = $1; } + if ($_ =~ /op= *([0-9]+)/i) { $filterInfo[$fcc][2] = $1; } + $fcc++; +} elsif (/ SRCH / && $_ =~ /filter=\"(.*)\"/i){ + $tmpp = $1; + $tmpp =~ tr/A-Z/a-z/; + $tmpp =~ s/\\22/\"/g; + $filter{$tmpp} = $filter{$tmpp} + 1; + $filterInfo[$fcc][0] = $tmpp; + if ($_ =~ /conn= *([0-9]+)/i) { $filterInfo[$fcc][1] = $1; } + if ($_ =~ /op= *([0-9]+)/i) { $filterInfo[$fcc][2] = $1; } + $fcc++; +} +} + +if ($usage =~ /a/ || $verb eq "yes"){ +if (/ SRCH / && $_ =~ /base=\"(.*)\" scope/i ){ + if ($1 eq ""){$tmpp = "Root DSE";} + else {$tmpp = $1;} + $tmpp =~ tr/A-Z/a-z/; + $base{$tmpp} = $base{$tmpp} + 1; +} +} + +if ($_ =~ /fd= *([0-9]+)/i ) { + $fds[$fdds] = $1; + if ($fds[$fdds] > $highfd) {$highfd = $fds[$fdds];} + $fdds++; +} + + +if ($usage =~ /f/ || $verb eq "yes"){ +if (/ err=49 tag=/ && / dn=\"/){ + if ($_ =~ /dn=\"(.*)\"/i ){ + $ds6xbadpwd{$1}++; + } + $ds6x = "true"; + $bpc++; + +} elsif (/ err=49 tag=/ ){ + if ($_ =~ /conn= *([0-9]+)/i ){ + $badPasswordConn[$bpc] = $1; + $bpc++; + } + if ($_ =~ /op= *([0-9]+)/i ){ + $badPasswordOp[$bpo] = $1; + $bpo++; + } +$badPasswordIp[$bpi] = $ip; +$bpi++; +} +} + +if (/ BIND / && /method=sasl/i){ + $sasl++; + if ($_ =~ /mech=(.*)/i ){ + $saslmech{$1}++; + } +} + +if (/ conn=Internal op=-1 / && !/ RESULT err=/){ $internal++; } + +if (/ ENTRY dn=/ ){ $entryOp++; } + +if (/ conn=/ && /op=/ && / REFERRAL/){ $referral++; } + +if (/ options=persistent/){$persistent++;} + +} + + +####################################### +# # +# The End # +# # +####################################### + diff --git a/ldap/cm/Makefile b/ldap/cm/Makefile index 2de6bfb9..b87d4788 100644 --- a/ldap/cm/Makefile +++ b/ldap/cm/Makefile @@ -461,14 +461,7 @@ ifdef USE_QUANTIFY mv -f $(RELDIR)/bin/slapd/server/ns-slapd.quantify $(RELDIR)/bin/slapd/server/ns-slapd endif -# Copy DSRK tools - $(INSTALL) -m 755 $(DSRK_BUILD_DIR)/perl/logconv.pl $(RELDIR)/bin/slapd/server -ifneq ($(ARCH), WINNT) - $(INSTALL) -m 755 $(DSRK_BUILD_DIR)/bin/n$(DSRKCOMP_DIR)/dbscan $(RELDIR)/bin/slapd/server -else - $(INSTALL) -m 755 $(DSRK_BUILD_DIR)/bin/n$(DSRKCOMP_DIR)/dbscan$(DOTEXE) $(RELDIR)/bin/slapd/server -endif - +# Copy db tools $(INSTALL) -m 755 $(DB_BINPATH)/db_printlog* $(RELDIR)/bin/slapd/server $(INSTALL) -m 755 $(DB_BINPATH)/db_verify* $(RELDIR)/bin/slapd/server diff --git a/ldap/servers/slapd/tools/Makefile b/ldap/servers/slapd/tools/Makefile index 5b423d2a..1f827184 100644 --- a/ldap/servers/slapd/tools/Makefile +++ b/ldap/servers/slapd/tools/Makefile @@ -118,7 +118,7 @@ CFLAGS+=-DLDAP_DONT_USE_SMARTHEAP endif -TOOL_OBJS = ldif.o keyupg.o pwenc.o mmldif.o migratecred.o eggencode.o +TOOL_OBJS = ldif.o keyupg.o pwenc.o mmldif.o migratecred.o eggencode.o dbscan.o ALL_OBJS = $(addprefix $(OBJDEST)/, $(TOOL_OBJS)) LDIF = $(addsuffix $(EXE_SUFFIX), \ @@ -133,8 +133,10 @@ MMLDIF = $(addsuffix $(EXE_SUFFIX), \ $(addprefix $(BINDIR)/, mmldif)) EGGENCODE = $(addsuffix $(EXE_SUFFIX), \ $(addprefix $(BINDIR)/, eggencode)) +DBSCAN = $(addsuffix $(EXE_SUFFIX), \ + $(addprefix $(BINDIR)/, dbscan)) -BINS= $(LDIF) $(PWDHASH) $(KEYUPG) $(MMLDIF) $(MIGRATECRED) +BINS= $(LDIF) $(PWDHASH) $(KEYUPG) $(MMLDIF) $(MIGRATECRED) $(DBSCAN) EXTRABINS= $(EGGENCODE) all: $(OBJDEST) $(BINDIR) $(LDAP_ADMIN_BIN_RELDIR) $(BINS) @@ -159,6 +161,9 @@ $(MMLDIF): $(OBJDEST)/mmldif.o $(EXTRA_LIBS_DEP) $(EGGENCODE): $(OBJDEST)/eggencode.o $(LINK_EXE_NOLIBSOBJS) $(OBJDEST)/eggencode.o +$(DBSCAN): $(OBJDEST)/dbscan.o + $(LINK_EXE) $< + $(OBJDEST): $(MKDIR) $(OBJDEST) diff --git a/ldap/servers/slapd/tools/dbscan.c b/ldap/servers/slapd/tools/dbscan.c new file mode 100644 index 00000000..e8a96572 --- /dev/null +++ b/ldap/servers/slapd/tools/dbscan.c @@ -0,0 +1,800 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright Copyright 2002 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ + +/* + * small program to scan a Directory Server db file and dump the contents + * + * TODO: indirect indexes + */ + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <sys/types.h> +#include <time.h> +#include <string.h> +#include "db.h" + +#ifdef _WIN32 +#include <windows.h> +extern int getopt(); +extern char *optarg; +typedef unsigned char uint8_t; +#else +#include <netinet/in.h> +#include <inttypes.h> +#endif + +/* stolen from slapi-plugin.h */ +#define SLAPI_OPERATION_BIND 0x00000001UL +#define SLAPI_OPERATION_UNBIND 0x00000002UL +#define SLAPI_OPERATION_SEARCH 0x00000004UL +#define SLAPI_OPERATION_MODIFY 0x00000008UL +#define SLAPI_OPERATION_ADD 0x00000010UL +#define SLAPI_OPERATION_DELETE 0x00000020UL +#define SLAPI_OPERATION_MODDN 0x00000040UL +#define SLAPI_OPERATION_MODRDN SLAPI_OPERATION_MODDN +#define SLAPI_OPERATION_COMPARE 0x00000080UL +#define SLAPI_OPERATION_ABANDON 0x00000100UL +#define SLAPI_OPERATION_EXTENDED 0x00000200UL +#define SLAPI_OPERATION_ANY 0xFFFFFFFFUL +#define SLAPI_OPERATION_NONE 0x00000000UL + +#if defined(linux) +#include <getopt.h> +#endif + +typedef u_int32_t ID; + +typedef unsigned int uint32; + +typedef struct { + uint32 max; + uint32 used; + uint32 id[1]; +} IDL; + +/** db_printf - functioning same as printf but a place for manipluating output. +*/ +void db_printf(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); +} + +void db_printfln(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + vfprintf(stdout, "\n", NULL); +} + +#ifdef DB26 +#define db_strerror strerror +#endif + +int MAX_BUFFER = 4096; + + +static IDL *idl_make(DBT *data) +{ + IDL *idl = NULL, *xidl; + + if (data->size < 2*sizeof(uint32)) { + idl = (IDL *)malloc(sizeof(IDL) + 64*sizeof(uint32)); + if (! idl) + return NULL; + idl->max = 64; + idl->used = 1; + idl->id[0] = *(uint32 *)(data->data); + return idl; + } + + xidl = (IDL *)(data->data); + idl = (IDL *)malloc(data->size); + if (! idl) + return NULL; + + memcpy(idl, xidl, data->size); + return idl; +} + +static void idl_free(IDL *idl) +{ + idl->max = 0; + idl->used = 0; + free(idl); +} + +static IDL *idl_append(IDL *idl, uint32 id) +{ + if (idl->used >= idl->max) { + /* must grow */ + idl->max *= 2; + idl = realloc(idl, sizeof(IDL) + idl->max * sizeof(uint32)); + if (! idl) + return NULL; + } + idl->id[idl->used++] = id; + return idl; +} + + +/* format a string for easy printing */ +#define FMT_LF_OK 1 +#define FMT_SP_OK 2 +static char *format_raw(unsigned char *s, int len, int flags) +{ + static unsigned char buf[BUFSIZ]; /* not intended to be threadsafe */ + static char hex[] = "0123456789ABCDEF"; + unsigned char *p, *o; + int i; + + for (p = s, o = buf, i = 0; i < len; p++, i++) { + if ((*p == '%') || (*p <= ' ') || (*p >= 126)) { + /* index keys are stored with their trailing NUL */ + if ((*p == 0) && (i == len-1)) + continue; + if ((flags & FMT_LF_OK) && (*p == '\n')) { + *o++ = '\n'; + *o++ = '\t'; + } else if ((flags && FMT_SP_OK) && (*p == ' ')) { + *o++ = ' '; + } else { + *o++ = '%'; + *o++ = hex[*p / 16]; + *o++ = hex[*p % 16]; + } + } else { + *o++ = *p; + } + if (o-buf > BUFSIZ-5) { + /* out of space */ + strcpy(o, " ..."); + i = len; + } + } + *o = 0; + return (char *)buf; +} + +static char *format(unsigned char *s, int len) +{ + return format_raw(s, len, 0); +} + +static char *format_entry(unsigned char *s, int len) +{ + return format_raw(s, len, FMT_LF_OK | FMT_SP_OK); +} + +static char *idl_format(IDL *idl) +{ + static char *buf = NULL; + uint32 i; + + if (buf == NULL) { + buf = (char *)malloc(MAX_BUFFER); + if (buf == NULL) + return "?"; + } + + buf[0] = 0; + for (i = 0; i < idl->used; i++) { + sprintf((char *)buf + strlen(buf), "%d ", idl->id[i]); + + if (strlen(buf) > (size_t)MAX_BUFFER-20) { + strcat(buf, "..."); + return (char *)buf; + } + } + return (char *)buf; +} + + +/*** Copied from cl5_api.c: _cl5ReadString ***/ +void _cl5ReadString (char **str, char **buff) +{ + if (str) + { + int len = strlen (*buff); + + if (len) + { + *str = strdup(*buff); + (*buff) += len + 1; + } + else /* just null char - skip it */ + { + *str = NULL; + (*buff) ++; + } + } + else /* just skip this string */ + { + (*buff) += strlen (*buff) + 1; + } +} + +/** print_attr - print attribute name followed by one value. + assume the value stored as null terminated string. +*/ +void print_attr(char *attrname, char **buff) +{ + char *val = NULL; + + _cl5ReadString(&val, buff); + if(attrname != NULL || val != NULL) { + db_printf("\t"); + } + + if(attrname) { + db_printf("%s: ", attrname); + } + if(val != NULL) { + db_printf("%s\n", val); + free(val); + } +} + +/*** Copied from cl5_api.c: _cl5ReadMods ***/ +/* mods format: + ----------- + <4 byte mods count><mod1><mod2>... + + mod format: + ----------- + <1 byte modop><null terminated attr name><4 byte count> + {<4 byte size><value1><4 byte size><value2>... || + <null terminated str1> <null terminated str2>...} + */ +void _cl5ReadMod(char **buff); + +void _cl5ReadMods(char **buff) +{ + char *pos = *buff; + uint32 i; + uint32 mod_count; + + /* need to copy first, to skirt around alignment problems on certain + architectures */ + memcpy((char *)&mod_count, *buff, sizeof(mod_count)); + mod_count = ntohl(mod_count); + pos += sizeof (mod_count); + + + for (i = 0; i < mod_count; i++) + { + _cl5ReadMod (&pos); + } + + *buff = pos; +} + + +/** print_ber_attr - print one line of attribute, the value was stored + in ber format, length followed by string. +*/ +void print_ber_attr(char* attrname, char** buff) +{ + char *val = NULL; + uint32 bv_len; + + memcpy((char *)&bv_len, *buff, sizeof(bv_len)); + bv_len = ntohl(bv_len); + *buff += sizeof (uint32); + if (bv_len > 0) { + + db_printf("\t\t"); + + if(attrname != NULL) { + db_printf("%s: ", attrname); + } + + val = malloc(bv_len + 1); + memcpy (val, *buff, bv_len); + val[bv_len] = 0; + *buff += bv_len; + db_printf("%s\n", val); + free(val); + } +} + +static ID id_stored_to_internal(char* b) +{ + ID i; + i = (ID)b[3] & 0x000000ff; + i |= (((ID)b[2]) << 8) & 0x0000ff00; + i |= (((ID)b[1]) << 16) & 0x00ff0000; + i |= ((ID)b[0]) << 24; + return i; +} + +void _cl5ReadMod(char **buff) +{ + char *pos = *buff; + uint32 i; + uint32 val_count; + char *type = NULL; + int op; + + op = (*pos) & 0x000000FF; + pos ++; + _cl5ReadString (&type, &pos); + + /* need to do the copy first, to skirt around alignment problems on + certain architectures */ + memcpy((char *)&val_count, pos, sizeof(val_count)); + val_count = ntohl(val_count); + pos += sizeof (uint32); + + for (i = 0; i < val_count; i++) + { + print_ber_attr(type, &pos); + } + + (*buff) = pos; + free(type); +} + +/* + *** Copied from cl5_api:cl5DBData2Entry *** + Data in db format: + ------------------ + <1 byte version><1 byte change_type><sizeof time_t time><null terminated dbid> + <null terminated csn><null terminated uniqueid><null terminated targetdn> + [<null terminated newrdn><1 byte deleteoldrdn>][<4 byte mod count><mod1><mod2>....] + + mod format: + ----------- + <1 byte modop><null terminated attr name><4 byte value count> + <4 byte value size><value1><4 byte value size><value2> +*/ +void print_changelog(unsigned char *data, int len) +{ + uint8_t version; + unsigned long operation_type; + char *pos = (char *)data; + time_t thetime; + uint32 replgen; + + /* read byte of version */ + version = *((uint8_t *)pos); + if (version != 5) + { + db_printf("Invalid changelog db version %i\nWorks for version 5 only.", version); + exit(1); + } + pos += sizeof(version); + + /* read change type */ + operation_type = (unsigned long)(*(uint8_t *)pos); + pos ++; + + /* need to do the copy first, to skirt around alignment problems on + certain architectures */ + memcpy((char *)&thetime, pos, sizeof(thetime)); + replgen = ntohl((uint32)(thetime)); + pos += sizeof (time_t); + db_printf("\treplgen: %ld %s", replgen, ctime((time_t *)&replgen)); + + /* read csn */ + print_attr("csn", &pos); + /* read UniqueID */ + print_attr("uniqueid", &pos); + + /* figure out what else we need to read depending on the operation type */ + switch (operation_type) + { + case SLAPI_OPERATION_ADD: + print_attr("parentuniqueid", &pos); + print_attr("dn", &pos); + /* convert mods to entry */ + db_printf("\toperation: add\n"); + _cl5ReadMods(&pos); + break; + + case SLAPI_OPERATION_MODIFY: + print_attr("dn", &pos); + db_printf("\toperation: modify\n"); + _cl5ReadMods(&pos); + break; + + case SLAPI_OPERATION_MODRDN: + print_attr("dn", &pos); + print_attr("newrdn", &pos); + pos ++; + print_attr("dn", &pos); + print_attr("uniqueid", &pos); + db_printf("\toperation: modrdn\n"); + _cl5ReadMods(&pos); + break; + + case SLAPI_OPERATION_DELETE: + print_attr("dn", &pos); + db_printf("\toperation: delete\n"); + break; + + default: + db_printf("Failed to format entry\n"); + break; + } +} + +int indexfile = 0, entryfile = 0, changelogfile = 0; +int lengths_only = 0; +uint32 min_display = 0; +int show_recno = 0; +int show_cnt = 0; +int verbose = 0; +long pres_cnt = 0; +long eq_cnt = 0; +long app_cnt = 0; +long sub_cnt = 0; +long match_cnt = 0; +long ind_cnt = 0; +long allids_cnt = 0; +long other_cnt = 0; + + +static void display_item(DBC *cursor, DBT *key, DBT *data) +{ + IDL *idl; + int ret = 0; + + if (indexfile) { + idl = idl_make(data); + if (idl == NULL) { + printf("\t(illegal idl)\n"); + return; + } + if (show_recno) { + cursor->c_get(cursor, key, data, DB_GET_RECNO); + printf("[%5d] ", *(db_recno_t *)(data->data)); + } + + /* fetch all other id's too */ + while (ret == 0) { + ret = cursor->c_get(cursor, key, data, DB_NEXT_DUP); + if (ret == 0) + idl = idl_append(idl, *(uint32 *)(data->data)); + } + if (ret == DB_NOTFOUND) + ret = 0; + if (ret != 0) { + printf("Failure while looping dupes: %s\n", + db_strerror(ret)); + exit(1); + } + + if (idl->max == 0) { + /* allids */ + if ( allids_cnt == 0 && show_cnt) { + printf("The following index keys reached allids:\n"); + } + printf("%-40s(allids)\n", format(key->data, key->size)); + allids_cnt++; + } else { + if (lengths_only) { + if (idl->used >= min_display) + printf("%-40s%d\n", + format(key->data, key->size), idl->used); + } else if (!show_cnt) { + printf("%s\n", format(key->data, key->size)); + printf("\t%s\n", idl_format(idl)); + } + } + + if ( show_cnt ) { + char firstchar; + + firstchar = ((char*)key->data)[0]; + + switch ( firstchar ) { + case '+': + pres_cnt += idl->used; + break; + + case '=': + eq_cnt += idl->used; + break; + + case '~': + app_cnt += idl->used; + break; + + case '*': + sub_cnt += idl->used; + break; + + case ':': + match_cnt += idl->used; + break; + + case '\\': + ind_cnt += idl->used; + break; + + default: + other_cnt += idl->used; + break; + } + } + idl_free(idl); + return; + } + + if (changelogfile) { + /* changelog db file */ + printf("\ndbid: %s\n", format(key->data, key->size)); + print_changelog(data->data, data->size); + return; + } + + if (entryfile) { + /* id2entry file */ + ID entry_id = id_stored_to_internal(key->data); + printf("id %d\n", entry_id); + printf("\t%s\n", format_entry(data->data, data->size)); + } else { + /* user didn't tell us what kind of file, dump it raw */ + printf("%s\n", format(key->data, key->size)); + printf("\t%s\n", format(data->data, data->size)); + } +} + + +static void usage(char *argv0) +{ + printf("\n%s - scan a db file and dump the contents\n", argv0); + printf(" -f <filename> specify db file\n"); + printf(" -i dump as an index file\n"); + printf(" -e dump as an entry (id2entry) file\n"); +#ifndef DB26 + printf(" -c dump as a changelog file\n"); +#endif + printf(" -l <size> max length of dumped id list (default %d)\n", + MAX_BUFFER); + printf(" -n display idl lengths only (not contents)\n"); + printf(" -G <n> (when used with -n) only display index entries with\n"); + printf(" more than <n> ids\n"); + printf(" -r show libdb record numbers, too\n"); + printf(" -k <key> lookup only a specific key\n"); + printf(" -K <entry_id> lookup only a specific entry id\n"); + printf(" -s Summary of index counts\n"); + printf("\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + DB_ENV *env = NULL; + DB *db = NULL; + DBC *cursor = NULL; + char *filename = NULL; + DBT key = {0}, data = {0}; + int ret; + char *find_key = NULL; + uint32 entry_id = -1; + int c; + +#ifndef DB26 + while ((c = getopt(argc, argv, "f:iecl:nG:srk:K:hv")) != EOF) { +#else + while ((c = getopt(argc, argv, "f:iel:nG:srk:K:h")) != EOF) { +#endif + switch (c) { + case 'f': + filename = optarg; + break; + case 'i': + indexfile = 1; + break; + case 'e': + entryfile = 1; + break; + case 'c': + changelogfile = 1; + break; + case 'l': + MAX_BUFFER = atoi(optarg); + break; + case 'n': + lengths_only = 1; + break; + case 'G': + min_display = atoi(optarg)+1; + break; + case 'r': + show_recno = 1; + break; + case 's': + show_cnt = 1; + break; + case 'k': + find_key = optarg; + break; + case 'K': + entry_id = (uint32)atoi(optarg); + break; + case 'h': + default: + usage(argv[0]); + } + } + + if(filename == NULL) { + usage(argv[0]); + } + + +#ifdef DB26 + env = (DB_ENV *)calloc(sizeof(DB_ENV), 1); + if (! env) { + printf("Can't create dbenv: %s\n", strerror(ret)); + exit(1); + } + ret = db_appinit(NULL, NULL, env, DB_CREATE); + if (ret != 0) { + printf("Can't init db26: %s\n", db_strerror(ret)); + exit(1); + } +#else + ret = db_env_create(&env, 0); + if (ret != 0) { + printf("Can't create dbenv: %s\n", db_strerror(ret)); + exit(1); + } + ret = env->open(env, NULL, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0); + if (ret != 0) { + printf("Can't open dbenv: %s\n", db_strerror(ret)); + exit(1); + } +#endif + +#ifdef DB26 + ret = db_open(filename, DB_UNKNOWN, 0, 0, env, NULL, &db); + if (ret != 0) { + printf("Can't open db2 file '%s': %s\n", filename, db_strerror(ret)); + exit(1); + } +#else + ret = db_create(&db, env, 0); + if (ret != 0) { + printf("Can't create db handle: %d\n", ret); + exit(1); + } + ret = db->open(db, NULL, filename, NULL, DB_UNKNOWN, DB_RDONLY, 0); + if (ret != 0) { + printf("Can't open db file '%s': %s\n", filename, db_strerror(ret)); + exit(1); + } +#endif + + /* cursor through the db */ + + ret = db->cursor(db, NULL, &cursor, 0); + if (ret != 0) { + printf("Can't create db cursor: %s\n", db_strerror(ret)); + exit(1); + } + ret = cursor->c_get(cursor, &key, &data, DB_FIRST); + if (ret == DB_NOTFOUND) { + printf("Empty database!\n"); + exit(0); + } + if (ret != 0) { + printf("Can't get first cursor: %s\n", db_strerror(ret)); + exit(1); + } + + if (find_key) { + key.size = strlen(find_key)+1; + key.data = find_key; + ret = db->get(db, NULL, &key, &data, 0); + if (ret != 0) { + /* could be a key that doesn't have the trailing null? */ + key.size--; + ret = db->get(db, NULL, &key, &data, 0); + if (ret != 0) { + printf("Can't find key '%s'\n", find_key); + exit(1); + } + } + ret = cursor->c_get(cursor, &key, &data, DB_SET); + if (ret != 0) { + printf("Can't set cursor to returned item: %s\n", + db_strerror(ret)); + exit(1); + } + display_item(cursor, &key, &data); + key.size = 0; + key.data = NULL; + } else if (entry_id != -1) { + key.size = sizeof(entry_id); + key.data = &entry_id; + ret = db->get(db, NULL, &key, &data, 0); + if (ret != 0) { + printf("Can't set cursor to returned item: %s\n", + db_strerror(ret)); + exit(1); + } + display_item(cursor, &key, &data); + key.size = 0; + key.data = NULL; + } else { + while (ret == 0) { + /* display */ + display_item(cursor, &key, &data); + + ret = cursor->c_get(cursor, &key, &data, DB_NEXT); + if ((ret != 0) && (ret != DB_NOTFOUND)) { + printf("Bizarre error: %s\n", db_strerror(ret)); + exit(1); + } + } + } + + ret = cursor->c_close(cursor); + if (ret != 0) { + printf("Can't close the cursor (?!): %s\n", db_strerror(ret)); + exit(1); + } + + ret = db->close(db, 0); + if (ret != 0) { + printf("Unable to close db file: %s\n", db_strerror(ret)); + exit(1); + } + + if ( show_cnt ) { + + if ( allids_cnt > 0 ) { + printf("Index keys that reached ALLIDs threshold: %ld\n", allids_cnt); + } + + if ( pres_cnt > 0 ) { + printf("Presence index keys: %ld\n", pres_cnt); + } + + if ( eq_cnt > 0 ) { + printf("Equality index keys: %ld\n", eq_cnt); + } + + if ( app_cnt > 0 ) { + printf("Approximate index keys: %ld\n", app_cnt); + } + + if ( sub_cnt > 0 ) { + printf("Substring index keys: %ld\n", sub_cnt); + } + + if ( match_cnt > 0 ) { + printf("Match index keys: %ld\n", match_cnt); + } + + if ( ind_cnt > 0 ) { + printf("Indirect index keys: %ld\n", ind_cnt); + } + + if ( other_cnt > 0 ) { + printf("This file contains %ld number of unknown type ( possible corruption)\n",other_cnt); + } + + } +#ifndef DB26 + ret = env->close(env, 0); + if (ret != 0) { + printf("Unable to shutdown libdb: %s\n", db_strerror(ret)); + exit(1); + } +#endif + + return 0; +} |