PageRenderTime 25ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/ldap-change-password/ChangePasswordLdapDriver.php

https://gitlab.com/wuhang2003/rainloop-webmail
PHP | 230 lines | 144 code | 29 blank | 57 comment | 12 complexity | 6be74c1e432a78f890ce6b49403ab8aa MD5 | raw file
  1. <?php
  2. class ChangePasswordLdapDriver implements \RainLoop\Providers\ChangePassword\ChangePasswordInterface
  3. {
  4. /**
  5. * @var string
  6. */
  7. private $sHostName = '127.0.0.1';
  8. /**
  9. * @var int
  10. */
  11. private $iHostPort = 389;
  12. /**
  13. * @var string
  14. */
  15. private $sUserDnFormat = '';
  16. /**
  17. * @var string
  18. */
  19. private $sPasswordField = 'userPassword';
  20. /**
  21. * @var string
  22. */
  23. private $sPasswordEncType = 'SHA';
  24. /**
  25. * @var \MailSo\Log\Logger
  26. */
  27. private $oLogger = null;
  28. /**
  29. * @var string
  30. */
  31. private $sAllowedEmails = '';
  32. /**
  33. * @param string $sHostName
  34. * @param int $iHostPort
  35. * @param string $sUserDnFormat
  36. * @param string $sPasswordField
  37. * @param string $sPasswordEncType
  38. *
  39. * @return \ChangePasswordLdapDriver
  40. */
  41. public function SetConfig($sHostName, $iHostPort, $sUserDnFormat, $sPasswordField, $sPasswordEncType)
  42. {
  43. $this->sHostName = $sHostName;
  44. $this->iHostPort = $iHostPort;
  45. $this->sUserDnFormat = $sUserDnFormat;
  46. $this->sPasswordField = $sPasswordField;
  47. $this->sPasswordEncType = $sPasswordEncType;
  48. return $this;
  49. }
  50. /**
  51. * @param string $sAllowedEmails
  52. *
  53. * @return \ChangePasswordLdapDriver
  54. */
  55. public function SetAllowedEmails($sAllowedEmails)
  56. {
  57. $this->sAllowedEmails = $sAllowedEmails;
  58. return $this;
  59. }
  60. /**
  61. * @param \MailSo\Log\Logger $oLogger
  62. *
  63. * @return \ChangePasswordLdapDriver
  64. */
  65. public function SetLogger($oLogger)
  66. {
  67. if ($oLogger instanceof \MailSo\Log\Logger)
  68. {
  69. $this->oLogger = $oLogger;
  70. }
  71. return $this;
  72. }
  73. /**
  74. * @param \RainLoop\Account $oAccount
  75. *
  76. * @return bool
  77. */
  78. public function PasswordChangePossibility($oAccount)
  79. {
  80. return $oAccount && $oAccount->Email() &&
  81. \RainLoop\Plugins\Helper::ValidateWildcardValues($oAccount->Email(), $this->sAllowedEmails);
  82. }
  83. /**
  84. * @param \RainLoop\Model\Account $oAccount
  85. * @param string $sPrevPassword
  86. * @param string $sNewPassword
  87. *
  88. * @return bool
  89. */
  90. public function ChangePassword(\RainLoop\Account $oAccount, $sPrevPassword, $sNewPassword)
  91. {
  92. $bResult = false;
  93. try
  94. {
  95. $sDomain = \MailSo\Base\Utils::GetDomainFromEmail($oAccount->Email());
  96. $sUserDn = \strtr($this->sUserDnFormat, array(
  97. '{domain}' => $sDomain,
  98. '{domain:dc}' => 'dc='.\strtr($sDomain, array('.' => ',dc=')),
  99. '{email}' => $oAccount->Email(),
  100. '{email:user}' => \MailSo\Base\Utils::GetAccountNameFromEmail($oAccount->Email()),
  101. '{email:domain}' => $sDomain,
  102. '{login}' => $oAccount->Login(),
  103. '{imap:login}' => $oAccount->Login(),
  104. '{imap:host}' => $oAccount->DomainIncHost(),
  105. '{imap:port}' => $oAccount->DomainIncPort()
  106. ));
  107. $oCon = @\ldap_connect($this->sHostName, $this->iHostPort);
  108. if ($oCon)
  109. {
  110. @\ldap_set_option($oCon, LDAP_OPT_PROTOCOL_VERSION, 3);
  111. if (!@\ldap_bind($oCon, $sUserDn, $sPrevPassword))
  112. {
  113. if ($this->oLogger)
  114. {
  115. $sError = $oCon ? @\ldap_error($oCon) : '';
  116. $iErrno = $oCon ? @\ldap_errno($oCon) : 0;
  117. $this->oLogger->Write('ldap_bind error: '.$sError.' ('.$iErrno.')',
  118. \MailSo\Log\Enumerations\Type::WARNING, 'LDAP');
  119. }
  120. return false;
  121. }
  122. }
  123. else
  124. {
  125. return false;
  126. }
  127. $sSshaSalt = '';
  128. $sShaPrefix = '{SHA}';
  129. $sEncodedNewPassword = $sNewPassword;
  130. switch (\strtolower($this->sPasswordEncType))
  131. {
  132. case 'ssha':
  133. $sSshaSalt = $this->getSalt(4);
  134. $sShaPrefix = '{SSHA}';
  135. case 'sha':
  136. switch (true)
  137. {
  138. default:
  139. case \function_exists('sha1'):
  140. $sEncodedNewPassword = $sShaPrefix.\base64_encode(\sha1($sNewPassword.$sSshaSalt, true).$sSshaSalt);
  141. break;
  142. case \function_exists('hash'):
  143. $sEncodedNewPassword = $sShaPrefix.\base64_encode(\hash('sha1', $sNewPassword, true).$sSshaSalt);
  144. break;
  145. case \function_exists('mhash') && defined('MHASH_SHA1'):
  146. $sEncodedNewPassword = $sShaPrefix.\base64_encode(\mhash(MHASH_SHA1, $sNewPassword).$sSshaSalt);
  147. break;
  148. }
  149. break;
  150. case 'md5':
  151. $sEncodedNewPassword = '{MD5}'.\base64_encode(\pack('H*', \md5($sNewPassword)));
  152. break;
  153. case 'crypt':
  154. $sEncodedNewPassword = '{CRYPT}'.\crypt($sNewPassword, $this->getSalt(2));
  155. break;
  156. }
  157. $aEntry = array();
  158. $aEntry[$this->sPasswordField] = (string) $sEncodedNewPassword;
  159. if (!!@\ldap_modify($oCon, $sUserDn, $aEntry))
  160. {
  161. $bResult = true;
  162. }
  163. else
  164. {
  165. if ($this->oLogger)
  166. {
  167. $sError = $oCon ? @\ldap_error($oCon) : '';
  168. $iErrno = $oCon ? @\ldap_errno($oCon) : 0;
  169. $this->oLogger->Write('ldap_modify error: '.$sError.' ('.$iErrno.')',
  170. \MailSo\Log\Enumerations\Type::WARNING, 'LDAP');
  171. }
  172. }
  173. }
  174. catch (\Exception $oException)
  175. {
  176. if ($this->oLogger)
  177. {
  178. $this->oLogger->WriteException($oException,
  179. \MailSo\Log\Enumerations\Type::WARNING, 'LDAP');
  180. }
  181. $bResult = false;
  182. }
  183. return $bResult;
  184. }
  185. /**
  186. * @param int $iLength
  187. *
  188. * @return string
  189. */
  190. private function getSalt($iLength)
  191. {
  192. $sChars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  193. $iCharsLength = \strlen($sChars);
  194. $sResult = '';
  195. while (\strlen($sResult) < $iLength)
  196. {
  197. $sResult .= \substr($sChars, \rand() % $iCharsLength, 1);
  198. }
  199. return $sResult;
  200. }
  201. }