5100704d |
1 | <?php |
35586184 |
2 | /** |
3 | * abook_ldap_server.php |
4 | * |
6c84ba1e |
5 | * Copyright (c) 1999-2005 The SquirrelMail Project Team |
35586184 |
6 | * Licensed under the GNU GPL. For full terms see the file COPYING. |
7 | * |
981681d5 |
8 | * Address book backend for LDAP server |
9 | * |
10 | * @version $Id$ |
11 | * @package squirrelmail |
12 | * @subpackage addressbook |
13 | */ |
14 | |
15 | /** |
35586184 |
16 | * Address book backend for LDAP server |
17 | * |
18 | * An array with the following elements must be passed to |
19 | * the class constructor (elements marked ? are optional): |
981681d5 |
20 | * <pre> |
35586184 |
21 | * host => LDAP server hostname/IP-address |
22 | * base => LDAP server root (base dn). Empty string allowed. |
23 | * ? port => LDAP server TCP port number (default: 389) |
24 | * ? charset => LDAP server charset (default: utf-8) |
25 | * ? name => Name for LDAP server (default "LDAP: hostname") |
26 | * Used to tag the result data |
27 | * ? maxrows => Maximum # of rows in search result |
28 | * ? timeout => Timeout for LDAP operations (in seconds, default: 30) |
29 | * Might not work for all LDAP libraries or servers. |
30e9932c |
30 | * ? binddn => LDAP Bind DN. |
31 | * ? bindpw => LDAP Bind Password. |
32 | * ? protocol => LDAP Bind protocol. |
981681d5 |
33 | * </pre> |
35586184 |
34 | * NOTE. This class should not be used directly. Use the |
35 | * "AddressBook" class instead. |
d6c32258 |
36 | * @package squirrelmail |
a9d318b0 |
37 | * @subpackage addressbook |
35586184 |
38 | */ |
35586184 |
39 | class abook_ldap_server extends addressbook_backend { |
981681d5 |
40 | /** |
41 | * @var string backend type |
42 | */ |
06b4facd |
43 | var $btype = 'remote'; |
981681d5 |
44 | /** |
45 | * @var string backend name |
46 | */ |
06b4facd |
47 | var $bname = 'ldap_server'; |
48 | |
49 | /* Parameters changed by class */ |
981681d5 |
50 | /** |
51 | * @var string displayed name |
52 | */ |
06b4facd |
53 | var $sname = 'LDAP'; /* Service name */ |
981681d5 |
54 | /** |
55 | * @var string LDAP server name or address or url |
56 | */ |
57 | var $server = ''; |
58 | /** |
59 | * @var integer LDAP server port |
60 | */ |
61 | var $port = 389; |
62 | /** |
63 | * @var string LDAP base DN |
64 | */ |
65 | var $basedn = ''; |
66 | /** |
67 | * @var string charset used for entries in LDAP server |
68 | */ |
69 | var $charset = 'utf-8'; |
70 | /** |
71 | * @var object PHP LDAP link ID |
72 | */ |
73 | var $linkid = false; |
74 | /** |
75 | * @var bool True if LDAP server is bound |
76 | */ |
77 | var $bound = false; |
78 | /** |
79 | * @var integer max rows in result |
80 | */ |
81 | var $maxrows = 250; |
82 | /** |
83 | * @var integer timeout of LDAP operations (in seconds) |
84 | */ |
85 | var $timeout = 30; |
86 | /** |
87 | * @var string DN to bind to (non-anonymous bind) |
88 | * @since 1.5.0 and 1.4.3 |
89 | */ |
90 | var $binddn = ''; |
91 | /** |
92 | * @var string password to bind with (non-anonymous bind) |
93 | * @since 1.5.0 and 1.4.3 |
94 | */ |
95 | var $bindpw = ''; |
96 | /** |
97 | * @var integer protocol used to connect to ldap server |
98 | * @since 1.5.0 and 1.4.3 |
99 | */ |
100 | var $protocol = ''; |
101 | |
102 | /** |
103 | * Constructor. Connects to database |
104 | * @param array connection options |
105 | */ |
06b4facd |
106 | function abook_ldap_server($param) { |
107 | if(!function_exists('ldap_connect')) { |
108 | $this->set_error('LDAP support missing from PHP'); |
109 | return; |
110 | } |
111 | if(is_array($param)) { |
112 | $this->server = $param['host']; |
113 | $this->basedn = $param['base']; |
114 | if(!empty($param['port'])) { |
115 | $this->port = $param['port']; |
116 | } |
117 | if(!empty($param['charset'])) { |
118 | $this->charset = strtolower($param['charset']); |
119 | } |
120 | if(isset($param['maxrows'])) { |
121 | $this->maxrows = $param['maxrows']; |
122 | } |
123 | if(isset($param['timeout'])) { |
124 | $this->timeout = $param['timeout']; |
125 | } |
30e9932c |
126 | if(isset($param['binddn'])) { |
127 | $this->binddn = $param['binddn']; |
128 | } |
129 | if(isset($param['bindpw'])) { |
130 | $this->bindpw = $param['bindpw']; |
981681d5 |
131 | } |
30e9932c |
132 | if(isset($param['protocol'])) { |
133 | $this->protocol = $param['protocol']; |
981681d5 |
134 | } |
06b4facd |
135 | if(empty($param['name'])) { |
136 | $this->sname = 'LDAP: ' . $param['host']; |
137 | } |
138 | else { |
139 | $this->sname = $param['name']; |
140 | } |
62f7daa5 |
141 | |
06b4facd |
142 | $this->open(true); |
143 | } else { |
144 | $this->set_error('Invalid argument to constructor'); |
145 | } |
146 | } |
147 | |
148 | |
981681d5 |
149 | /** |
150 | * Open the LDAP server. |
151 | * @param bool $new is it a new connection |
152 | * @return bool |
153 | */ |
06b4facd |
154 | function open($new = false) { |
155 | $this->error = ''; |
62f7daa5 |
156 | |
06b4facd |
157 | /* Connection is already open */ |
158 | if($this->linkid != false && !$new) { |
159 | return true; |
160 | } |
62f7daa5 |
161 | |
06b4facd |
162 | $this->linkid = @ldap_connect($this->server, $this->port); |
163 | if(!$this->linkid) { |
164 | if(function_exists('ldap_error')) { |
62f7daa5 |
165 | return $this->set_error(ldap_error($this->linkid)); |
06b4facd |
166 | } else { |
167 | return $this->set_error('ldap_connect failed'); |
168 | } |
169 | } |
62f7daa5 |
170 | |
981681d5 |
171 | if(!empty($this->protocol)) { |
30e9932c |
172 | if(!@ldap_set_option($this->linkid, LDAP_OPT_PROTOCOL_VERSION, $this->protocol)) { |
173 | if(function_exists('ldap_error')) { |
174 | return $this->set_error(ldap_error($this->linkid)); |
175 | } else { |
176 | return $this->set_error('ldap_set_option failed'); |
981681d5 |
177 | } |
178 | } |
179 | } |
30e9932c |
180 | |
181 | if(!empty($this->binddn)) { |
182 | if(!@ldap_bind($this->linkid, $this->binddn, $this->bindpw)) { |
183 | if(function_exists('ldap_error')) { |
184 | return $this->set_error(ldap_error($this->linkid)); |
185 | } else { |
186 | return $this->set_error('authenticated ldap_bind failed'); |
187 | } |
188 | } |
189 | } else { |
981681d5 |
190 | if(!@ldap_bind($this->linkid)) { |
191 | if(function_exists('ldap_error')) { |
192 | return $this->set_error(ldap_error($this->linkid)); |
193 | } else { |
194 | return $this->set_error('anonymous ldap_bind failed'); |
195 | } |
196 | } |
06b4facd |
197 | } |
30e9932c |
198 | |
06b4facd |
199 | $this->bound = true; |
62f7daa5 |
200 | |
06b4facd |
201 | return true; |
202 | } |
203 | |
981681d5 |
204 | /** |
205 | * Encode string to the charset used by this LDAP server |
206 | * @param string string that has to be encoded |
207 | * @return string encoded string |
208 | */ |
06b4facd |
209 | function charset_encode($str) { |
b64dd897 |
210 | global $default_charset; |
211 | if($this->charset != $default_charset) { |
212 | return charset_convert($default_charset,$str,$this->charset,false); |
06b4facd |
213 | } else { |
214 | return $str; |
215 | } |
216 | } |
217 | |
981681d5 |
218 | /** |
b64dd897 |
219 | * Decode from charset used by this LDAP server to charset used by translation |
981681d5 |
220 | * |
598294a7 |
221 | * Uses SquirrelMail charset_decode functions |
981681d5 |
222 | * @param string string that has to be decoded |
223 | * @return string decoded string |
224 | */ |
06b4facd |
225 | function charset_decode($str) { |
981681d5 |
226 | global $default_charset; |
227 | if ($this->charset != $default_charset) { |
b64dd897 |
228 | return charset_convert($this->charset,$str,$default_charset,false); |
06b4facd |
229 | } else { |
230 | return $str; |
231 | } |
232 | } |
233 | |
62f7daa5 |
234 | |
06b4facd |
235 | /* ========================== Public ======================== */ |
236 | |
981681d5 |
237 | /** |
238 | * Search the LDAP server |
239 | * @param string $expr search expression |
240 | * @return array search results |
241 | */ |
06b4facd |
242 | function search($expr) { |
62f7daa5 |
243 | |
06b4facd |
244 | /* To be replaced by advanded search expression parsing */ |
245 | if(is_array($expr)) return false; |
62f7daa5 |
246 | |
06b4facd |
247 | /* Encode the expression */ |
248 | $expr = $this->charset_encode($expr); |
249 | if(strstr($expr, '*') === false) { |
250 | $expr = "*$expr*"; |
251 | } |
252 | $expression = "cn=$expr"; |
62f7daa5 |
253 | |
06b4facd |
254 | /* Make sure connection is there */ |
255 | if(!$this->open()) { |
256 | return false; |
257 | } |
62f7daa5 |
258 | |
cccfa9c2 |
259 | $sret = @ldap_search($this->linkid, $this->basedn, $expression, |
981681d5 |
260 | array('dn', 'o', 'ou', 'sn', 'givenname', 'cn', 'mail'), |
cccfa9c2 |
261 | 0, $this->maxrows, $this->timeout); |
62f7daa5 |
262 | |
06b4facd |
263 | /* Should get error from server using the ldap_error() function, |
264 | * but it only exist in the PHP LDAP documentation. */ |
265 | if(!$sret) { |
266 | if(function_exists('ldap_error')) { |
62f7daa5 |
267 | return $this->set_error(ldap_error($this->linkid)); |
06b4facd |
268 | } else { |
62f7daa5 |
269 | return $this->set_error('ldap_search failed'); |
06b4facd |
270 | } |
271 | } |
62f7daa5 |
272 | |
06b4facd |
273 | if(@ldap_count_entries($this->linkid, $sret) <= 0) { |
274 | return array(); |
275 | } |
62f7daa5 |
276 | |
06b4facd |
277 | /* Get results */ |
278 | $ret = array(); |
279 | $returned_rows = 0; |
280 | $res = @ldap_get_entries($this->linkid, $sret); |
281 | for($i = 0 ; $i < $res['count'] ; $i++) { |
282 | $row = $res[$i]; |
62f7daa5 |
283 | |
06b4facd |
284 | /* Extract data common for all e-mail addresses |
285 | * of an object. Use only the first name */ |
286 | $nickname = $this->charset_decode($row['dn']); |
287 | $fullname = $this->charset_decode($row['cn'][0]); |
62f7daa5 |
288 | |
06b4facd |
289 | if(!empty($row['ou'][0])) { |
290 | $label = $this->charset_decode($row['ou'][0]); |
291 | } |
292 | else if(!empty($row['o'][0])) { |
293 | $label = $this->charset_decode($row['o'][0]); |
294 | } else { |
295 | $label = ''; |
296 | } |
62f7daa5 |
297 | |
06b4facd |
298 | if(empty($row['givenname'][0])) { |
299 | $firstname = ''; |
300 | } else { |
301 | $firstname = $this->charset_decode($row['givenname'][0]); |
302 | } |
62f7daa5 |
303 | |
06b4facd |
304 | if(empty($row['sn'][0])) { |
305 | $surname = ''; |
306 | } else { |
307 | $surname = $this->charset_decode($row['sn'][0]); |
308 | } |
62f7daa5 |
309 | |
06b4facd |
310 | /* Add one row to result for each e-mail address */ |
311 | if(isset($row['mail']['count'])) { |
312 | for($j = 0 ; $j < $row['mail']['count'] ; $j++) { |
313 | array_push($ret, array('nickname' => $nickname, |
314 | 'name' => $fullname, |
315 | 'firstname' => $firstname, |
316 | 'lastname' => $surname, |
317 | 'email' => $row['mail'][$j], |
318 | 'label' => $label, |
06b4facd |
319 | 'backend' => $this->bnum, |
320 | 'source' => &$this->sname)); |
62f7daa5 |
321 | |
06b4facd |
322 | // Limit number of hits |
323 | $returned_rows++; |
62f7daa5 |
324 | if(($returned_rows >= $this->maxrows) && |
06b4facd |
325 | ($this->maxrows > 0) ) { |
326 | ldap_free_result($sret); |
327 | return $ret; |
328 | } |
329 | |
330 | } // for($j ...) |
331 | |
332 | } // isset($row['mail']['count']) |
62f7daa5 |
333 | |
06b4facd |
334 | } |
62f7daa5 |
335 | |
06b4facd |
336 | ldap_free_result($sret); |
337 | return $ret; |
338 | } /* end search() */ |
339 | |
340 | |
981681d5 |
341 | /** |
342 | * List all entries present in LDAP server |
06b4facd |
343 | * |
981681d5 |
344 | * If you run a tiny LDAP server and you want the "List All" button |
345 | * to show EVERYONE, disable first return call and enable the second one. |
346 | * Remember that maxrows setting might limit list of returned entries. |
06b4facd |
347 | * |
981681d5 |
348 | * Careful with this -- it could get quite large for big sites. |
349 | * @return array all entries in ldap server |
350 | */ |
351 | function list_addr() { |
352 | return array(); |
353 | // return $this->search('*'); |
354 | } |
06b4facd |
355 | } |
62f7daa5 |
356 | ?> |