Facebook
From Sweet Dolphin, 3 Years ago, written in Plain Text.
Embed
Download Paste or View Raw
Hits: 154
  1. /*
  2.  * Openldap (2.4.30) binding in GO
  3.  *
  4.  *
  5.  *  link to ldap or ldap_r (for thread-safe binding)
  6.  *
  7.  *
  8.  * Copyright (C) 2012 - Marc Quinton.
  9.  *
  10.  * Use of this source code is governed by the MIT Licence :
  11.  *  http://opensource.org/licenses/mit-license.php
  12.  *
  13.  * Permission is hereby granted, free of charge, to any person obtaining
  14.  * a copy of this software and associated documentation files (the
  15.  * "Software"), to deal in the Software without restriction, including
  16.  * without limitation the rights to use, copy, modify, merge, publish,
  17.  * distribute, sublicense, and/or sell copies of the Software, and to
  18.  * permit persons to whom the Software is furnished to do so, subject to
  19.  * the following conditions:
  20.  *
  21.  * The above copyright notice and this permission notice shall be
  22.  * included in all copies or substantial portions of the Software.
  23.  *
  24.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25.  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27.  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  28.  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  29.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  30.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31.  *
  32.  */
  33.  
  34. package openldap
  35.  
  36. /*
  37.  
  38. #define LDAP_DEPRECATED 1
  39. #include <stdlib.h>
  40. #include <ldap.h>
  41.  
  42. static inline char* to_charptr(const void* s) { return (char*)s; }
  43. static inline LDAPControl** to_ldapctrlptr(const void* s) {
  44.         return (LDAPControl**) s;
  45. }
  46. */
  47. // #cgo CFLAGS: -DLDAP_DEPRECATED=1
  48. // #cgo linux CFLAGS: -DLINUX=1
  49. // #cgo LDFLAGS: -lldap -llber
  50. import "C"
  51.  
  52. import (
  53.         "errors"
  54.         "fmt"
  55.         "unsafe"
  56.         "strings"
  57.         "strconv"
  58. )
  59.  
  60. /* Intialize() open an LDAP connexion ; supported url formats :
  61.  *
  62.  *   ldap://host:389/
  63.  *   ldaps://secure-host:636/
  64.  *
  65.  * return values :
  66.  *  - on success : LDAP object, nil
  67.  *  - on error : nil and error with error description.
  68.  */
  69. func Initialize(url string) (*Ldap, error) {
  70.         _url := C.CString(url)
  71.         defer C.free(unsafe.Pointer(_url))
  72.         var ldap *C.LDAP
  73.         var val int
  74.         val = LDAP_OPT_X_TLS_NEVER
  75.         C.ldap_set_option(ldap,LDAP_OPT_X_TLS_REQUIRE_CERT, unsafe.Pointer(&val))
  76.  
  77.         // API: int ldap_initialize (LDAP **ldp, LDAP_CONST char *url )
  78.         rv := C.ldap_initialize(&ldap, _url)
  79.  
  80.         if rv != 0 {
  81.                 err := errors.New(fmt.Sprintf("LDAP::Initialize() error (%d) : %s", rv, ErrorToString(int(rv))))
  82.                 return nil, err
  83.         }
  84.  
  85.         return &Ldap{ldap}, nil
  86. }
  87.  
  88. /*
  89.  * StartTLS() is used for regular LDAP (not
  90.  * LDAPS) connections to establish encryption
  91.  * after the session is running.
  92.  *
  93.  * return value :
  94.  *  - nil on success,
  95.  *  - error with error description on error.
  96.  */
  97. func (self *Ldap) StartTLS() error {
  98.         var rv int
  99.  
  100.         // API: int ldap_start_tls_s(LDAP *ld, LDAPControl **serverctrls, LDAPControl **clientctrls);
  101.         rv = int(C.ldap_start_tls_s(self.conn,
  102.                 C.to_ldapctrlptr(unsafe.Pointer(nil)),
  103.                 C.to_ldapctrlptr(unsafe.Pointer(nil))))
  104.        
  105.         if rv == LDAP_OPT_SUCCESS {
  106.                 return nil
  107.         }
  108.  
  109.         return errors.New(fmt.Sprintf("LDAP::StartTLS() error (%d) : %s", rv,
  110.                 ErrorToString(rv)))
  111. }
  112.  
  113. /*
  114.  * Bind() is used for LDAP authentifications
  115.  *
  116.  * if who is empty this is an anonymous bind
  117.  * else this is an authentificated bind
  118.  *
  119.  * return value :
  120.  *  - nil on succes,
  121.  *  - error with error description on error.
  122.  *
  123.  */
  124. func (self *Ldap) Bind(who, cred string) error {
  125.         var rv int
  126.  
  127.         authmethod := C.int(LDAP_AUTH_SIMPLE)
  128.  
  129.         // DEPRECATED
  130.         // API: int ldap_bind_s (LDAP *ld,      LDAP_CONST char *who, LDAP_CONST char *cred, int authmethod );
  131.         if who == "" {
  132.                 _who := C.to_charptr(unsafe.Pointer(nil))
  133.                 _cred := C.to_charptr(unsafe.Pointer(nil))
  134.  
  135.                 rv = int(C.ldap_bind_s(self.conn, _who, _cred, authmethod))
  136.         } else {
  137.                 _who := C.CString(who)
  138.                 _cred := C.CString(cred)
  139.                 defer C.free(unsafe.Pointer(_who))
  140.                 rv = int(C.ldap_bind_s(self.conn, _who, _cred, authmethod))
  141.         }
  142.  
  143.         if rv == LDAP_OPT_SUCCESS {
  144.                 return nil
  145.         }
  146.  
  147.         self.conn = nil
  148.         return errors.New(fmt.Sprintf("LDAP::Bind() error (%d) : %s", rv, ErrorToString(rv)))
  149. }
  150.  
  151. /*
  152.  * close LDAP connexion
  153.  *
  154.  * return value :
  155.  *  - nil on succes,
  156.  *  - error with error description on error.
  157.  *
  158.  */
  159. func (self *Ldap) Close() error {
  160.  
  161.         // DEPRECATED
  162.         // API: int ldap_unbind(LDAP *ld)
  163.         rv := C.ldap_unbind(self.conn)
  164.  
  165.         if rv == LDAP_OPT_SUCCESS {
  166.                 return nil
  167.         }
  168.  
  169.         self.conn = nil
  170.         return errors.New(fmt.Sprintf("LDAP::Close() error (%d) : %s", int(rv), ErrorToString(int(rv))))
  171.  
  172. }
  173. /*
  174.  * Unbind() close LDAP connexion
  175.  *
  176.  * an alias to Ldap::Close()
  177.  *
  178.  */
  179. func (self *Ldap) Unbind() error {
  180.         return self.Close()
  181. }
  182.  
  183. /* Search() is used to search LDAP server
  184.   - base is where search is starting
  185.   - scope allows local or deep search. Supported values :
  186.      - LDAP_SCOPE_BASE
  187.            - LDAP_SCOPE_ONELEVEL
  188.      - LDAP_SCOPE_SUBTREE
  189.   - filter is an LDAP search expression,
  190.   - attributes is an array of string telling with LDAP attribute to get from this request
  191. */
  192. func (self *Ldap) Search(base string, scope int, filter string, attributes []string) (*LdapMessage, error) {
  193.  
  194.         var attrsonly int = 0 // false: returns all, true, returns only attributes without values
  195.  
  196.         _base := C.CString(base)
  197.         defer C.free(unsafe.Pointer(_base))
  198.  
  199.         _filter := C.CString(filter)
  200.         defer C.free(unsafe.Pointer(_filter))
  201.  
  202.         // transform []string to C.char** null terminated array (attributes argument)
  203.         _attributes := make([]*C.char, len(attributes)+1) // default set to nil (NULL in C)
  204.  
  205.         for i, arg := range attributes {
  206.                 _attributes[i] = C.CString(arg)
  207.                 defer C.free(unsafe.Pointer(_attributes[i]))
  208.         }
  209.  
  210.         var msg *C.LDAPMessage
  211.  
  212.         // DEPRECATED
  213.         // API: int ldap_search_s (LDAP *ld, char *base, int scope, char *filter, char **attrs, int attrsonly, LdapMessage * ldap_res)
  214.         rv := int(C.ldap_search_s(self.conn, _base, C.int(scope), _filter, &_attributes[0], C.int(attrsonly), &msg))
  215.  
  216.         if rv == LDAP_OPT_SUCCESS {
  217.                 _msg := new(LdapMessage)
  218.                 _msg.ldap = self
  219.                 _msg.errno = rv
  220.                 _msg.msg = msg
  221.                 return _msg, nil
  222.         }
  223.  
  224.         return nil, errors.New(fmt.Sprintf("LDAP::Search() error : %d (%s)", rv, ErrorToString(rv)))
  225. }
  226.  
  227. // ------------------------------------- Ldap* method (object oriented) -------------------------------------------------------------------
  228.  
  229. // Create a new LdapAttribute entry with name and values.
  230. func LdapAttributeNew(name string, values []string)(*LdapAttribute){
  231.         a := new(LdapAttribute)
  232.         a.values = values
  233.         a.name = name
  234.         return a
  235. }
  236.  
  237. // Append() adds an LdapAttribute to self LdapEntry
  238. func (self *LdapEntry) Append(a LdapAttribute){
  239.         self.values = append(self.values, a)
  240. }
  241.  
  242. // String() is used for fmt.Println(self)
  243. //
  244. func (self *LdapAttribute) String() string{
  245.         return self.ToText()
  246. }
  247.  
  248. // ToText() returns a text string representation of LdapAttribute
  249. // avoiding displaying binary data.
  250. //
  251. func (self *LdapAttribute) ToText() string{
  252.        
  253.         var list []string
  254.        
  255.         for _, a := range self.Values() {
  256.                 if (!_isPrint(a)) {
  257.                         list = append(list, fmt.Sprintf("binary-data[%d]", len(a)))
  258.                 } else {
  259.                         list = append(list, a)
  260.                 }
  261.         }
  262.         if len(list) > 1 {
  263.                 return fmt.Sprintf("%s: (%d)[%s]", self.name, len(list), strings.Join(list, ", "))
  264.         }
  265.         return fmt.Sprintf("%s: [%s]", self.name, strings.Join(list, ", "))
  266. }
  267.  
  268. // Name() return attribute name
  269. func (self *LdapAttribute) Name() string{
  270.         return self.name
  271. }
  272.  
  273. // Values() returns array values for self LdapAttribute
  274. //
  275. func (self *LdapAttribute) Values() []string{
  276.         return self.values
  277. }
  278.  
  279. // _isPrint() returns true if str is printable
  280. //
  281. // @private method
  282. func _isPrint(str string) bool{
  283.         for _, c := range str{
  284.                
  285.                 if !strconv.IsPrint(rune(c)) {
  286.                         return false
  287.                 }
  288.         }
  289.        
  290.         return true
  291. }
  292.  
  293. // IsPrint() returns true is self LdapAttribute is printable.
  294. func (self *LdapAttribute) IsPrint() bool{
  295.         for _, a := range self.Values() {
  296.                 if (!_isPrint(a)) {
  297.                         return false
  298.                 }
  299.         }
  300.         return true
  301. }
  302.  
  303. // Dn() returns DN (Distinguish Name) for self LdapEntry
  304. func (self *LdapEntry) Dn() string{
  305.         return self.dn
  306. }
  307.  
  308. // Attributes() returns an array of LdapAttribute
  309. func (self *LdapEntry) Attributes() []LdapAttribute{
  310.         return self.values
  311. }
  312.  
  313. // Print() allow printing self LdapEntry with fmt.Println()
  314. func (self *LdapEntry) String() string {
  315.         return self.ToText()
  316. }
  317.  
  318. // GetValuesByName() get a list of values for self LdapEntry, using "name" attribute
  319. func (self *LdapEntry) GetValuesByName(attrib string) []string{
  320.        
  321.         for _, a := range self.values{
  322.                 if a.Name() == attrib {
  323.                         return a.values
  324.                 }
  325.         }
  326.        
  327.         return []string{}
  328. }
  329. // GetOneValueByName() ; a quick way to get a single attribute value
  330. func (self *LdapEntry) GetOneValueByName(attrib string) (string, error){
  331.        
  332.         for _, a := range self.values{
  333.                 if a.Name() == attrib {
  334.                         return a.values[0], nil
  335.                 }
  336.         }
  337.        
  338.         return "", errors.New(fmt.Sprintf("LdapEntry::GetOneValueByName() error : attribute %s not found", attrib))
  339. }
  340.  
  341. // ToText() return a string representating self LdapEntry
  342. func (self *LdapEntry) ToText() string{
  343.  
  344.         txt := fmt.Sprintf("dn: %s\n", self.dn)
  345.        
  346.         for _, a := range self.values{
  347.                 txt = txt + fmt.Sprintf("%s\n", a.ToText())
  348.         }
  349.  
  350.         return txt
  351. }
  352.  
  353. // Append() add e to LdapSearchResult array
  354. func (self *LdapSearchResult) Append(e LdapEntry){
  355.         self.entries = append(self.entries, e)
  356. }
  357.  
  358. // ToText() : a quick way to print an LdapSearchResult
  359. func (self *LdapSearchResult) ToText() string{
  360.  
  361.         txt := fmt.Sprintf("# query : %s\n", self.filter)
  362.         txt = txt + fmt.Sprintf("# num results : %d\n", self.Count())
  363.         txt = txt + fmt.Sprintf("# search : %s\n", self.Filter())
  364.         txt = txt + fmt.Sprintf("# base : %s\n", self.Base())
  365.         txt = txt + fmt.Sprintf("# attributes : [%s]\n", strings.Join(self.Attributes(), ", "))
  366.  
  367.         for _, e := range self.entries{
  368.                 txt = txt + fmt.Sprintf("%s\n", e.ToText())
  369.         }
  370.  
  371.         return txt
  372. }
  373.  
  374. // String() : used for fmt.Println(self)
  375. func (self *LdapSearchResult) String() string{
  376.         return self.ToText()
  377. }
  378.  
  379. // Entries() : returns an array of LdapEntry for self
  380. func (self *LdapSearchResult) Entries() []LdapEntry{
  381.         return self.entries
  382. }
  383.  
  384. // Count() : returns number of results for self search.
  385. func (self *LdapSearchResult) Count() int{
  386.         return len(self.entries)
  387. }
  388.  
  389. // Filter() : returns filter for self search
  390. func (self *LdapSearchResult) Filter() string{
  391.         return self.filter
  392. }
  393.  
  394. // Filter() : returns base DN for self search
  395. func (self *LdapSearchResult) Base() string{
  396.         return self.base
  397. }
  398.  
  399. // Filter() : returns scope for self search
  400. func (self *LdapSearchResult) Scope() int{
  401.         return self.scope
  402. }
  403.  
  404. // Filter() : returns an array of attributes used for this actual search
  405. func (self *LdapSearchResult) Attributes() []string{
  406.         return self.attributes
  407. }
  408.  
  409. // SearchAll() : a quick way to make search. This method returns an LdapSearchResult with all necessary methods to
  410. // access data. Result is a collection (tree) of []LdapEntry / []LdapAttribute.
  411. //
  412. func (self *Ldap) SearchAll(base string, scope int, filter string, attributes []string) (*LdapSearchResult, error) {
  413.  
  414.         sr := new(LdapSearchResult)
  415.  
  416.         sr.ldap   = self
  417.         sr.base   = base
  418.         sr.scope  = scope
  419.         sr.filter = filter
  420.         sr.attributes = attributes
  421.  
  422.         // Search(base string, scope int, filter string, attributes []string) (*LDAPMessage, error)    
  423.         result, err := self.Search(base, scope, filter, attributes)
  424.  
  425.         if err != nil {
  426.                 fmt.Println(err)
  427.                 return sr, err
  428.         }
  429.  
  430.         // Free LDAP::Result() allocated data
  431.         defer result.MsgFree()
  432.  
  433.         e := result.FirstEntry()
  434.  
  435.         for e != nil {
  436.                 _e := new(LdapEntry)
  437.                
  438.                 _e.dn = e.GetDn()
  439.  
  440.                 attr, _ := e.FirstAttribute()
  441.                 for attr != "" {
  442.  
  443.                         _attr := LdapAttributeNew(attr, e.GetValues(attr))
  444.                         _e.Append(*_attr)
  445.  
  446.                         attr, _ = e.NextAttribute()
  447.  
  448.                 }
  449.  
  450.                 sr.Append(*_e)
  451.  
  452.                 e = e.NextEntry()
  453.         }
  454.        
  455.         return sr, nil
  456. }
  457.