0010022: allow to disable ldap certificate check
[tine20] / tine20 / Tinebase / Ldap.php
1 <?php
2 /**
3  * Tine 2.0
4  *
5  * @package     Tinebase
6  * @subpackage  Ldap
7  * @license     http://www.gnu.org/licenses/agpl.html AGPL3
8  * @copyright   Copyright (c) 2008-2014 Metaways Infosystems GmbH (http://www.metaways.de)
9  * @author      Lars Kneschke <l.kneschke@metaways.de>
10  */
11
12 /**
13  * LDAP base class for tine 2.0
14  * @package     Tinebase
15  * @subpackage  Ldap
16  */
17 class Tinebase_Ldap extends Zend_Ldap
18 {
19     /**
20      * Extend constructor
21      *
22      * @param array $_options
23      * @return @see Zend_Ldap
24      */
25     public function __construct(array $_options)
26     {
27         if (Tinebase_Config::getInstance()->get(Tinebase_Config::LDAP_DISABLE_TLSREQCERT)) {
28             if (Tinebase_Core::isLogLevel(Zend_Log::INFO)) Tinebase_Core::getLogger()->info(__METHOD__ . '::' . __LINE__
29                 . ' Disable TLS certificate check');
30             putenv('LDAPTLS_REQCERT=never');
31         }
32         
33         // strip non Zend_Ldap options
34         $options = array_intersect_key($_options, array(
35             'host'                      => null,
36             'port'                      => null,
37             'useSsl'                    => null,
38             'username'                  => null,
39             'password'                  => null,
40             'bindRequiresDn'            => null,
41             'baseDn'                    => null,
42             'accountCanonicalForm'      => null,
43             'accountDomainName'         => null,
44             'accountDomainNameShort'    => null,
45             'accountFilterFormat'       => null,
46             'allowEmptyPassword'        => null,
47             'useStartTls'               => null,
48             'optReferrals'              => null,
49             'tryUsernameSplit'          => null
50         ));
51         
52         $returnValue = parent::__construct($options);
53         
54         return $returnValue;
55     }
56     
57     /**
58      * Delete an LDAP entry
59      *
60      * @param  string|Zend_Ldap_Dn $dn
61      * @param  array $data
62      * @return Zend_Ldap *Provides a fluid interface*
63      * @throws Zend_Ldap_Exception
64      */
65     public function deleteProperty($dn, array $data)
66     {
67         if ($dn instanceof Zend_Ldap_Dn) {
68             $dn = $dn->toString();
69         }
70
71         $isDeleted = @ldap_mod_del($this->getResource(), $dn, $data);
72         if($isDeleted === false) {
73             /**
74              * @see Zend_Ldap_Exception
75              */
76             require_once 'Zend/Ldap/Exception.php';
77             throw new Zend_Ldap_Exception($this, 'deleting: ' . $dn);
78         }
79         return $this;
80     }
81     
82     /**
83      * read binary attribute from one entry from the ldap directory
84      *
85      * @todo still needed???
86      * 
87      * @param string $_dn the dn to read
88      * @param string $_filter search filter
89      * @param array $_attribute which field to return
90      * @return blob binary data of given field
91      * @throws  Exception with ldap error
92      */
93     public function fetchBinaryAttribute($_dn, $_filter, $_attribute)
94     {
95         $searchResult = @ldap_search($this->getResource(), $_dn, $_filter, $_attribute, $this->_attrsOnly, $this->_sizeLimit, $this->_timeLimit);
96         
97         if($searchResult === FALSE) {
98             throw new Exception(ldap_error($this->getResource()));
99         }
100         
101         $searchCount = ldap_count_entries($this->getResource(), $searchResult);
102         if($searchCount === 0) {
103             throw new Exception('Nothing found for filter: ' . $_filter);
104         } elseif ($searchCount > 1) {
105             throw new Exception('More than one entry found for filter: ' . $_filter);
106         }
107         
108         $entry = ldap_first_entry($this->getResource(), $searchResult);
109         
110         return ldap_get_values_len($this->getResource(), $entry, $_attribute);
111     }
112     
113     /**
114      * Add new information to the LDAP repository
115      *
116      * @param string|Zend_Ldap_Dn $dn
117      * @param array $entry
118      * @return Zend_Ldap *Provides a fluid interface*
119      * @throws Zend_Ldap_Exception
120      */
121     public function addProperty($dn, array $entry)
122     {
123         if (!($dn instanceof Zend_Ldap_Dn)) {
124             $dn = Zend_Ldap_Dn::factory($dn, null);
125         }
126         self::prepareLdapEntryArray($entry);
127         foreach ($entry as $key => $value) {
128             if (is_array($value) && count($value) === 0) {
129                 unset($entry[$key]);
130             }
131         }
132
133         $rdnParts = $dn->getRdn(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER);
134         $adAttributes = array('distinguishedname', 'instancetype', 'name', 'objectcategory',
135             'objectguid', 'usnchanged', 'usncreated', 'whenchanged', 'whencreated');
136         $stripAttributes = array_merge(array_keys($rdnParts), $adAttributes);
137         foreach ($stripAttributes as $attr) {
138             if ((isset($entry[$attr]) || array_key_exists($attr, $entry))) {
139                 unset($entry[$attr]);
140             }
141         }
142         
143         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  $dn: ' . $dn->toString());
144         if (Tinebase_Core::isLogLevel(Zend_Log::DEBUG)) Tinebase_Core::getLogger()->debug(__METHOD__ . '::' . __LINE__ . '  $data: ' . print_r($entry, true));
145         
146         $isAdded = @ldap_mod_add($this->getResource(), $dn->toString(), $entry);
147         if($isAdded === false) {
148             /**
149              * @see Zend_Ldap_Exception
150              */
151             require_once 'Zend/Ldap/Exception.php';
152             throw new Zend_Ldap_Exception($this, 'adding: ' . $dn->toString());
153         }
154         return $this;
155     }
156     
157     /**
158      * Update LDAP registry
159      *
160      * @param string|Zend_Ldap_Dn $dn
161      * @param array $entry
162      * @return Zend_Ldap *Provides a fluid interface*
163      * @throws Zend_Ldap_Exception
164      */
165     public function updateProperty($dn, array $entry)
166     {
167         if (!($dn instanceof Zend_Ldap_Dn)) {
168             $dn = Zend_Ldap_Dn::factory($dn, null);
169         }
170         self::prepareLdapEntryArray($entry);
171
172         $rdnParts = $dn->getRdn(Zend_Ldap_Dn::ATTR_CASEFOLD_LOWER);
173         $adAttributes = array('distinguishedname', 'instancetype', 'name', 'objectcategory',
174             'objectguid', 'usnchanged', 'usncreated', 'whenchanged', 'whencreated');
175         $stripAttributes = array_merge(array_keys($rdnParts), $adAttributes);
176         foreach ($stripAttributes as $attr) {
177             if ((isset($entry[$attr]) || array_key_exists($attr, $entry))) {
178                 unset($entry[$attr]);
179             }
180         }
181
182         if (count($entry) > 0) {
183             $isModified = @ldap_mod_replace($this->getResource(), $dn->toString(), $entry);
184             if($isModified === false) {
185                 /**
186                  * @see Zend_Ldap_Exception
187                  */
188                 require_once 'Zend/Ldap/Exception.php';
189                 throw new Zend_Ldap_Exception($this, 'updating: ' . $dn->toString());
190             }
191         }
192         return $this;
193     }
194     
195     /**
196      * return first namingContext from LDAP root DSE
197      * 
198      * @return string
199      */
200     public function getFirstNamingContext()
201     {
202         return array_value(0, $this->getRootDse()->getNamingContexts());
203     }
204     
205     /**
206      * convert binary objectGUID to to plain ASCII string
207      * example guid: c8ab4322-3a4b-4af9-a100-9ed746049c91
208      * 
209      * @param  string  $binaryGuid
210      * @return string
211      */
212     public static function decodeGuid($binaryGuid)
213     {
214         $hexGuid = unpack("H*hex", $binaryGuid); 
215         $hex = $hexGuid["hex"];
216         
217         $hex1 = substr($hex, -26, 2) . substr($hex, -28, 2) . substr($hex, -30, 2) . substr($hex, -32, 2);
218         $hex2 = substr($hex, -22, 2) . substr($hex, -24, 2);
219         $hex3 = substr($hex, -18, 2) . substr($hex, -20, 2);
220         $hex4 = substr($hex, -16, 4);
221         $hex5 = substr($hex, -12, 12);
222         
223         $guid = $hex1 . "-" . $hex2 . "-" . $hex3 . "-" . $hex4 . "-" . $hex5;
224         
225         return $guid;
226     }
227     
228     /**
229      * convert plain ASCII objectGUID to binary string
230      * example guid: c8ab4322-3a4b-4af9-a100-9ed746049c91
231      * 
232      * @param  string $guid
233      * @return string
234      */
235     public static function encodeGuid($guid)
236     {
237         $hex  = substr($guid, -30, 2) . substr($guid, -32, 2) . substr($guid, -34, 2) . substr($guid, -36, 2);
238         $hex .= substr($guid, -25, 2) . substr($guid, -27, 2);
239         $hex .= substr($guid, -20, 2) . substr($guid, -22, 2);
240         $hex .= substr($guid, -17, 4);
241         $hex .= substr($guid, -12, 12);
242         
243         $binaryGuid = pack('H*', $hex);
244         
245         return $binaryGuid;
246     }
247     
248     /**
249      * decode ActiveDirectory SID
250      * 
251      * @param  string  $binarySid  the binary encoded SID
252      * @return string
253      */
254     public static function decodeSid($binarySid) 
255     {
256         if (strpos($binarySid, '-') !== false) {
257             return $binarySid;
258         }
259         
260         $sid = false; 
261         
262         $unpacked = unpack("crev/cdashes/nc/Nd/V*e", $binarySid); 
263         
264         if ($unpacked) { 
265             $n232 = pow(2,32); 
266             unset($unpacked["dashes"]); // unused 
267             $unpacked["c"] = $n232 * $unpacked["c"] + $unpacked["d"]; 
268             unset($unpacked["d"]); 
269             
270             $sid = "S";
271             
272             foreach ($unpacked as $v) { 
273                 if ($v < 0) {
274                     $v = $n232 + $v; 
275                 }
276                 $sid .= '-' . $v; 
277             } 
278         }
279          
280         return $sid; 
281     }
282 }