author | Dan Fuhry <dan@fuhry.us> |
Fri, 18 Jan 2013 19:59:50 -0500 | |
changeset 5 | cdd708efa505 |
parent 4 | 2212b2ded8bf |
child 8 | f68fdcc18df9 |
permissions | -rw-r--r-- |
0 | 1 |
<?php |
2 |
||
3 |
// BEGIN CONSTANTS |
|
4 |
||
5 |
$ldap_readonly_attrs = array( |
|
6 |
'uid' |
|
7 |
, 'objectClass' |
|
8 |
, 'userPassword' |
|
9 |
, 'homeDirectory' |
|
10 |
, 'uidNumber' |
|
11 |
, 'gidNumber' |
|
12 |
); |
|
13 |
||
14 |
$ldap_field_names = array( |
|
15 |
'cn' => 'Common name' |
|
16 |
, 'uid' => 'Username' |
|
17 |
, 'givenName' => 'Given name' |
|
18 |
, 'sn' => 'Surname' |
|
19 |
, 'mail' => 'E-mail' |
|
20 |
, 'title' => 'Job title' |
|
21 |
, 'telephoneNumber' => 'Phone' |
|
22 |
); |
|
23 |
||
24 |
$ldap_add_single = array( |
|
25 |
'title' |
|
26 |
, 'mail' |
|
27 |
); |
|
28 |
||
29 |
$ldap_add_multiple = array( |
|
30 |
'telephoneNumber' |
|
31 |
, 'mobile' |
|
32 |
, 'mail' |
|
4
2212b2ded8bf
Added OpenSSH public key support in LDAP
Dan Fuhry <dan@fuhry.us>
parents:
3
diff
changeset
|
33 |
, 'sshPublicKey' |
0 | 34 |
); |
35 |
||
36 |
// END CONSTANTS |
|
37 |
||
38 |
global $_ldapconn; |
|
39 |
$_ldapconn = ldap_connect($ldap_server); |
|
40 |
if ( !$_ldapconn ) |
|
41 |
die("Failed to connect to the LDAP database"); |
|
42 |
||
43 |
if ( !ldap_set_option($_ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3) ) |
|
44 |
die("Failed to set LDAP version to 3"); |
|
45 |
||
46 |
if ( !ldap_bind($_ldapconn, $ldap_manager['dn'], $ldap_manager['password']) ) |
|
47 |
die("Failed to bind to LDAP as a manager"); |
|
48 |
||
49 |
register_shutdown_function(function() use ($_ldapconn) |
|
50 |
{ |
|
51 |
ldap_unbind($_ldapconn); |
|
52 |
}); |
|
53 |
||
54 |
||
55 |
function ldap_escape($str) |
|
56 |
{ |
|
57 |
// FIXME escape properly |
|
58 |
return $str; |
|
59 |
} |
|
60 |
||
61 |
function ldap_get_user($username) |
|
62 |
{ |
|
63 |
global $_ldapconn, $ldap_user_basedn; |
|
64 |
||
65 |
$search_filter = sprintf("(&(uid=%s)(objectClass=posixAccount))", ldap_escape($username)); |
|
66 |
||
67 |
$search_result = ldap_search($_ldapconn, $ldap_user_basedn, $search_filter); |
|
68 |
if ( ldap_count_entries($_ldapconn, $search_result) !== 1 ) |
|
69 |
return false; |
|
70 |
||
71 |
return ldap_array_cleanup(ldap_get_attributes($_ldapconn, ldap_first_entry($_ldapconn, $search_result))); |
|
72 |
} |
|
73 |
||
74 |
function ldap_get_group($group) |
|
75 |
{ |
|
76 |
global $_ldapconn, $ldap_group_basedn; |
|
77 |
||
78 |
$search_filter = sprintf("(&(cn=%s)(objectClass=posixGroup))", ldap_escape($group)); |
|
79 |
||
80 |
$search_result = ldap_search($_ldapconn, $ldap_group_basedn, $search_filter); |
|
81 |
if ( ldap_count_entries($_ldapconn, $search_result) !== 1 ) |
|
82 |
return false; |
|
83 |
||
84 |
$result = ldap_array_cleanup(ldap_get_attributes($_ldapconn, ldap_first_entry($_ldapconn, $search_result))); |
|
85 |
if ( !isset($result['memberUid']) ) |
|
86 |
$result['memberUid'] = array(); |
|
87 |
if ( !is_array($result['memberUid']) ) |
|
88 |
$result['memberUid'] = array($result['memberUid']); |
|
89 |
||
90 |
return $result; |
|
91 |
} |
|
92 |
||
93 |
function ldap_update_user($user, $entry) |
|
94 |
{ |
|
95 |
global $_ldapconn; |
|
96 |
||
97 |
return ldap_modify($_ldapconn, ldap_make_user_dn($user), $entry); |
|
98 |
} |
|
99 |
||
100 |
function ldap_list_users() |
|
101 |
{ |
|
102 |
global $_ldapconn, $ldap_user_basedn; |
|
103 |
||
104 |
$search_result = ldap_search($_ldapconn, $ldap_user_basedn, '(objectClass=organizationalPerson)'); |
|
105 |
||
106 |
$results = array(); |
|
107 |
for ( $entry = ldap_first_entry($_ldapconn, $search_result); |
|
108 |
$entry; |
|
109 |
$entry = ldap_next_entry($_ldapconn, $entry) ) |
|
110 |
{ |
|
111 |
$entry_arr = ldap_array_cleanup(ldap_get_attributes($_ldapconn, $entry)); |
|
112 |
$results[$entry_arr['uid']] = $entry_arr; |
|
113 |
} |
|
114 |
||
115 |
return $results; |
|
116 |
} |
|
117 |
||
118 |
function ldap_list_groups() |
|
119 |
{ |
|
120 |
global $_ldapconn, $ldap_group_basedn; |
|
121 |
||
122 |
$search_result = ldap_search($_ldapconn, $ldap_group_basedn, '(objectClass=posixGroup)'); |
|
123 |
||
124 |
$results = array(); |
|
125 |
for ( $entry = ldap_first_entry($_ldapconn, $search_result); |
|
126 |
$entry; |
|
127 |
$entry = ldap_next_entry($_ldapconn, $entry) ) |
|
128 |
{ |
|
129 |
$entry_arr = ldap_array_cleanup(ldap_get_attributes($_ldapconn, $entry)); |
|
130 |
$results[$entry_arr['cn']] = $entry_arr; |
|
131 |
} |
|
132 |
||
133 |
return $results; |
|
134 |
} |
|
135 |
||
136 |
function ldap_array_cleanup($arr) |
|
137 |
{ |
|
4
2212b2ded8bf
Added OpenSSH public key support in LDAP
Dan Fuhry <dan@fuhry.us>
parents:
3
diff
changeset
|
138 |
global $ldap_add_multiple; |
2212b2ded8bf
Added OpenSSH public key support in LDAP
Dan Fuhry <dan@fuhry.us>
parents:
3
diff
changeset
|
139 |
|
0 | 140 |
$result = array(); |
141 |
foreach ( $arr as $k => $v ) |
|
142 |
{ |
|
143 |
if ( is_int($k) || $k == 'count' ) |
|
144 |
continue; |
|
145 |
||
4
2212b2ded8bf
Added OpenSSH public key support in LDAP
Dan Fuhry <dan@fuhry.us>
parents:
3
diff
changeset
|
146 |
if ( $v['count'] === 1 && !in_array($k, $ldap_add_multiple) ) |
0 | 147 |
$v = $v[0]; |
148 |
else |
|
149 |
unset($v['count']); |
|
150 |
||
151 |
$result[$k] = $v; |
|
152 |
} |
|
153 |
||
154 |
return $result; |
|
155 |
} |
|
156 |
||
157 |
function ldap_make_user_dn($username) |
|
158 |
{ |
|
159 |
global $ldap_user_basedn; |
|
160 |
return sprintf('uid=%s,%s', ldap_escape($username), $ldap_user_basedn); |
|
161 |
} |
|
162 |
||
163 |
function ldap_make_group_dn($group) |
|
164 |
{ |
|
165 |
global $ldap_group_basedn; |
|
166 |
return sprintf('cn=%s,%s', ldap_escape($group), $ldap_group_basedn); |
|
167 |
} |
|
168 |
||
169 |
function ldap_replace_attr($dn, $attribute, $value) |
|
170 |
{ |
|
171 |
global $_ldapconn; |
|
172 |
||
173 |
$ldif = array( |
|
174 |
$attribute => array($value) |
|
175 |
); |
|
176 |
||
177 |
return ldap_mod_replace($_ldapconn, $dn, $ldif); |
|
178 |
} |
|
179 |
||
180 |
function ldap_delete_user($username) |
|
181 |
{ |
|
182 |
global $_ldapconn, $ldap_user_basedn, $ldap_group_basedn; |
|
183 |
||
184 |
// remove user from all LDAP groups |
|
185 |
$search_filter = sprintf("(&(memberUid=%s)(objectClass=posixGroup))", ldap_escape($username)); |
|
186 |
$search_result = ldap_search($_ldapconn, $ldap_group_basedn, $search_filter); |
|
187 |
for ( $entry = ldap_first_entry($_ldapconn, $search_result); |
|
188 |
$entry; |
|
189 |
$entry = ldap_next_entry($_ldapconn, $entry) ) |
|
190 |
{ |
|
191 |
$entry_arr = ldap_array_cleanup(ldap_get_attributes($_ldapconn, $entry)); |
|
192 |
$dn = ldap_get_dn($_ldapconn, $entry); |
|
193 |
ldap_mod_del($_ldapconn, $dn, array('memberUid' => array($username))); |
|
194 |
} |
|
195 |
||
196 |
// delete user DN |
|
197 |
return ldap_delete($_ldapconn, ldap_make_user_dn($username)); |
|
198 |
} |
|
199 |
||
200 |
function ldap_delete_group_member($gid, $uid) |
|
201 |
{ |
|
202 |
global $_ldapconn; |
|
203 |
||
204 |
return ldap_mod_del($_ldapconn, ldap_make_group_dn($gid), array('memberUid' => array($uid))); |
|
205 |
} |
|
206 |
||
207 |
function ldap_add_group_member($gid, $uid) |
|
208 |
{ |
|
209 |
global $_ldapconn; |
|
210 |
||
211 |
return ldap_mod_add($_ldapconn, ldap_make_group_dn($gid), array('memberUid' => array($uid))); |
|
212 |
} |
|
213 |
||
214 |
function get_next_available_uid() |
|
215 |
{ |
|
216 |
$users = ldap_list_users(); |
|
217 |
$uids = array(); |
|
218 |
foreach ( $users as $u ) |
|
219 |
$uids[] = intval($u['uidNumber']); |
|
220 |
||
221 |
asort($uids); |
|
222 |
$uid = UID_MIN; |
|
223 |
$last_uid = $uids[0]; |
|
224 |
foreach ( $uids as $u ) |
|
225 |
{ |
|
226 |
if ( $u > $last_uid + 1 && ($last_uid + 1) > UID_MIN ) |
|
227 |
{ |
|
228 |
return $last_uid + 1; |
|
229 |
} |
|
230 |
||
231 |
$last_uid = $u; |
|
232 |
} |
|
233 |
||
234 |
return max($uids) + 1; |
|
235 |
} |
|
236 |
||
237 |
function get_next_available_gid() |
|
238 |
{ |
|
239 |
$groups = ldap_list_groups(); |
|
240 |
$gids = array(); |
|
241 |
foreach ( $groups as $g ) |
|
242 |
$gids[] = intval($g['gidNumber']); |
|
243 |
||
244 |
asort($gids); |
|
245 |
$gid = GID_MIN; |
|
246 |
$last_gid = $gids[0]; |
|
247 |
foreach ( $gids as $g ) |
|
248 |
{ |
|
249 |
if ( $g > $last_gid + 1 && ($last_gid + 1) > GID_MIN ) |
|
250 |
{ |
|
251 |
return $last_gid + 1; |
|
252 |
} |
|
253 |
||
254 |
$last_gid = $g; |
|
255 |
} |
|
256 |
||
257 |
return max($gids) + 1; |
|
258 |
} |
|
259 |
||
260 |
function get_next_available_extension() |
|
261 |
{ |
|
262 |
$users = ldap_list_users(); |
|
263 |
$exts = array(); |
|
264 |
foreach ( $users as $u ) |
|
265 |
{ |
|
266 |
if ( !isset($u['telephoneNumber']) ) |
|
267 |
continue; |
|
268 |
||
269 |
if ( !is_array($u['telephoneNumber']) ) |
|
270 |
$u['telephoneNumber'] = array($u['telephoneNumber']); |
|
271 |
||
272 |
foreach ( $u['telephoneNumber'] as $n ) |
|
273 |
{ |
|
274 |
if ( preg_match('/^([0-9]+) \(extension\)$/', $n, $match) ) |
|
275 |
$exts[] = intval($n); |
|
276 |
} |
|
277 |
} |
|
278 |
||
279 |
asort($exts); |
|
280 |
$ext = PHONE_EXT_MIN; |
|
281 |
$last_ext = PHONE_EXT_MIN - 1; |
|
282 |
foreach ( $exts as $e ) |
|
283 |
{ |
|
284 |
if ( $e > $last_ext + 1 && ($last_ext + 1) > UID_MIN ) |
|
285 |
{ |
|
286 |
return $last_ext + 1; |
|
287 |
} |
|
288 |
||
289 |
$last_ext = $e; |
|
290 |
} |
|
291 |
||
292 |
return count($exts) ? max($exts) + 1 : PHONE_EXT_MIN; |
|
293 |
} |
|
294 |
||
295 |
function ldap_create_user($username, $gn, $sn, $cn, $title) |
|
296 |
{ |
|
297 |
global $_ldapconn; |
|
298 |
||
299 |
$krb_realm = get_default_kerberos_realm(); |
|
300 |
||
301 |
if ( !ldap_add($_ldapconn, ldap_make_user_dn($username), array( |
|
302 |
'cn' => array($cn) |
|
303 |
, 'uid' => array($username) |
|
304 |
, 'objectClass' => array( |
|
305 |
'top' |
|
306 |
, 'person' |
|
307 |
, 'inetOrgPerson' |
|
308 |
, 'organizationalPerson' |
|
309 |
, 'posixAccount' |
|
4
2212b2ded8bf
Added OpenSSH public key support in LDAP
Dan Fuhry <dan@fuhry.us>
parents:
3
diff
changeset
|
310 |
, 'ldapPublicKey' |
0 | 311 |
) |
312 |
, 'gn' => array($gn) |
|
313 |
, 'sn' => array($sn) |
|
314 |
, 'userPassword' => array("{SASL}$username@$krb_realm") |
|
315 |
, 'loginShell' => array('/bin/bash') |
|
316 |
, 'homeDirectory' => array("/home/users/$username") |
|
317 |
, 'uidNumber' => array(get_next_available_uid()) |
|
318 |
, 'gidNumber' => array(500) |
|
319 |
, 'title' => array($title) |
|
320 |
)) ) |
|
321 |
return false; |
|
322 |
||
323 |
if ( !ldap_mod_add($_ldapconn, ldap_make_group_dn('users'), array('memberUid' => array($username))) ) |
|
324 |
return false; |
|
325 |
||
326 |
return true; |
|
327 |
} |
|
328 |
||
329 |
function ldap_create_group($cn, $description) |
|
330 |
{ |
|
331 |
global $_ldapconn; |
|
332 |
||
333 |
if ( !ldap_add($_ldapconn, ldap_make_group_dn($cn), array( |
|
334 |
'cn' => array($cn) |
|
335 |
, 'description' => array($description) |
|
336 |
, 'gidNumber' => array(get_next_available_gid()) |
|
337 |
, 'objectClass' => array( |
|
338 |
'top' |
|
339 |
, 'posixGroup' |
|
340 |
) |
|
341 |
)) ) |
|
342 |
return false; |
|
343 |
} |
|
344 |
||
345 |
function ldap_delete_group($cn) |
|
346 |
{ |
|
347 |
global $_ldapconn; |
|
348 |
||
349 |
$group = ldap_get_group($cn); |
|
350 |
$users = ldap_list_users(); |
|
351 |
||
352 |
foreach ( $users as $u ) |
|
353 |
{ |
|
354 |
if ( $u['gidNumber'] === $group['gidNumber'] ) |
|
355 |
return false; |
|
356 |
} |
|
357 |
||
358 |
return ldap_delete($_ldapconn, ldap_make_group_dn($cn)); |
|
359 |
} |
|
3 | 360 |
|
361 |
/** |
|
362 |
* Is the given username in the specified LDAP group? |
|
363 |
* @param string username |
|
364 |
* @param string Group name |
|
365 |
* @return bool |
|
366 |
*/ |
|
367 |
||
368 |
function ldap_test_group_membership($username, $group) |
|
369 |
{ |
|
370 |
global $_ldapconn, $ldap_group_basedn; |
|
371 |
||
372 |
$filter = sprintf('(&(memberUid=%s)(cn=%s)(objectClass=posixGroup))', ldap_escape($username), ldap_escape($group)); |
|
373 |
||
374 |
$result = ldap_search($_ldapconn, $ldap_group_basedn, $filter); |
|
375 |
return ldap_count_entries($_ldapconn, $result) > 0; |
|
376 |
} |