5100704d |
1 | <?php |
35586184 |
2 | /** |
3 | * abook_ldap_server.php |
4 | * |
82d304a0 |
5 | * Copyright (c) 1999-2004 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) { |
210 | if($this->charset == 'utf-8') { |
211 | if(function_exists('utf8_encode')) { |
212 | return utf8_encode($str); |
213 | } else { |
214 | return $str; |
215 | } |
216 | } else { |
217 | return $str; |
218 | } |
219 | } |
220 | |
981681d5 |
221 | /** |
222 | * Decode from charset used by this LDAP server to html entities |
223 | * |
224 | * Uses squirrelmail charset_decode functions |
225 | * @param string string that has to be decoded |
226 | * @return string decoded string |
227 | */ |
06b4facd |
228 | function charset_decode($str) { |
981681d5 |
229 | global $default_charset; |
230 | if ($this->charset != $default_charset) { |
231 | return charset_decode($this->charset,$str); |
06b4facd |
232 | } else { |
233 | return $str; |
234 | } |
235 | } |
236 | |
62f7daa5 |
237 | |
06b4facd |
238 | /* ========================== Public ======================== */ |
239 | |
981681d5 |
240 | /** |
241 | * Search the LDAP server |
242 | * @param string $expr search expression |
243 | * @return array search results |
244 | */ |
06b4facd |
245 | function search($expr) { |
62f7daa5 |
246 | |
06b4facd |
247 | /* To be replaced by advanded search expression parsing */ |
248 | if(is_array($expr)) return false; |
62f7daa5 |
249 | |
06b4facd |
250 | /* Encode the expression */ |
251 | $expr = $this->charset_encode($expr); |
252 | if(strstr($expr, '*') === false) { |
253 | $expr = "*$expr*"; |
254 | } |
255 | $expression = "cn=$expr"; |
62f7daa5 |
256 | |
06b4facd |
257 | /* Make sure connection is there */ |
258 | if(!$this->open()) { |
259 | return false; |
260 | } |
62f7daa5 |
261 | |
cccfa9c2 |
262 | $sret = @ldap_search($this->linkid, $this->basedn, $expression, |
981681d5 |
263 | array('dn', 'o', 'ou', 'sn', 'givenname', 'cn', 'mail'), |
cccfa9c2 |
264 | 0, $this->maxrows, $this->timeout); |
62f7daa5 |
265 | |
06b4facd |
266 | /* Should get error from server using the ldap_error() function, |
267 | * but it only exist in the PHP LDAP documentation. */ |
268 | if(!$sret) { |
269 | if(function_exists('ldap_error')) { |
62f7daa5 |
270 | return $this->set_error(ldap_error($this->linkid)); |
06b4facd |
271 | } else { |
62f7daa5 |
272 | return $this->set_error('ldap_search failed'); |
06b4facd |
273 | } |
274 | } |
62f7daa5 |
275 | |
06b4facd |
276 | if(@ldap_count_entries($this->linkid, $sret) <= 0) { |
277 | return array(); |
278 | } |
62f7daa5 |
279 | |
06b4facd |
280 | /* Get results */ |
281 | $ret = array(); |
282 | $returned_rows = 0; |
283 | $res = @ldap_get_entries($this->linkid, $sret); |
284 | for($i = 0 ; $i < $res['count'] ; $i++) { |
285 | $row = $res[$i]; |
62f7daa5 |
286 | |
06b4facd |
287 | /* Extract data common for all e-mail addresses |
288 | * of an object. Use only the first name */ |
289 | $nickname = $this->charset_decode($row['dn']); |
290 | $fullname = $this->charset_decode($row['cn'][0]); |
62f7daa5 |
291 | |
06b4facd |
292 | if(!empty($row['ou'][0])) { |
293 | $label = $this->charset_decode($row['ou'][0]); |
294 | } |
295 | else if(!empty($row['o'][0])) { |
296 | $label = $this->charset_decode($row['o'][0]); |
297 | } else { |
298 | $label = ''; |
299 | } |
62f7daa5 |
300 | |
06b4facd |
301 | if(empty($row['givenname'][0])) { |
302 | $firstname = ''; |
303 | } else { |
304 | $firstname = $this->charset_decode($row['givenname'][0]); |
305 | } |
62f7daa5 |
306 | |
06b4facd |
307 | if(empty($row['sn'][0])) { |
308 | $surname = ''; |
309 | } else { |
310 | $surname = $this->charset_decode($row['sn'][0]); |
311 | } |
62f7daa5 |
312 | |
06b4facd |
313 | /* Add one row to result for each e-mail address */ |
314 | if(isset($row['mail']['count'])) { |
315 | for($j = 0 ; $j < $row['mail']['count'] ; $j++) { |
316 | array_push($ret, array('nickname' => $nickname, |
317 | 'name' => $fullname, |
318 | 'firstname' => $firstname, |
319 | 'lastname' => $surname, |
320 | 'email' => $row['mail'][$j], |
321 | 'label' => $label, |
06b4facd |
322 | 'backend' => $this->bnum, |
323 | 'source' => &$this->sname)); |
62f7daa5 |
324 | |
06b4facd |
325 | // Limit number of hits |
326 | $returned_rows++; |
62f7daa5 |
327 | if(($returned_rows >= $this->maxrows) && |
06b4facd |
328 | ($this->maxrows > 0) ) { |
329 | ldap_free_result($sret); |
330 | return $ret; |
331 | } |
332 | |
333 | } // for($j ...) |
334 | |
335 | } // isset($row['mail']['count']) |
62f7daa5 |
336 | |
06b4facd |
337 | } |
62f7daa5 |
338 | |
06b4facd |
339 | ldap_free_result($sret); |
340 | return $ret; |
341 | } /* end search() */ |
342 | |
343 | |
981681d5 |
344 | /** |
345 | * List all entries present in LDAP server |
06b4facd |
346 | * |
981681d5 |
347 | * If you run a tiny LDAP server and you want the "List All" button |
348 | * to show EVERYONE, disable first return call and enable the second one. |
349 | * Remember that maxrows setting might limit list of returned entries. |
06b4facd |
350 | * |
981681d5 |
351 | * Careful with this -- it could get quite large for big sites. |
352 | * @return array all entries in ldap server |
353 | */ |
354 | function list_addr() { |
355 | return array(); |
356 | // return $this->search('*'); |
357 | } |
06b4facd |
358 | } |
62f7daa5 |
359 | ?> |