2121# SOFTWARE.
2222#
2323####################
24-
24+ from __future__ import unicode_literals
2525import sys , os , re , codecs , json , argparse , getpass , base64
2626# import class and constants
2727from datetime import datetime
28- from urllib import quote_plus
29-
28+ try :
29+ from urllib .parse import quote_plus
30+ except ImportError :
31+ from urllib import quote_plus
3032import ldap3
3133from ldap3 import Server , Connection , SIMPLE , SYNC , ALL , SASL , NTLM
3234from ldap3 .core .exceptions import LDAPKeyError , LDAPAttributeError , LDAPCursorError
3335from ldap3 .abstract import attribute , attrDef
3436from ldap3 .utils import dn
3537from ldap3 .protocol .formatters .formatters import format_sid
38+ from builtins import str
39+ from future .utils import itervalues , iteritems , native_str
3640
3741# dnspython, for resolving hostnames
3842import dns .resolver
@@ -452,7 +456,7 @@ def parseFlags(self, attr, flags_def):
452456 outflags = []
453457 if attr is None :
454458 return outflags
455- for flag , val in flags_def . items ( ):
459+ for flag , val in iteritems ( flags_def ):
456460 if attr .value & val :
457461 outflags .append (flag )
458462 return outflags
@@ -462,7 +466,7 @@ def parseTrustDirection(self, attr, flags_def):
462466 outflags = []
463467 if attr is None :
464468 return outflags
465- for flag , val in flags_def . items ( ):
469+ for flag , val in iteritems ( flags_def ):
466470 if attr .value == val :
467471 outflags .append (flag )
468472 return outflags
@@ -473,40 +477,40 @@ def generateHtmlTable(self, listable, attributes, header='', firstTable=True, sp
473477 #Only if this is the first table it is an actual table, the others are just bodies of the first table
474478 #This makes sure that multiple tables have their columns aligned to make it less messy
475479 if firstTable :
476- of .append (u '<table>' )
480+ of .append ('<table>' )
477481 #Table header
478482 if header != '' :
479- of .append (u '<thead><tr><td colspan="%d" id="cn_%s">%s</td></tr></thead>' % (len (attributes ), self .formatId (header ), header ))
480- of .append (u '<tbody><tr>' )
483+ of .append ('<thead><tr><td colspan="%d" id="cn_%s">%s</td></tr></thead>' % (len (attributes ), self .formatId (header ), header ))
484+ of .append ('<tbody><tr>' )
481485 for hdr in attributes :
482486 try :
483487 #Print alias of this attribute if there is one
484- of .append (u '<th>%s</th>' % self .htmlescape (attr_translations [hdr ]))
488+ of .append ('<th>%s</th>' % self .htmlescape (attr_translations [hdr ]))
485489 except KeyError :
486- of .append (u '<th>%s</th>' % self .htmlescape (hdr ))
487- of .append (u '</tr>\n ' )
490+ of .append ('<th>%s</th>' % self .htmlescape (hdr ))
491+ of .append ('</tr>\n ' )
488492 for li in listable :
489493 #Whether we should format group objects separately
490494 if specialGroupsFormat and 'group' in li ['objectClass' ].values :
491495 #Give it an extra class and pass it to the function below to make sure the CN is a link
492496 liIsGroup = True
493- of .append (u '<tr class="group">' )
497+ of .append ('<tr class="group">' )
494498 else :
495499 liIsGroup = False
496- of .append (u '<tr>' )
500+ of .append ('<tr>' )
497501 for att in attributes :
498502 try :
499- of .append (u '<td>%s</td>' % self .formatAttribute (li [att ], liIsGroup ))
503+ of .append ('<td>%s</td>' % self .formatAttribute (li [att ], liIsGroup ))
500504 except (LDAPKeyError , LDAPCursorError ):
501- of .append (u '<td> </td>' )
502- of .append (u '</tr>\n ' )
503- of .append (u '</tbody>\n ' )
504- return u '' .join (of )
505+ of .append ('<td> </td>' )
506+ of .append ('</tr>\n ' )
507+ of .append ('</tbody>\n ' )
508+ return '' .join (of )
505509
506510 #Generate several HTML tables for grouped reports
507511 def generateGroupedHtmlTables (self , groups , attributes ):
508512 first = True
509- for groupname , members in groups . iteritems ():
513+ for groupname , members in iteritems (groups ):
510514 yield self .generateHtmlTable (members , attributes , groupname , first , specialGroupsFormat = True )
511515 if first :
512516 first = False
@@ -566,13 +570,14 @@ def formatString(self, value):
566570 return value .strftime ('%x %X' )
567571 except ValueError :
568572 #Invalid date
569- return u'0'
570- if type (value ) is unicode :
571- return value #.encode('utf8')
573+ return '0'
574+ # Make sure it's a unicode string
575+ if type (value ) is bytes :
576+ return value .encode ('utf8' )
572577 if type (value ) is str :
573- return unicode ( value , errors = 'replace' ) #.encode('utf8')
578+ return value #.encode('utf8')
574579 if type (value ) is int :
575- return unicode (value )
580+ return str (value )
576581 if value is None :
577582 return ''
578583 #Other type: just return it
@@ -619,7 +624,7 @@ def formatAttribute(self, att, formatCnAsGroup=False):
619624
620625
621626 def formatCnWithGroupLink (self , cn ):
622- return u 'Group: <a href="#cn_%s" title="%s">%s</a>' % (self .formatId (cn ), self .htmlescape (cn ), self .htmlescape (cn ))
627+ return 'Group: <a href="#cn_%s" title="%s">%s</a>' % (self .formatId (cn ), self .htmlescape (cn ), self .htmlescape (cn ))
623628
624629 #Convert a CN to a valid HTML id by replacing all non-ascii characters with a _
625630 def formatId (self , cn ):
@@ -630,7 +635,7 @@ def formatGroupsHtml(self, grouplist):
630635 outcache = []
631636 for group in grouplist :
632637 cn = self .unescapecn (dn .parse_dn (group )[0 ][1 ])
633- outcache .append (u '<a href="%s.html#cn_%s" title="%s">%s</a>' % (self .config .users_by_group , quote_plus (self .formatId (cn )), self .htmlescape (group ), self .htmlescape (cn )))
638+ outcache .append ('<a href="%s.html#cn_%s" title="%s">%s</a>' % (self .config .users_by_group , quote_plus (self .formatId (cn )), self .htmlescape (group ), self .htmlescape (cn )))
634639 return ', ' .join (outcache )
635640
636641 #Format groups to readable HTML
@@ -707,7 +712,7 @@ def generateJsonGroupedList(self, groups):
707712 #Start of the list
708713 yield '['
709714 firstGroup = True
710- for group in groups . iteritems ():
715+ for group in iteritems (groups ):
711716 if not firstGroup :
712717 #Separate items
713718 yield ','
@@ -799,11 +804,11 @@ def generateTrustsReport(self, dd):
799804
800805#Some quick logging helpers
801806def log_warn (text ):
802- print '[!] %s' % text
807+ print ( '[!] %s' % text )
803808def log_info (text ):
804- print '[*] %s' % text
809+ print ( '[*] %s' % text )
805810def log_success (text ):
806- print '[+] %s' % text
811+ print ( '[+] %s' % text )
807812
808813def main ():
809814 parser = argparse .ArgumentParser (description = 'Domain information dumper via LDAP. Dumps users/computers/groups and OS/membership information to HTML/JSON/greppable output.' )
@@ -813,8 +818,8 @@ def main():
813818 #Main parameters
814819 #maingroup = parser.add_argument_group("Main options")
815820 parser .add_argument ("host" , type = str , metavar = 'HOSTNAME' , help = "Hostname/ip or ldap://host:port connection string to connect to (use ldaps:// to use SSL)" )
816- parser .add_argument ("-u" , "--user" , type = str , metavar = 'USERNAME' , help = "DOMAIN\\ username for authentication, leave empty for anonymous authentication" )
817- parser .add_argument ("-p" , "--password" , type = str , metavar = 'PASSWORD' , help = "Password or LM:NTLM hash, will prompt if not specified" )
821+ parser .add_argument ("-u" , "--user" , type = native_str , metavar = 'USERNAME' , help = "DOMAIN\\ username for authentication, leave empty for anonymous authentication" )
822+ parser .add_argument ("-p" , "--password" , type = native_str , metavar = 'PASSWORD' , help = "Password or LM:NTLM hash, will prompt if not specified" )
818823 parser .add_argument ("-at" , "--authtype" , type = str , choices = ['NTLM' , 'SIMPLE' ], default = 'NTLM' , help = "Authentication type (NTLM or SIMPLE, default: NTLM)" )
819824
820825 #Output parameters
@@ -879,6 +884,7 @@ def main():
879884 # define the server and the connection
880885 s = Server (args .host , get_info = ALL )
881886 log_info ('Connecting to host...' )
887+
882888 c = Connection (s , user = args .user , password = args .password , authentication = authentication )
883889 log_info ('Binding to host' )
884890 # perform the Bind operation
0 commit comments