<?php
// BEGIN CONSTANTS
$ldap_readonly_attrs = array(
'uid'
, 'objectClass'
, 'userPassword'
, 'homeDirectory'
, 'uidNumber'
, 'gidNumber'
);
$ldap_field_names = array(
'cn' => 'Common name'
, 'uid' => 'Username'
, 'givenName' => 'Given name'
, 'sn' => 'Surname'
, 'mail' => 'E-mail'
, 'title' => 'Job title'
, 'telephoneNumber' => 'Phone'
);
$ldap_add_single = array(
'title'
, 'mail'
);
$ldap_add_multiple = array(
'telephoneNumber'
, 'mobile'
, 'mail'
, 'sshPublicKey'
);
// END CONSTANTS
global $_ldapconn;
$_ldapconn = ldap_connect($ldap_server);
if ( !$_ldapconn )
die("Failed to connect to the LDAP database");
if ( !ldap_set_option($_ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3) )
die("Failed to set LDAP version to 3");
if ( !ldap_bind($_ldapconn, $ldap_manager['dn'], $ldap_manager['password']) )
die("Failed to bind to LDAP as a manager");
register_shutdown_function(function() use ($_ldapconn)
{
ldap_unbind($_ldapconn);
});
function ldap_escape($str)
{
// FIXME escape properly
return $str;
}
function ldap_get_user($username)
{
global $_ldapconn, $ldap_user_basedn;
$search_filter = sprintf("(&(uid=%s)(objectClass=posixAccount))", ldap_escape($username));
$search_result = ldap_search($_ldapconn, $ldap_user_basedn, $search_filter);
if ( ldap_count_entries($_ldapconn, $search_result) !== 1 )
return false;
return ldap_array_cleanup(ldap_get_attributes($_ldapconn, ldap_first_entry($_ldapconn, $search_result)));
}
function ldap_get_group($group)
{
global $_ldapconn, $ldap_group_basedn;
$search_filter = sprintf("(&(cn=%s)(objectClass=posixGroup))", ldap_escape($group));
$search_result = ldap_search($_ldapconn, $ldap_group_basedn, $search_filter);
if ( ldap_count_entries($_ldapconn, $search_result) !== 1 )
return false;
$result = ldap_array_cleanup(ldap_get_attributes($_ldapconn, ldap_first_entry($_ldapconn, $search_result)));
if ( !isset($result['memberUid']) )
$result['memberUid'] = array();
if ( !is_array($result['memberUid']) )
$result['memberUid'] = array($result['memberUid']);
return $result;
}
function ldap_update_user($user, $entry)
{
global $_ldapconn;
return ldap_modify($_ldapconn, ldap_make_user_dn($user), $entry);
}
function ldap_list_users()
{
global $_ldapconn, $ldap_user_basedn;
$search_result = ldap_search($_ldapconn, $ldap_user_basedn, '(objectClass=organizationalPerson)');
$results = array();
for ( $entry = ldap_first_entry($_ldapconn, $search_result);
$entry;
$entry = ldap_next_entry($_ldapconn, $entry) )
{
$entry_arr = ldap_array_cleanup(ldap_get_attributes($_ldapconn, $entry));
$results[$entry_arr['uid']] = $entry_arr;
}
return $results;
}
function ldap_list_groups()
{
global $_ldapconn, $ldap_group_basedn;
$search_result = ldap_search($_ldapconn, $ldap_group_basedn, '(objectClass=posixGroup)');
$results = array();
for ( $entry = ldap_first_entry($_ldapconn, $search_result);
$entry;
$entry = ldap_next_entry($_ldapconn, $entry) )
{
$entry_arr = ldap_array_cleanup(ldap_get_attributes($_ldapconn, $entry));
$results[$entry_arr['cn']] = $entry_arr;
}
return $results;
}
function ldap_array_cleanup($arr)
{
global $ldap_add_multiple;
$result = array();
foreach ( $arr as $k => $v )
{
if ( is_int($k) || $k == 'count' )
continue;
if ( $v['count'] === 1 && !in_array($k, $ldap_add_multiple) )
$v = $v[0];
else
unset($v['count']);
$result[$k] = $v;
}
return $result;
}
function ldap_make_user_dn($username)
{
global $ldap_user_basedn;
return sprintf('uid=%s,%s', ldap_escape($username), $ldap_user_basedn);
}
function ldap_make_group_dn($group)
{
global $ldap_group_basedn;
return sprintf('cn=%s,%s', ldap_escape($group), $ldap_group_basedn);
}
function ldap_replace_attr($dn, $attribute, $value)
{
global $_ldapconn;
$ldif = array(
$attribute => array($value)
);
return ldap_mod_replace($_ldapconn, $dn, $ldif);
}
function ldap_delete_user($username)
{
global $_ldapconn, $ldap_user_basedn, $ldap_group_basedn;
// remove user from all LDAP groups
$search_filter = sprintf("(&(memberUid=%s)(objectClass=posixGroup))", ldap_escape($username));
$search_result = ldap_search($_ldapconn, $ldap_group_basedn, $search_filter);
for ( $entry = ldap_first_entry($_ldapconn, $search_result);
$entry;
$entry = ldap_next_entry($_ldapconn, $entry) )
{
$entry_arr = ldap_array_cleanup(ldap_get_attributes($_ldapconn, $entry));
$dn = ldap_get_dn($_ldapconn, $entry);
ldap_mod_del($_ldapconn, $dn, array('memberUid' => array($username)));
}
// delete user DN
return ldap_delete($_ldapconn, ldap_make_user_dn($username));
}
function ldap_delete_group_member($gid, $uid)
{
global $_ldapconn;
return ldap_mod_del($_ldapconn, ldap_make_group_dn($gid), array('memberUid' => array($uid)));
}
function ldap_add_group_member($gid, $uid)
{
global $_ldapconn;
return ldap_mod_add($_ldapconn, ldap_make_group_dn($gid), array('memberUid' => array($uid)));
}
function get_next_available_uid()
{
$users = ldap_list_users();
$uids = array();
foreach ( $users as $u )
$uids[] = intval($u['uidNumber']);
asort($uids);
$uid = UID_MIN;
$last_uid = $uids[0];
foreach ( $uids as $u )
{
if ( $u > $last_uid + 1 && ($last_uid + 1) > UID_MIN )
{
return $last_uid + 1;
}
$last_uid = $u;
}
return max($uids) + 1;
}
function get_next_available_gid()
{
$groups = ldap_list_groups();
$gids = array();
foreach ( $groups as $g )
$gids[] = intval($g['gidNumber']);
asort($gids);
$gid = GID_MIN;
$last_gid = $gids[0];
foreach ( $gids as $g )
{
if ( $g > $last_gid + 1 && ($last_gid + 1) > GID_MIN )
{
return $last_gid + 1;
}
$last_gid = $g;
}
return max($gids) + 1;
}
function get_next_available_extension()
{
$users = ldap_list_users();
$exts = array();
foreach ( $users as $u )
{
if ( !isset($u['telephoneNumber']) )
continue;
if ( !is_array($u['telephoneNumber']) )
$u['telephoneNumber'] = array($u['telephoneNumber']);
foreach ( $u['telephoneNumber'] as $n )
{
if ( preg_match('/^([0-9]+) \(extension\)$/', $n, $match) )
$exts[] = intval($n);
}
}
asort($exts);
$ext = PHONE_EXT_MIN;
$last_ext = PHONE_EXT_MIN - 1;
foreach ( $exts as $e )
{
if ( $e > $last_ext + 1 && ($last_ext + 1) > UID_MIN )
{
return $last_ext + 1;
}
$last_ext = $e;
}
return count($exts) ? max($exts) + 1 : PHONE_EXT_MIN;
}
function ldap_create_user($username, $gn, $sn, $cn, $title)
{
global $_ldapconn;
$krb_realm = get_default_kerberos_realm();
if ( !ldap_add($_ldapconn, ldap_make_user_dn($username), array(
'cn' => array($cn)
, 'uid' => array($username)
, 'objectClass' => array(
'top'
, 'person'
, 'inetOrgPerson'
, 'organizationalPerson'
, 'posixAccount'
, 'ldapPublicKey'
)
, 'gn' => array($gn)
, 'sn' => array($sn)
, 'userPassword' => array("{SASL}$username@$krb_realm")
, 'loginShell' => array('/bin/bash')
, 'homeDirectory' => array("/home/users/$username")
, 'uidNumber' => array(get_next_available_uid())
, 'gidNumber' => array(500)
, 'title' => array($title)
)) )
return false;
if ( !ldap_mod_add($_ldapconn, ldap_make_group_dn('users'), array('memberUid' => array($username))) )
return false;
return true;
}
function ldap_create_group($cn, $description)
{
global $_ldapconn;
if ( !ldap_add($_ldapconn, ldap_make_group_dn($cn), array(
'cn' => array($cn)
, 'description' => array($description)
, 'gidNumber' => array(get_next_available_gid())
, 'objectClass' => array(
'top'
, 'posixGroup'
)
)) )
return false;
}
function ldap_delete_group($cn)
{
global $_ldapconn;
$group = ldap_get_group($cn);
$users = ldap_list_users();
foreach ( $users as $u )
{
if ( $u['gidNumber'] === $group['gidNumber'] )
return false;
}
return ldap_delete($_ldapconn, ldap_make_group_dn($cn));
}
/**
* Is the given username in the specified LDAP group?
* @param string username
* @param string Group name
* @return bool
*/
function ldap_test_group_membership($username, $group)
{
global $_ldapconn, $ldap_group_basedn;
$filter = sprintf('(&(memberUid=%s)(cn=%s)(objectClass=posixGroup))', ldap_escape($username), ldap_escape($group));
$result = ldap_search($_ldapconn, $ldap_group_basedn, $filter);
return ldap_count_entries($_ldapconn, $result) > 0;
}