LDAP '''Lightweight Directory Access Protocol''' is a protocol for networked directories [http://en.wikipedia.org/wiki/LDAP]. This page is about both TCL ldap libraries and TCL ldap clients. As of 2010, the mostly referred to TCL ldap library is the one provided by tcllib: http://tcllib.sourceforge.net/doc/ldap.html As of 2010, there is no up-to-date tcl GUI client. http://sourceforge.net/projects/legacytcl/%|%Legacy TCL project%|% has a collection of TCL programs, among them there is a ldap client more than a decade old. ---- [musashiXXX] 2010-May-10 I've written a CGI based interface to LDAP. It was designed for the sole purpose of allowing users to administer a single OU from a web interface. It's very basic at the moment but I plan on developing it further. The tarball is located here: http://nefaria.com/scriptz/tcl-ldap-cgi.tar.gz ... there is no README or instructions (I'm working on that) but if you need any help, feel free to contact me (musashiXXX) on irc.freenode.net #tcl or via e-mail (musashi@nefaria.com). ---- There are four independent (?) implementations, [ldapTcl], [Matt Newman]'s LDAP extension [http://www.sensus.org/tcl/index.htm], Jochen Loewer's (see below), a derivative of the latter available in [tcllib] as of 2004, and [Gareth Owen]'s tclLdap-pkg [http://www-users.aston.ac.uk/~oweng/tclLdap-pkg/] (but is this a derivative of an early tclLdap?). It would be particularly useful to compare the latter two. ---- I did a pure Tcl implementation of a ldap interface in June 99. See ([Jochen Loewer]). It is running since then very nicely to query a large enterprise wide people directory. Right now only the read/query parts of the protocol are implemented. However, the internal [ASN] layer is there, so it should be rather easy to extend it. Unfortunately I didn't release the code to the public yet. I thought about that several times. It would be ideal for tcllib or even standard tcl (like the http package). [CL]: ooooo. ASN.1 ''would'' be nice for [tcllib]. [ak]: Tcllib head provides an (incomplete) [asn] package. Directly derived from the code in the ldap package. ---- Interesting LDAP-based applications include Owen's Ldapper [http://www-users.aston.ac.uk/~oweng/ldapper-1.2/] (which pages says it was last modified ''Wed Feb 3 17:46:54 GMT 1999''). ---- As of 2004, the major category of LDAP servers are instances of [Microsoft]'s [Active Directory]. ---- CL observes that learning to work with LDAP can intimidate newcomers, if only for the usual complication of client-server protocols ([SNMP] presents the same challenge): one must have a working server ''and'' client before achieving the "Hello, world" level of progress. In the '90s, there were quite a few public LDAP services, and it was inviting to connect new client applications to them for quick exercise. As far as I know, they're all gone now [[task: confirm this]]. Is there interest in Tclistan for a public LDAP server against which we can all practice? I might set one up ... (again, same's true for SNMP). ---- [Patrick Finnegan] provided several [IBM]-pertinent example LDAP-using scripts [http://aspn.activestate.com/ASPN/Cookbook/Tcl?kwd=LDAP] to the '''[Cookbook]'''. ---- In general, LDAP querying requires quoting of such characters as comma [http://groups.google.com/group/comp.lang.tcl/browse_thread/thread/0c13fc6495fdaa34/742865a7048b8873]. ---- [schlenk] The tcllib ldap client package was greatly enhanced in the 1.9 version of Tcllib. * STARTTLS support ([RFC] 4513) * SASL Auth support (RFC 4513) * new ldapx subpackage to provide an OO API * LDIF support in the ldapx package (RFC 2849) * asynchronous operation, does no longer block your app during ldap queries * Who am I extension supported (RFC 4532) * New introspection commands to inspect the running connection Using [LDIF] you can for example parse Mozilla Thunderbird Addressbooks, which can be exported in ldif format, see the examples/ldap directory in the tcllib distribution. ---- [LV] 2009-Sep-15 Has anyone written a tutorial for learning to interact with LDAP (or even better, Active Directory) using Tcl? It would be nice to have a series of examples starting at something simple like looking for the current user's LDAP information, then on to listing all users along with their phone numbers, etc. and finally a few examples of things like adding a new user, updating an existing user, deleting a user. These examples would really help a novice administrator get started using Tcl. ---- '''[rojo] - 2011-04-26 10:20:20''' @LV: Here's an example of an LDAP search in a MS environment for you. ====== #! /bin/sh # \ exec tclsh "$0" ${1+"$@"} namespace eval ldapsearch { set settings(domain) your.domain set settings(user) authorized_user set settings(pass) p4sSwh1rRed # timeout in seconds for LDAP queries... For some reason, when searching for cn, # results return immediately; whereas searching any other field (employeeID for # instance) will not return results until the timeout. This doesn't seem to be # a TCL-only thing, as I've noticed it with ASP and .NET apps as well. Maybe # my domain controllers have seen better days. But I digress. Set this low # for faster queries, but not low enough that every search returns 0 results. set settings(timeout) 5 # Wildcard searches seem to error with ldap::secure_connect set settings(use-ssl) false variable settings package require ldap if {$settings(use-ssl)} { package require tls } proc isid {what} { # What does an employee ID look like in your organization? # For this example we'll say it's in the format of E01234567 return [regexp -nocase {^E\d{8}$} $what] } proc search {what} { variable settings if {$settings(use-ssl)} { if {[catch {ldap::secure_connect $settings(domain)} idx]} { set idx [ldap::connect $settings(domain)] } } { set idx [ldap::connect $settings(domain)] } if {$settings(use-ssl) && [::ldap::info tls $idx]} { puts "SSL connected to [::ldap::info ip $idx]" } { puts "Connected to [::ldap::info ip $idx]" } ldap::bind $idx $settings(user)@$settings(domain) $settings(pass) set attributes { sAMAccountName name displayName employeeID pwdLastSet userAccountControl memberOf msExchHomeServerName msExchHideFromAddressLists } if {[isid $what]} { set filter "|(employeeID=$what)" } elseif {[string match *,* $what]} { set filter "|(displayName=$what*)" } else { set filter "|(cn=$what)" } if {[catch { set dc "dc=[string map {. ,dc=} $settings(domain)]" ldap::searchInit $idx $dc $filter $attributes [list -scope sub -timelimit $settings(timeout)] } fail]} { puts "Init failure: $fail"; ldap::unbind $idx; ldap::disconnect $idx; return } while {![catch {ldap::searchNext $idx} flat]} { set dn [lindex $flat 0] set flat [lindex $flat 1] if {![llength $flat]} { continue } foreach attr $attributes { set res($attr) {} } foreach {name val} $flat { set res($name) $val } # $res(pwdLastSet) is measured in 100 nanosecond intervals since 1/1/1601 # convert to seconds set res(pwdLastSet) [expr {wide($res(pwdLastSet) * pow(10,-7))}] # convert to 1970 epoch incr res(pwdLastSet) [clock scan {1601-1-1} -format {%Y-%m-%d}] # expires when? set res(pwdExpires) [clock format [clock add $res(pwdLastSet) 90 days] -format {%H:%M:%S %b %d %Y}] # Set how long ago? set res(pwdAge) "[expr {([clock seconds] - $res(pwdLastSet)) / 60 / 60 / 24}] days" # see http://support.microsoft.com/kb/305144 for $res(userAccountControl) set UAC { 16777216 TRUSTED_TO_AUTH_FOR_DELEGATION 8388608 PASSWORD_EXPIRED 4194304 DONT_REQ_PREAUTH 2097152 USE_DES_KEY_ONLY 1048576 NOT_DELEGATED 524288 TRUSTED_FOR_DELEGATION 262144 SMARTCARD_REQUIRED 131072 MNS_LOGON_ACCOUNT 65536 DONT_EXPIRE_PASSWORD 8192 SERVER_TRUST_ACCOUNT 4096 WORKSTATION_TRUST_ACCOUNT 2048 INTERDOMAIN_TRUST_ACCOUNT 512 NORMAL_ACCOUNT 256 TEMP_DUPLICATE_ACCOUNT 128 ENCRYPTED_TEXT_PWD_ALLOWED 64 PASSWD_CANT_CHANGE 32 PASSWD_NOTREQD 16 LOCKOUT 8 HOMEDIR_REQUIRED 2 ACCOUNTDISABLE 1 SCRIPT } set flags [list] foreach {dec flag} $UAC { if {!$res(userAccountControl)} { break } if {$res(userAccountControl) >= $dec} { lappend flags $flag; incr res(userAccountControl) -$dec } } set res(userAccountControl) $flags set groups [list] foreach group $res(memberOf) { lappend groups [string map {CN= ""} [lindex [split $group ,] 0]] } set res(memberOf) $groups set res(msExchHomeServerName) [lindex [split [lindex $res(msExchHomeServerName) end] =] end] foreach {name val} [array get res] { puts "$name: $val" } puts "\n" } # puts "Last value of \$flat: $flat" ldap::searchEnd $idx ldap::unbind $idx ldap::disconnect $idx return } }; # end namespace if {[llength $argv]} { puts $argv; ldapsearch::search [lindex $argv 0] } ====== usage: $ tclsh % source thisfile.tcl % ldapsearch::search username - outputs records for all users matching username* similar to Active Directory Users & Computers % ldapsearch::search {lastname, f} - outputs records for all users matching "lastname, f*" similar to Active Directory Users & Computers % ldapsearch::search employeeID - outputs exact match where employeeID=searchterm <> Acronym | Internet