Skip to content

Instantly share code, notes, and snippets.

@Quintus
Last active August 29, 2015 13:56
Show Gist options
  • Save Quintus/9119159 to your computer and use it in GitHub Desktop.
Save Quintus/9119159 to your computer and use it in GitHub Desktop.
Nice tree outputter for LDAP
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require "optparse"
require "base64"
require "pp"
########################################
# Option handling
@options = {
:dn => "dc=pegasus-alpha,dc=eu",
:verbose => false,
:filter => "(objectclass=*)",
:authdn => nil
}
OptionParser.new do |op|
op.banner =<<-USAGE
lsldap [OPTIONS]
Prints out the LDAP tree in a nicely indented fashion. If -b
is specified, print only entries below that distinguished
name (dn).
Options:
USAGE
op.on("-b", "--base DN", "Specify tree root"){|dn| @options[:dn] = dn}
op.on("-D", "--auth-dn DN", "Specify the DN for accessing the LDAP.", "This will ask you for a password."){|dn| @options[:authdn] = dn}
op.on("-f", "--filter FILTER", "Use a specific filter;", "default is '#{@options[:filter]}'."){|filter| @options[:filter] = filter}
op.on("-h", "--help", "Show this help"){ puts(op); exit }
op.on("-v", "--[no-]verbose", "Run verbosely"){|bool| @options[:verbose] = bool}
end.parse!(ARGV)
########################################
# Helpers
class Entry
attr_accessor :info
attr_accessor :rdn
def initialize(rdn = "·", info = nil)
@rdn = rdn
@tree = {}
@info = info
end
def [](key)
@tree[key] ||= Entry.new(key)
end
def []=(key, value)
@tree[key] = value
end
# call-seq:
# recursive_each( [yield_self] ){|rdn, entry, level, is_last| ...}
#
# Iterates recursively over the entire subtree.
def recursive_each(yield_self = true, level = 0, is_last = false, &block)
block.call(@rdn, self, level, is_last) if yield_self
@tree.values.each_with_index do |entry, index|
entry.recursive_each(true, level + 1, index + 1 == @tree.values.count, &block)
end
end
end
def ldapsearch(base = nil)
cmd = "ldapsearch -x -LLL -o ldif-wrap=no"
cmd << " " << "-b '" << base << "'" if base
cmd << " " << "-D '" << @options[:authdn] << "' -W" if @options[:authdn]
cmd << " '#{@options[:filter]}'"
puts cmd if @options[:verbose]
str = `#{cmd}`
result = Entry.new
str.split("\n\n").each do |block|
if block =~ /^(dn::?)\s(.*?)$/
if $1.start_with?("dn::") # Base64-encoded
dn = Base64.decode64($2)
else
dn = $2
end
keys = dn.split(",")
entry = result
entry = entry[keys.pop] until keys.count == 1
lastkey = keys.pop
if entry[lastkey]
entry[lastkey].rdn = lastkey
entry[lastkey].info = block.lines.to_a.map(&:strip)
else
entry[lastkey] = Entry.new(lastkey, block.lines.to_a.map(&:strip))
end
end
end
result
end
########################################
# Program
ldapsearch(@options[:dn]).recursive_each do |rdn, entry, level, is_last|
if level > 0
print(" " * (level -1))
print(is_last ? "└" : "├")
print("── ")
end
puts entry.rdn
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment