<?php
+# Make Shout methods available
+require_once SHOUT_BASE . '/lib/Shout.php';
+
// {{{ Shout_Driver_ldap class
class Shout_Driver_ldap extends Shout_Driver
{
+ var $_ldapKey; // Index used for storing objects
+ var $_appKey; // Index used for moving info to/from the app
// {{{ Class local variables
/**
{
parent::Shout_Driver($params);
$this->_connect();
+
+ /* These next lines will translate between indexes used in the
+ * application and LDAP. The rationale is that translation here will
+ * help make Shout more driver-independant. The keys used to contruct
+ * user arrays should be more appropriate to human-legibility (name
+ * instead of 'cn' and email instead of 'mail'). This translation is
+ * only needed because LDAP indexes users based on an arbitrary
+ * attribute and the application indexes by extension/context. In my
+ * environment users are indexed by their 'mail' attribute and others
+ * may index based on 'cn' or 'uid'. Any time a new $prefs['uid'] needs
+ * to be supported, this function should be checked and possibly
+ * modified to handle that translation.
+ */
+ switch($this->_params['uid']) {
+ case 'cn':
+ $this->_ldapKey = 'cn';
+ $this->_appKey = 'name';
+ break;
+ case 'mail':
+ $this->_ldapKey = 'mail';
+ $this->_appKey = 'email';
+ break;
+ case 'uid':
+ # There is no value that maps uid to LDAP so we can choose to use
+ # either extension or name, or anything really. I want to
+ # support it since it's a very common DN attribute.
+ # Since it's entirely administrator's preference, I'll
+ # set it to name for now
+ $this->_ldapKey = 'uid';
+ $this->_appKey = 'name';
+ break;
+ case 'voiceMailbox':
+ $this->_ldapKey = 'voiceMailbox';
+ $this->_appKey = 'extension';
+ break;
+ }
}
// }}}
# Collect all the possible contexts from the backend
- $res = ldap_search($this->_LDAP,
+ $res = @ldap_search($this->_LDAP,
SHOUT_ASTERISK_BRANCH.','.$this->_params['basedn'],
"(&(objectClass=asteriskObject)$searchfilter)",
array('context'));
break;
}
- $res = ldap_search($this->_LDAP,
+ $res = @ldap_search($this->_LDAP,
SHOUT_ASTERISK_BRANCH.','.$this->_params['basedn'],
"(&(objectClass=asteriskObject)$searchfilter(context=$context))",
array("context"));
}
// }}}
- // {{{ _getUsers method
+ // {{{ getUsers method
/**
* Get a list of users valid for the contexts
*
if (isset($entries[$context])) {
return $entries[$context];
}
- $search = ldap_search($this->_LDAP,
+
+ $search = @ldap_search($this->_LDAP,
SHOUT_USERS_BRANCH.','.$this->_params['basedn'],
'(&(objectClass='.SHOUT_USER_OBJECTCLASS.')(context='.$context.'))',
array('voiceMailbox', 'asteriskUserDialOptions',
'cn', 'telephoneNumber',
'asteriskUserDialTimeout', 'mail', 'asteriskPager'));
if (!$search) {
- return PEAR::raiseError("Unable to search directory");
+ return PEAR::raiseError("Unable to search directory: " .
+ ldap_error($this->_LDAP));
}
$res = ldap_get_entries($this->_LDAP, $search);
$entries[$context] = array();
*/
function getHomeContext()
{
- $res = ldap_search($this->_LDAP,
+ $res = @ldap_search($this->_LDAP,
SHOUT_USERS_BRANCH.','.$this->_params['basedn'],
"(&(mail=".Auth::getAuth().")(objectClass=asteriskUser))",
array('context'));
function getContextProperties($context)
{
- $res = ldap_search($this->_LDAP,
+ $res = @ldap_search($this->_LDAP,
SHOUT_ASTERISK_BRANCH.','.$this->_params['basedn'],
"(&(objectClass=asteriskObject)(context=$context))",
array('objectClass'));
}
// }}}
- // {{{ _getDialplan method
+ // {{{ getDialplan method
/**
* Get a context's dialplan and return as a multi-dimensional associative
* array
return $dialplans[$context];
}
- $res = ldap_search($this->_LDAP,
+ $res = @ldap_search($this->_LDAP,
SHOUT_ASTERISK_BRANCH.','.$this->_params['basedn'],
"(&(objectClass=asteriskExtensions)(context=$context))",
array('asteriskExtensionLine', 'asteriskIncludeLine',
*/
function saveUser($context, $extension, $userdetails)
{
+ # FIXME: Add test to make sure we aren't duplicating the extension
- $dn = $this->_params['uid'];
- switch ($this->_params['uid']) {
- case 'mail':
- $uid = 'email';
- break;
- case 'cn':
- $uid = 'name';
- break;
- case 'voiceMailbox':
- return PEAR::raiseError("Unsupported user key/DN");
- }
-
+ # FIXME Access Control/Authorization
+ $ldapKey = &$this->_ldapKey;
+ $appKey = &$this->_appKey;
- # FIXME Access Control/Authorization
$entry = array(
'cn' => $userdetails['name'],
'mail' => $userdetails['email'],
'context' => $context,
'asteriskUserDialOptions' => $userdetails['dialopts'],
);
- if (!empty($userdetails['telephonenumbers'])) {
+
+ if (!empty ($userdetails['telephonenumbers'])) {
$entry['telephoneNumber'] = $userdetails['telephonenumbers'];
}
$validusers = &$this->getUsers($context);
if (!isset($validusers[$extension])) {
- # FIXME: What if just the extension changed?
-
- # We must be adding a new user.
- $dn .= '='.$userdetails[$uid].',';
- $dn .= SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
-
- $entry['objectClass'] = array(
- 'top',
- 'person',
- 'organizationalPerson',
- 'inetOrgPerson',
- 'hordePerson',
- 'asteriskUser',
- 'asteriskVoiceMailbox'
- );
-
- # Check to see if the maximum number of users for this context
- # has been reached
- $limits = $this->getLimits($context);
- if (is_a($limits, "PEAR_Error")) {
- return $limits;
- }
- if (count($validusers) >= $limits['asteriskusers']) {
- print count($validusers).$limits['asteriskusers'];
- return PEAR::raiseError('Maximum number of users reached.');
- }
+ # Test to see if we're modifying an existing user that has
+ # no telephone system objectClasses and update that object/user
+ $rdn = "$ldapKey=".$userdetails[$appKey].',';
+ $branch = SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
- $res = ldap_add($this->_LDAP, $dn, $entry);
- if (!$res) {
- print $dn;
- print_r($entry);
- return PEAR::raiseError('LDAP Add failed: ' .
- ldap_error($this->_LDAP));
- }
-
- return true;
- } else {
- $key = $this->_params['uid'];
- if ($validusers[$extension][$uid] != $entry[$key]) {
- print "need rename\n";
- $oldrdn = $key.'='.$validusers[$extension][$uid];
- $oldparent = SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
- $newrdn = $key.'='.$entry[$key];
- $res = ldap_rename($this->_LDAP, "$oldrdn,$oldparent",
- $newrdn, $oldparent, true);
+ # This test is something of a hack. I want a cheap way to check
+ # for the existance of an object. I don't want to do a full search
+ # so instead I compare that the dn equals the dn. If the object
+ # exists then it'll return true. If the object doesn't exist,
+ # it'll return error. If it ever returns false something wierd
+ # is going on.
+ $res = @ldap_compare($this->_LDAP, $rdn.$branch,
+ $ldapKey, $userdetails[$appKey]);
+ if ($res === false) {
+ # We should never get here: a DN should ALWAYS match itself
+ return PEAR::raiseError("Internal Error: " . __FILE__ . " at " .
+ __LINE__);
+ } elseif ($res === true) {
+ # The object/user exists but doesn't have the Asterisk
+ # objectClasses
+ $extension = $userdetails['newextension'];
+
+ # $tmp is the minimal information required to establish
+ # an account in LDAP as required by the objectClasses.
+ # The entry will be fully populated below.
+ $tmp = array();
+ $tmp['objectClass'] = array(
+ 'asteriskUser',
+ 'asteriskVoiceMailbox'
+ );
+ $tmp['voiceMailbox'] = $extension;
+ $tmp['context'] = $context;
+ $res = @ldap_mod_add($this->_LDAP, $rdn.$branch, $tmp);
if (!$res) {
- print $oldrdn;
- print $newrdn;
- print_r($entry);
- return PEAR::raiseError('LDAP Rename failed: ' .
+ return PEAR::raiseError("Unable to modify the user: " .
ldap_error($this->_LDAP));
}
+
+ # Populate the $validusers array to make the edit go smoothly
+ # below
+ $validusers[$extension] = array();
+ $validusers[$extension][$appKey] = $userdetails[$appKey];
+
+ # The remainder of the work is done at the outside of the
+ # parent if() like a normal edit.
+
+ } elseif ($res === -1) {
+ # We must be adding a new user.
+ $entry['objectClass'] = array(
+ 'top',
+ 'person',
+ 'organizationalPerson',
+ 'inetOrgPerson',
+ 'hordePerson',
+ 'asteriskUser',
+ 'asteriskVoiceMailbox'
+ );
+
+ # Check to see if the maximum number of users for this context
+ # has been reached
+ $limits = $this->getLimits($context);
+ if (is_a($limits, "PEAR_Error")) {
+ return $limits;
+ }
+ if (count($validusers) >= $limits['asteriskusers']) {
+ print count($validusers).$limits['asteriskusers'];
+ return PEAR::raiseError('Maximum number of users reached.');
+ }
+
+ $res = @ldap_add($this->_LDAP, $rdn.$branch, $entry);
+ if (!$res) {
+ return PEAR::raiseError('LDAP Add failed: ' .
+ ldap_error($this->_LDAP));
+ }
+
+ return true;
}
- $dn = $key.'='.$entry[$key];
- $dn .= ','.SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
- $res = ldap_modify($this->_LDAP, $dn, $entry);
- print_r($entry);
+ }
+
+ # Anything after this point is an edit.
+
+ # Check to see if the object needs to be renamed (DN changed)
+ if ($validusers[$extension][$appKey] != $entry[$ldapKey]) {
+ $oldrdn = $ldapKey.'='.$validusers[$extension][$appKey];
+ $oldparent = SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
+ $newrdn = $ldapKey.'='.$entry[$ldapKey];
+ $res = @ldap_rename($this->_LDAP, "$oldrdn,$oldparent",
+ $newrdn, $oldparent, true);
if (!$res) {
- print $dn;
- print_r($entry);
- return PEAR::raiseError('LDAP Modify failed: ' .
+ return PEAR::raiseError('LDAP Rename failed: ' .
ldap_error($this->_LDAP));
}
- return true;
}
+
+ # Update the object/user
+ $dn = $ldapKey.'='.$entry[$ldapKey];
+ $dn .= ','.SHOUT_USERS_BRANCH.','.$this->_params['basedn'];
+ $res = @ldap_modify($this->_LDAP, $dn, $entry);
+ if (!$res) {
+ return PEAR::raiseError('LDAP Modify failed: ' .
+ ldap_error($this->_LDAP));
+ }
+
+ # We must have been successful
+ return true;
}
-
- // {{{ _connect method
+ // }}}
+
+ // {{{ deleteUser method
+ /**
+ * Deletes a user from the LDAP tree
+ *
+ * @param string $context Context to delete the user from
+ * @param string $extension Extension of the user to be deleted
+ *
+ * @return boolean True on success, PEAR::Error object on error
+ */
+ function deleteUser($context, $extension)
+ {
+ $ldapKey = &$this->_ldapKey;
+ $appKey = &$this->_appKey;
+
+ if (!Shout::checkRights("shout:contexts:$context:users",
+ PERMS_DELETE, 1)) {
+ return PEAR::raiseError("No permission to delete users in this " .
+ "context.");
+ }
+
+ $validusers = $this->getUsers($context);
+ if (!isset($validusers[$extension])) {
+ return PEAR::raiseError("That extension does not exist.");
+ }
+
+ $dn = "$ldapKey=".$validusers[$extension][$appKey];
+ $dn .= ',' . SHOUT_USERS_BRANCH . ',' . $this->_params['basedn'];
+
+ $res = @ldap_delete($this->_LDAP, $dn);
+ if (!$res) {
+ return PEAR::raiseError("Unable to delete $extension from " .
+ "$context: " . ldap_error($this->_LDAP));
+ }
+ return true;
+ }
+ // }}}
+
+ // {{{ connect method
/**
* Attempts to open a connection to the LDAP server.
*
<item url="templates/" uploadstatus="2" />
<item url="lib/" uploadstatus="2" />
<item url="lib/Driver/" uploadstatus="2" />
- <item modified_time="1122529043" url="lib/Driver/ldap.php" uploadstatus="2" />
+ <item modified_time="1122701473" url="lib/Driver/ldap.php" uploadstatus="2" />
<item modified_time="1120589135" url="lib/base.php" uploadstatus="2" />
<item modified_time="1121306551" url="lib/Driver.php" uploadstatus="2" />
<item modified_time="1121623574" url="index.php" uploadstatus="2" />
<uploadeditem upload_time="1121306551" url="lib/Driver.php" />
<uploadeditem upload_time="1120022560" url="lib/Driver.php~" />
<uploadeditem upload_time="0" url="lib/Driver/" />
- <uploadeditem upload_time="1122529043" url="lib/Driver/ldap.php" />
+ <uploadeditem upload_time="1122701473" url="lib/Driver/ldap.php" />
<uploadeditem upload_time="1120026921" url="lib/Driver/ldap.php~" />
<uploadeditem upload_time="1120288491" url="lib/SelectContext.php" />
- <uploadeditem upload_time="1121580048" url="lib/Shout.php" />
+ <uploadeditem upload_time="1122606970" url="lib/Shout.php" />
<uploadeditem upload_time="1121623619" url="lib/System.php" />
<uploadeditem upload_time="1122514535" url="lib/User.php" />
<uploadeditem upload_time="1120279975" url="lib/Users.php" />
<uploadeditem upload_time="1121580098" url="themes/graphics/add-extension.gif" />
<uploadeditem upload_time="1121300828" url="themes/graphics/add-user.gif" />
<uploadeditem upload_time="1121574328" url="themes/screen.css" />
- <uploadeditem upload_time="1121623747" url="users.php" />
+ <uploadeditem upload_time="1122593887" url="users.php" />
<uploadeditem upload_time="0" url="users/" />
- <uploadeditem upload_time="1121404120" url="users/add.php" />
+ <uploadeditem upload_time="1122593878" url="users/add.php" />
+ <uploadeditem upload_time="1122701749" url="users/delete.php" />
<uploadeditem upload_time="1121821098" url="users/edit.php" />
<uploadeditem upload_time="1121396278" url="users/index.php" />
<uploadeditem upload_time="1122514769" url="users/save.php" />
<defaultDTD>-//w3c//dtd xhtml 1.0 strict//en</defaultDTD>
<item modified_time="1120073766" url="config/conf.xml" uploadstatus="1" />
<item url="config/" uploadstatus="1" />
- <item modified_time="1121580048" url="lib/Shout.php" uploadstatus="1" />
+ <item modified_time="1122606970" url="lib/Shout.php" uploadstatus="1" />
<item modified_time="1120174958" url="templates/common-header.inc" uploadstatus="1" />
<item modified_time="1121623829" url="templates/menu.inc" uploadstatus="1" />
<item url="templates/context/" uploadstatus="1" />
<item modified_time="1120287842" url="main/moh.php" uploadstatus="1" />
<item modified_time="1120815615" url="main/system.php" uploadstatus="1" />
<item modified_time="1121623695" url="main/users.php" uploadstatus="1" />
- <item modified_time="1121623747" url="users.php" uploadstatus="1" />
+ <item modified_time="1122593887" url="users.php" uploadstatus="1" />
<item modified_time="1122514769" url="users/save.php" uploadstatus="1" />
<item modified_time="1121574328" url="themes/screen.css" uploadstatus="1" />
<item modified_time="1121821098" url="users/edit.php" uploadstatus="1" />
<item modified_time="1121621204" url="templates/dialplan/priority-form-begin.inc" uploadstatus="1" />
<item modified_time="1121621077" url="templates/dialplan/priority-form-end.inc" uploadstatus="1" />
<item modified_time="1121621149" url="templates/dialplan/priority-form-line.inc" uploadstatus="1" />
+ <item modified_time="1122593878" url="users/add.php" uploadstatus="1" />
+ <item modified_time="1122701749" url="users/delete.php" uploadstatus="1" />
<treestatus>
<openfolder url="config" />
<openfolder url="dialplan" />