Mercurial > hg > rc1
comparison plugins/password/drivers/ldap_simple.php @ 0:1e000243b222
vanilla 1.3.3 distro, I hope
| author | Charlie Root |
|---|---|
| date | Thu, 04 Jan 2018 15:50:29 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:1e000243b222 |
|---|---|
| 1 <?php | |
| 2 | |
| 3 /** | |
| 4 * Simple LDAP Password Driver | |
| 5 * | |
| 6 * Driver for passwords stored in LDAP | |
| 7 * This driver is based on Edouard's LDAP Password Driver, but does not | |
| 8 * require PEAR's Net_LDAP2 to be installed | |
| 9 * | |
| 10 * @version 2.0 | |
| 11 * @author Wout Decre <wout@canodus.be> | |
| 12 * @author Aleksander Machniak <machniak@kolabsys.com> | |
| 13 * | |
| 14 * Copyright (C) 2005-2014, The Roundcube Dev Team | |
| 15 * | |
| 16 * This program is free software: you can redistribute it and/or modify | |
| 17 * it under the terms of the GNU General Public License as published by | |
| 18 * the Free Software Foundation, either version 3 of the License, or | |
| 19 * (at your option) any later version. | |
| 20 * | |
| 21 * This program is distributed in the hope that it will be useful, | |
| 22 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 24 * GNU General Public License for more details. | |
| 25 * | |
| 26 * You should have received a copy of the GNU General Public License | |
| 27 * along with this program. If not, see http://www.gnu.org/licenses/. | |
| 28 */ | |
| 29 | |
| 30 class rcube_ldap_simple_password | |
| 31 { | |
| 32 private $debug = false; | |
| 33 | |
| 34 function save($curpass, $passwd) | |
| 35 { | |
| 36 $rcmail = rcmail::get_instance(); | |
| 37 | |
| 38 $this->debug = $rcmail->config->get('ldap_debug'); | |
| 39 | |
| 40 $ldap_host = $rcmail->config->get('password_ldap_host', 'localhost'); | |
| 41 $ldap_port = $rcmail->config->get('password_ldap_port', '389'); | |
| 42 | |
| 43 $this->_debug("C: Connect to $ldap_host:$ldap_port"); | |
| 44 | |
| 45 // Connect | |
| 46 if (!$ds = ldap_connect($ldap_host, $ldap_port)) { | |
| 47 $this->_debug("S: NOT OK"); | |
| 48 | |
| 49 rcube::raise_error(array( | |
| 50 'code' => 100, 'type' => 'ldap', | |
| 51 'file' => __FILE__, 'line' => __LINE__, | |
| 52 'message' => "Could not connect to LDAP server" | |
| 53 ), | |
| 54 true); | |
| 55 | |
| 56 return PASSWORD_CONNECT_ERROR; | |
| 57 } | |
| 58 | |
| 59 $this->_debug("S: OK"); | |
| 60 | |
| 61 // Set protocol version | |
| 62 ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, | |
| 63 $rcmail->config->get('password_ldap_version', '3')); | |
| 64 | |
| 65 // Start TLS | |
| 66 if ($rcmail->config->get('password_ldap_starttls')) { | |
| 67 if (!ldap_start_tls($ds)) { | |
| 68 ldap_unbind($ds); | |
| 69 return PASSWORD_CONNECT_ERROR; | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 // include 'ldap' driver, we share some static methods with it | |
| 74 require_once INSTALL_PATH . 'plugins/password/drivers/ldap.php'; | |
| 75 | |
| 76 // other plugins might want to modify user DN | |
| 77 $plugin = $rcmail->plugins->exec_hook('password_ldap_bind', array( | |
| 78 'user_dn' => '', 'conn' => $ds)); | |
| 79 | |
| 80 // Build user DN | |
| 81 if (!empty($plugin['user_dn'])) { | |
| 82 $user_dn = $plugin['user_dn']; | |
| 83 } | |
| 84 else if ($user_dn = $rcmail->config->get('password_ldap_userDN_mask')) { | |
| 85 $user_dn = rcube_ldap_password::substitute_vars($user_dn); | |
| 86 } | |
| 87 else { | |
| 88 $user_dn = $this->search_userdn($rcmail, $ds); | |
| 89 } | |
| 90 | |
| 91 if (empty($user_dn)) { | |
| 92 ldap_unbind($ds); | |
| 93 return PASSWORD_CONNECT_ERROR; | |
| 94 } | |
| 95 | |
| 96 // Connection method | |
| 97 switch ($rcmail->config->get('password_ldap_method')) { | |
| 98 case 'admin': | |
| 99 $binddn = $rcmail->config->get('password_ldap_adminDN'); | |
| 100 $bindpw = $rcmail->config->get('password_ldap_adminPW'); | |
| 101 break; | |
| 102 case 'user': | |
| 103 default: | |
| 104 $binddn = $user_dn; | |
| 105 $bindpw = $curpass; | |
| 106 break; | |
| 107 } | |
| 108 | |
| 109 $lchattr = $rcmail->config->get('password_ldap_lchattr'); | |
| 110 $pwattr = $rcmail->config->get('password_ldap_pwattr', 'userPassword'); | |
| 111 $smbpwattr = $rcmail->config->get('password_ldap_samba_pwattr'); | |
| 112 $smblchattr = $rcmail->config->get('password_ldap_samba_lchattr'); | |
| 113 $samba = $rcmail->config->get('password_ldap_samba'); | |
| 114 $pass_mode = $rcmail->config->get('password_ldap_encodage', 'crypt'); | |
| 115 $crypted_pass = password::hash_password($passwd, $pass_mode); | |
| 116 | |
| 117 // Support password_ldap_samba option for backward compat. | |
| 118 if ($samba && !$smbpwattr) { | |
| 119 $smbpwattr = 'sambaNTPassword'; | |
| 120 $smblchattr = 'sambaPwdLastSet'; | |
| 121 } | |
| 122 | |
| 123 // Crypt new password | |
| 124 if (!$crypted_pass) { | |
| 125 return PASSWORD_CRYPT_ERROR; | |
| 126 } | |
| 127 | |
| 128 // Crypt new Samba password | |
| 129 if ($smbpwattr && !($samba_pass = password::hash_password($passwd, 'samba'))) { | |
| 130 return PASSWORD_CRYPT_ERROR; | |
| 131 } | |
| 132 | |
| 133 $this->_debug("C: Bind $binddn, pass: **** [" . strlen($bindpw) . "]"); | |
| 134 | |
| 135 // Bind | |
| 136 if (!ldap_bind($ds, $binddn, $bindpw)) { | |
| 137 $this->_debug("S: ".ldap_error($ds)); | |
| 138 | |
| 139 ldap_unbind($ds); | |
| 140 | |
| 141 return PASSWORD_CONNECT_ERROR; | |
| 142 } | |
| 143 | |
| 144 $this->_debug("S: OK"); | |
| 145 | |
| 146 $entry[$pwattr] = $crypted_pass; | |
| 147 | |
| 148 // Update PasswordLastChange Attribute if desired | |
| 149 if ($lchattr) { | |
| 150 $entry[$lchattr] = (int)(time() / 86400); | |
| 151 } | |
| 152 | |
| 153 // Update Samba password | |
| 154 if ($smbpwattr) { | |
| 155 $entry[$smbpwattr] = $samba_pass; | |
| 156 } | |
| 157 | |
| 158 // Update Samba password last change | |
| 159 if ($smblchattr) { | |
| 160 $entry[$smblchattr] = time(); | |
| 161 } | |
| 162 | |
| 163 $this->_debug("C: Modify $user_dn: " . print_r($entry, true)); | |
| 164 | |
| 165 if (!ldap_modify($ds, $user_dn, $entry)) { | |
| 166 $this->_debug("S: ".ldap_error($ds)); | |
| 167 | |
| 168 $errno = ldap_errno($ds); | |
| 169 | |
| 170 ldap_unbind($ds); | |
| 171 | |
| 172 if ($errno == 0x13) { // LDAP_CONSTRAINT_VIOLATION | |
| 173 return PASSWORD_CONSTRAINT_VIOLATION; | |
| 174 } | |
| 175 | |
| 176 return PASSWORD_CONNECT_ERROR; | |
| 177 } | |
| 178 | |
| 179 $this->_debug("S: OK"); | |
| 180 | |
| 181 // All done, no error | |
| 182 ldap_unbind($ds); | |
| 183 | |
| 184 return PASSWORD_SUCCESS; | |
| 185 } | |
| 186 | |
| 187 /** | |
| 188 * Bind with searchDN and searchPW and search for the user's DN | |
| 189 * Use search_base and search_filter defined in config file | |
| 190 * Return the found DN | |
| 191 */ | |
| 192 function search_userdn($rcmail, $ds) | |
| 193 { | |
| 194 $search_user = $rcmail->config->get('password_ldap_searchDN'); | |
| 195 $search_pass = $rcmail->config->get('password_ldap_searchPW'); | |
| 196 $search_base = $rcmail->config->get('password_ldap_search_base'); | |
| 197 $search_filter = $rcmail->config->get('password_ldap_search_filter'); | |
| 198 | |
| 199 if (empty($search_filter)) { | |
| 200 return false; | |
| 201 } | |
| 202 | |
| 203 $this->_debug("C: Bind " . ($search_user ? $search_user : '[anonymous]')); | |
| 204 | |
| 205 // Bind | |
| 206 if (!ldap_bind($ds, $search_user, $search_pass)) { | |
| 207 $this->_debug("S: ".ldap_error($ds)); | |
| 208 return false; | |
| 209 } | |
| 210 | |
| 211 $this->_debug("S: OK"); | |
| 212 | |
| 213 $search_base = rcube_ldap_password::substitute_vars($search_base); | |
| 214 $search_filter = rcube_ldap_password::substitute_vars($search_filter); | |
| 215 | |
| 216 $this->_debug("C: Search $search_base for $search_filter"); | |
| 217 | |
| 218 // Search for the DN | |
| 219 if (!$sr = ldap_search($ds, $search_base, $search_filter)) { | |
| 220 $this->_debug("S: ".ldap_error($ds)); | |
| 221 return false; | |
| 222 } | |
| 223 | |
| 224 $found = ldap_count_entries($ds, $sr); | |
| 225 | |
| 226 $this->_debug("S: OK [found $found records]"); | |
| 227 | |
| 228 // If no or more entries were found, return false | |
| 229 if ($found != 1) { | |
| 230 return false; | |
| 231 } | |
| 232 | |
| 233 return ldap_get_dn($ds, ldap_first_entry($ds, $sr)); | |
| 234 } | |
| 235 | |
| 236 /** | |
| 237 * Prints debug info to the log | |
| 238 */ | |
| 239 private function _debug($str) | |
| 240 { | |
| 241 if ($this->debug) { | |
| 242 rcube::write_log('ldap', $str); | |
| 243 } | |
| 244 } | |
| 245 } |
