PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/ingo/lib/Driver/ldap.php

https://github.com/wrobel/horde-fw3
PHP | 268 lines | 178 code | 29 blank | 61 comment | 34 complexity | 42a53a3c3a3d66b5e2cfeb56624b211d MD5 | raw file
Possible License(s): LGPL-2.0, AGPL-1.0, LGPL-2.1, BSD-2-Clause
  1. <?php
  2. /**
  3. * Ingo_Driver_ldap:: Implements the Sieve_Driver api to allow scripts to be
  4. * installed and set active via an LDAP server.
  5. *
  6. * $Horde: ingo/lib/Driver/ldap.php,v 1.8.2.4 2007-12-20 14:05:47 jan Exp $
  7. *
  8. * See the enclosed file LICENSE for license information (ASL). If you
  9. * did not receive this file, see http://www.horde.org/licenses/asl.php.
  10. *
  11. * @author Jason M. Felice <jason.m.felice@gmail.com>
  12. * @since Ingo 1.1
  13. * @package Ingo
  14. */
  15. class Ingo_Driver_ldap extends Ingo_Driver {
  16. /**
  17. * Constructor.
  18. */
  19. function Ingo_Driver_ldap($params = array())
  20. {
  21. if (!Util::extensionExists('ldap')) {
  22. Horde::fatal(PEAR::raiseError(_("LDAP support is required but the LDAP module is not available or not loaded.")), __FILE__, __LINE__);
  23. }
  24. $default_params = array('hostspec' => 'localhost',
  25. 'port' => 389,
  26. 'script_attribute' => 'mailSieveRuleSource');
  27. $this->_params = array_merge($this->_params, $default_params, $params);
  28. }
  29. /**
  30. * Create a DN from a DN template.
  31. *
  32. * This is done by substituting the username for %u and the 'dc='
  33. * components for %d.
  34. *
  35. * @access private
  36. *
  37. * @param string $templ The DN template (from the config).
  38. *
  39. * @return string The resulting DN.
  40. */
  41. function _substUser($templ)
  42. {
  43. $domain = '';
  44. $username = $this->_params['username'];
  45. if (strpos($username, '@') !== false) {
  46. list($username, $domain) = explode('@', $username);
  47. }
  48. $domain = implode(', dc=', explode('.', $domain));
  49. if (!empty($domain)) {
  50. $domain = 'dc=' . $domain;
  51. }
  52. if (preg_match('/^\s|\s$|\s\s|[,+="\r\n<>#;]/', $username)) {
  53. $username = '"' . str_replace('"', '\\"', $username) . '"';
  54. }
  55. return str_replace(array('%u', '%d'),
  56. array($username, $domain),
  57. $templ);
  58. }
  59. /**
  60. * Connect and bind to ldap server.
  61. */
  62. function _connect()
  63. {
  64. if (!($ldapcn = @ldap_connect($this->_params['hostspec'],
  65. $this->_params['port']))) {
  66. return PEAR::raiseError(_("Connection failure"));
  67. }
  68. /* Set the LDAP protocol version. */
  69. if (!empty($this->_params['version'])) {
  70. @ldap_set_option($ldapcn,
  71. LDAP_OPT_PROTOCOL_VERSION,
  72. $this->_params['version']);
  73. }
  74. /* Start TLS if we're using it. */
  75. if (!empty($this->_params['tls'])) {
  76. if (!@ldap_start_tls($ldapcn)) {
  77. return PEAR::raiseError(sprintf(_("STARTTLS failed: (%s) %s"),
  78. ldap_errno($ldapcn),
  79. ldap_error($ldapcn)));
  80. }
  81. }
  82. /* Bind to the server. */
  83. if (isset($this->_params['bind_dn'])) {
  84. $bind_dn = $this->_substUser($this->_params['bind_dn']);
  85. if (is_a($bind_dn, 'PEAR_Error')) {
  86. return $bind_dn;
  87. }
  88. if (isset($this->_params['bind_password'])) {
  89. $password = $this->_params['bind_password'];
  90. } else {
  91. $password = $this->_params['password'];
  92. }
  93. if (!@ldap_bind($ldapcn, $bind_dn, $password)) {
  94. return PEAR::raiseError(sprintf(_("Bind failed: (%s) %s"),
  95. ldap_errno($ldapcn),
  96. ldap_error($ldapcn)));
  97. }
  98. } elseif (!(@ldap_bind($ldapcn))) {
  99. return PEAR::raiseError(sprintf(_("Bind failed: (%s) %s"),
  100. ldap_errno($ldapcn),
  101. ldap_error($ldapcn)));
  102. }
  103. return $ldapcn;
  104. }
  105. /**
  106. * Retrieve current user's scripts.
  107. *
  108. * @access private
  109. *
  110. * @param resource $ldapcn The connection to the LDAP server.
  111. * @param string $userDN Set to the user object's real DN.
  112. *
  113. * @return mixed Array of script sources, or PEAR_Error on failure.
  114. */
  115. function _getScripts($ldapcn, &$userDN)
  116. {
  117. $attrs = array($this->_params['script_attribute'], 'dn');
  118. $filter = $this->_substUser($this->_params['script_filter']);
  119. /* Find the user object. */
  120. $sr = @ldap_search($ldapcn, $this->_params['script_base'], $filter,
  121. $attrs);
  122. if ($sr === false) {
  123. return PEAR::raiseError(sprintf(_("Error retrieving current script: (%d) %s"),
  124. ldap_errno($ldapcn),
  125. ldap_error($ldapcn)));
  126. }
  127. if (@ldap_count_entries($ldapcn, $sr) != 1) {
  128. return PEAR::raiseError(sprintf(_("Expected 1 object, got %d."),
  129. ldap_count_entries($ldapcn, $sr)));
  130. }
  131. $ent = @ldap_first_entry($ldapcn, $sr);
  132. if ($ent === false) {
  133. return PEAR::raiseError(sprintf(_("Error retrieving current script: (%d) %s"),
  134. ldap_errno($ldapcn),
  135. ldap_error($ldapcn)));
  136. }
  137. /* Retrieve the user's DN. */
  138. $v = @ldap_get_dn($ldapcn, $ent);
  139. if ($v === false) {
  140. @ldap_free_result($sr);
  141. return PEAR::raiseError(sprintf(_("Error retrieving current script: (%d) %s"),
  142. ldap_errno($ldapcn),
  143. ldap_error($ldapcn)));
  144. }
  145. $userDN = $v;
  146. /* Retrieve the user's scripts. */
  147. $attrs = @ldap_get_attributes($ldapcn, $ent);
  148. @ldap_free_result($sr);
  149. if ($attrs === false) {
  150. return PEAR::raiseError(sprintf(_("Error retrieving current script: (%d) %s"),
  151. ldap_errno($ldapcn),
  152. ldap_error($ldapcn)));
  153. }
  154. /* Attribute can be in any case, and can have a ";binary"
  155. * specifier. */
  156. $regexp = '/^' . preg_quote($this->_params['script_attribute'], '/') .
  157. '(?:;.*)?$/i';
  158. unset($attrs['count']);
  159. foreach ($attrs as $name => $values) {
  160. if (preg_match($regexp, $name)) {
  161. unset($values['count']);
  162. return array_values($values);
  163. }
  164. }
  165. return array();
  166. }
  167. /**
  168. * Sets a script running on the backend.
  169. *
  170. * @param string $script The sieve script.
  171. *
  172. * @return mixed True on success, PEAR_Error on error.
  173. */
  174. function setScriptActive($script)
  175. {
  176. $ldapcn = $this->_connect();
  177. if (is_a($ldapcn, 'PEAR_Error')) {
  178. return $ldapcn;
  179. }
  180. $values = $this->_getScripts($ldapcn, $userDN);
  181. if (is_a($values, 'PEAR_Error')) {
  182. return $values;
  183. }
  184. $found = false;
  185. foreach ($values as $i => $value) {
  186. if (strpos($value, "# Sieve Filter\n") !== false) {
  187. if (empty($script)) {
  188. unset($values[$i]);
  189. } else {
  190. $values[$i] = $script;
  191. }
  192. $found = true;
  193. break;
  194. }
  195. }
  196. if (!$found && !empty($script)) {
  197. $values[] = $script;
  198. }
  199. $replace = array(String::lower($this->_params['script_attribute']) => $values);
  200. if (empty($values)) {
  201. $r = @ldap_mod_del($ldapcn, $userDN, $replace);
  202. } else {
  203. $r = @ldap_mod_replace($ldapcn, $userDN, $replace);
  204. }
  205. if (!$r) {
  206. return PEAR::raiseError(sprintf(_("Activating the script for \"%s\" failed: (%d) %s"),
  207. $userDN,
  208. ldap_errno($ldapcn),
  209. ldap_error($ldapcn)));
  210. }
  211. @ldap_close($ldapcn);
  212. return true;
  213. }
  214. /**
  215. * Returns the content of the currently active script.
  216. *
  217. * @return string The complete ruleset of the specified user.
  218. */
  219. function getScript()
  220. {
  221. $ldapcn = $this->_connect();
  222. if (is_a($ldapcn, 'PEAR_Error')) {
  223. return $ldapcn;
  224. }
  225. $values = $this->_getScripts($ldapcn, $userDN);
  226. if (is_a($values, 'PEAR_Error')) {
  227. return $values;
  228. }
  229. $script = '';
  230. foreach ($values as $value) {
  231. if (strpos($value, "# Sieve Filter\n") !== false) {
  232. $script = $value;
  233. break;
  234. }
  235. }
  236. @ldap_close($ldapcn);
  237. return $script;
  238. }
  239. }