PageRenderTime 27ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/ldap/idlookup.py

https://github.com/cohoe/scripts
Python | 210 lines | 189 code | 12 blank | 9 comment | 9 complexity | 285920f0416fc3c62c5798f10a2aed92 MD5 | raw file
  1. #!/usr/bin/env python
  2. import argparse
  3. import re
  4. import os
  5. import ldap
  6. from getpass import getpass
  7. from string import Template
  8. # Base class for LDAP implementation object
  9. class directoryserver(object):
  10. # Attributes supported by this program
  11. s_attrs = ['username','lastname','firstname']
  12. def __init__(self, i_vals, ld_type):
  13. # These are common to all implementations
  14. values = {'lastname':'sn', 'firstname':'givenName', 'mode':ld_type}
  15. self.set_values(dict(values, **i_vals))
  16. def set_values(self, values):
  17. for k in values:
  18. setattr(self, k, values[k])
  19. setattr(self, values[k], k)
  20. # Active Directory instance
  21. class ad(directoryserver):
  22. def __init__(self):
  23. values = {'username':'sAMAccountName'}
  24. self.bindstring = Template("ldapsearch -x -LLL -e pr=200/noprompt -h $server -D \"$binder\" -W \"$search\" $attrs")
  25. super(type(self), self).__init__(values, type(self).__name__)
  26. # OpenLDAP instance
  27. class openldap(directoryserver):
  28. def __init__(self):
  29. values = {'username':'uid'}
  30. self.bindstring = Template("ldapsearch -x -LLL -h $server -D \"$binder\" -W \"$search\" $attrs")
  31. super(type(self), self).__init__(values, type(self).__name__)
  32. # Get the domain from the system. This needs some work...
  33. def get_sys_domain():
  34. dom = re.sub(r'^(.*?)\.','',os.getenv('HOSTNAME'))
  35. return dom
  36. # Get the user from the system
  37. def get_sys_user():
  38. user = os.getenv('USER')
  39. return user
  40. # Get the domain that was provided from the arguments
  41. def get_domain():
  42. return args.domain
  43. # Get the user that was provided from the arguments
  44. def get_user():
  45. return args.user
  46. # Prompt the user for their password
  47. def get_user_password():
  48. pw = getpass("Enter password: ")
  49. return pw
  50. # Set up and parse the arguments given on the CLI
  51. def get_args():
  52. parser = argparse.ArgumentParser(description="Lookup basic ID information from an LDAP server", epilog="Written by Grant Cohoe (http://grantcohoe.com)")
  53. parser.add_argument("-m", "--mode", dest="mode", metavar="MODE", default="ad", help="set ldap mode (ad or openldap)")
  54. parser.add_argument("-u", "--user", dest="user", metavar="USER", default=get_sys_user(), help="User to bind as (default: current)")
  55. parser.add_argument("-d", "--domain", dest="domain", metavar="DOMAIN", default=get_sys_domain(), help="LDAP domain to search (ex: corp.example.com). Default is system domain.")
  56. parser.add_argument("-s", "--server", dest="server", metavar="SERVER", default=None, help="LDAP server to bind to (ex: ldap.example.com). Default is domain server (AD-style)")
  57. parser.add_argument("-i", "--input", dest="input", metavar="fields", required=True, help="specify input values (username,lastname,firstname)")
  58. parser.add_argument("-o", "--output", dest="output", metavar="fields", help="specify output values (username,lastname,firstname)")
  59. parser.add_argument("-p", "--print", dest="prnt", action="store_true", help="print an ldapsearch command rather than executing a bind")
  60. return parser.parse_args()
  61. # Set the mode of the ldap object based on what the CLI said
  62. def set_ldap_mode():
  63. global ld
  64. if args.mode == "ad":
  65. ld = ad()
  66. elif args.mode == "openldap":
  67. ld = openldap()
  68. else:
  69. print "error: mode can only be 'ad' or 'openldap'"
  70. quit(1)
  71. # Build search filter
  72. def get_filter():
  73. u_input = str(args.input).split(',')
  74. u_attrs = {}
  75. for item in u_input:
  76. try:
  77. (k,v) = item.split('=')
  78. except ValueError:
  79. print "Need to specify a value to search on (ex: username=foo)"
  80. quit(1)
  81. if k not in ld.s_attrs:
  82. print "error: attribute "+k+" is not supported"
  83. quit(1)
  84. u_attrs[getattr(ld,k)] = v
  85. filter = "(&"
  86. for item in u_attrs:
  87. filter +="("+item+"="+u_attrs[item]+")"
  88. filter += ")"
  89. return filter
  90. # Output attrs
  91. def get_output_attributes(raw):
  92. u_output = str(args.output).split(',')
  93. u_print = []
  94. for item in u_output:
  95. if item not in ld.s_attrs:
  96. print "error: attribute "+item+" is not supported"
  97. quit(1)
  98. u_print.append(item)
  99. o_attrs = ""
  100. if raw:
  101. raw_attrs = []
  102. for item in u_print:
  103. raw_attrs.append(getattr(ld,item))
  104. return raw_attrs
  105. else:
  106. for item in u_print:
  107. o_attrs += getattr(ld,item)+" "
  108. return o_attrs
  109. # Create the bind DN string based on what mode we are in
  110. def get_binder():
  111. if ld.mode == "ad":
  112. return args.user+"@"+args.domain
  113. elif ld.mode == "openldap":
  114. return args.user
  115. else:
  116. print "Error in processing mode."
  117. quit(1)
  118. # Figure out where to bind to in the event the user never specified it
  119. def get_server():
  120. if args.server is None:
  121. return args.domain
  122. return args.server
  123. # Build the ldapsearch command
  124. def build_search():
  125. ldapsearch = ld.bindstring.substitute(
  126. domain=get_domain(),
  127. server=get_server(),
  128. user=get_user(),
  129. binder=get_binder(),
  130. search=get_filter(),
  131. attrs=get_output_attributes(None)
  132. )
  133. return ldapsearch
  134. # Calculate the base DN for a directory based on the domain name given
  135. def get_base_dn(domain):
  136. dn = "dc="
  137. dn += re.sub(r'\.',',dc=',domain)
  138. return dn
  139. # Bind to the directory server and query
  140. def bind_search():
  141. o_attrs = get_output_attributes(1)
  142. i_filter = get_filter()
  143. pw = get_user_password()
  144. l = ldap.initialize("ldap://"+get_server())
  145. l.protocol_version = 3
  146. # This allows for binding to AD with 'user@domain' syntax rather than 'cn=user'
  147. if ld.mode == "ad":
  148. l.set_option(ldap.OPT_REFERRALS, 0)
  149. try:
  150. l.simple_bind_s(get_binder(), pw)
  151. except ldap.INVALID_CREDENTIALS:
  152. print "Invalid LDAP credentials"
  153. quit(1)
  154. # Search
  155. r = l.search(get_base_dn(get_domain()), ldap.SCOPE_SUBTREE, i_filter, o_attrs)
  156. type,results = l.result(r,60)
  157. # AD returns extra crap that we don't want
  158. if ld.mode == "ad":
  159. results.pop()
  160. return results
  161. # Print the results in a pretty way
  162. def result_print(res):
  163. for result in res:
  164. print "Result:"
  165. for attr in get_output_attributes(1):
  166. if attr in result[1]:
  167. print getattr(ld, attr)+": "+result[1][attr][0]
  168. else:
  169. print getattr(ld, attr)+": Not specified in this directory"
  170. # main functionality of this program
  171. def main():
  172. global args
  173. args = get_args()
  174. set_ldap_mode()
  175. if args.prnt is True:
  176. print build_search()
  177. else:
  178. res = bind_search()
  179. result_print(res)
  180. if __name__ == "__main__":
  181. main()