commit | author | age
|
48e9c1
|
1 |
<?php |
T |
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 |
*/ |
|
13 |
|
|
14 |
class rcube_ldap_simple_password |
|
15 |
{ |
99de1f
|
16 |
private $debug = false; |
AM |
17 |
|
48e9c1
|
18 |
function save($curpass, $passwd) |
T |
19 |
{ |
d6938b
|
20 |
$rcmail = rcmail::get_instance(); |
48e9c1
|
21 |
|
99de1f
|
22 |
$this->debug = $rcmail->config->get('ldap_debug'); |
AM |
23 |
|
|
24 |
$ldap_host = $rcmail->config->get('password_ldap_host'); |
|
25 |
$ldap_port = $rcmail->config->get('password_ldap_port'); |
|
26 |
|
|
27 |
$this->_debug("C: Connect to $ldap_host:$ldap_port"); |
|
28 |
|
d6938b
|
29 |
// Connect |
99de1f
|
30 |
if (!$ds = ldap_connect($ldap_host, $ldap_port)) { |
AM |
31 |
$this->_debug("S: NOT OK"); |
|
32 |
|
|
33 |
rcube::raise_error(array( |
|
34 |
'code' => 100, 'type' => 'ldap', |
|
35 |
'file' => __FILE__, 'line' => __LINE__, |
|
36 |
'message' => "Could not connect to LDAP server" |
|
37 |
), |
|
38 |
true); |
|
39 |
|
d6938b
|
40 |
return PASSWORD_CONNECT_ERROR; |
AM |
41 |
} |
48e9c1
|
42 |
|
99de1f
|
43 |
$this->_debug("S: OK"); |
AM |
44 |
|
d6938b
|
45 |
// Set protocol version |
99de1f
|
46 |
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $rcmail->config->get('password_ldap_version')); |
48e9c1
|
47 |
|
d6938b
|
48 |
// Start TLS |
AM |
49 |
if ($rcmail->config->get('password_ldap_starttls')) { |
|
50 |
if (!ldap_start_tls($ds)) { |
|
51 |
ldap_unbind($ds); |
|
52 |
return PASSWORD_CONNECT_ERROR; |
|
53 |
} |
|
54 |
} |
48e9c1
|
55 |
|
19884e
|
56 |
// include 'ldap' driver, we share some static methods with it |
AM |
57 |
require_once INSTALL_PATH . 'plugins/password/drivers/ldap.php'; |
|
58 |
|
99de1f
|
59 |
// other plugins might want to modify user DN |
AM |
60 |
$plugin = $rcmail->plugins->exec_hook('password_ldap_bind', array( |
|
61 |
'user_dn' => '', 'conn' => $ds)); |
|
62 |
|
d6938b
|
63 |
// Build user DN |
99de1f
|
64 |
if (!empty($plugin['user_dn'])) { |
AM |
65 |
$user_dn = $plugin['user_dn']; |
|
66 |
} |
|
67 |
else if ($user_dn = $rcmail->config->get('password_ldap_userDN_mask')) { |
19884e
|
68 |
$user_dn = rcube_ldap_password::substitute_vars($user_dn); |
d6938b
|
69 |
} |
AM |
70 |
else { |
|
71 |
$user_dn = $this->search_userdn($rcmail, $ds); |
|
72 |
} |
48e9c1
|
73 |
|
d6938b
|
74 |
if (empty($user_dn)) { |
AM |
75 |
ldap_unbind($ds); |
|
76 |
return PASSWORD_CONNECT_ERROR; |
|
77 |
} |
48e9c1
|
78 |
|
d6938b
|
79 |
// Connection method |
AM |
80 |
switch ($rcmail->config->get('password_ldap_method')) { |
|
81 |
case 'admin': |
|
82 |
$binddn = $rcmail->config->get('password_ldap_adminDN'); |
|
83 |
$bindpw = $rcmail->config->get('password_ldap_adminPW'); |
|
84 |
break; |
|
85 |
case 'user': |
|
86 |
default: |
|
87 |
$binddn = $user_dn; |
|
88 |
$bindpw = $curpass; |
|
89 |
break; |
|
90 |
} |
48e9c1
|
91 |
|
d6938b
|
92 |
$lchattr = $rcmail->config->get('password_ldap_lchattr'); |
AM |
93 |
$pwattr = $rcmail->config->get('password_ldap_pwattr'); |
48e9c1
|
94 |
$smbpwattr = $rcmail->config->get('password_ldap_samba_pwattr'); |
T |
95 |
$smblchattr = $rcmail->config->get('password_ldap_samba_lchattr'); |
|
96 |
$samba = $rcmail->config->get('password_ldap_samba'); |
19884e
|
97 |
$pass_mode = $rcmail->config->get('password_ldap_encodage'); |
AM |
98 |
$crypted_pass = rcube_ldap_password::hash_password($passwd, $pass_mode); |
48e9c1
|
99 |
|
T |
100 |
// Support password_ldap_samba option for backward compat. |
|
101 |
if ($samba && !$smbpwattr) { |
|
102 |
$smbpwattr = 'sambaNTPassword'; |
|
103 |
$smblchattr = 'sambaPwdLastSet'; |
|
104 |
} |
|
105 |
|
d6938b
|
106 |
// Crypt new password |
AM |
107 |
if (!$crypted_pass) { |
|
108 |
return PASSWORD_CRYPT_ERROR; |
|
109 |
} |
48e9c1
|
110 |
|
T |
111 |
// Crypt new Samba password |
19884e
|
112 |
if ($smbpwattr && !($samba_pass = rcube_ldap_password::hash_password($passwd, 'samba'))) { |
d6938b
|
113 |
return PASSWORD_CRYPT_ERROR; |
48e9c1
|
114 |
} |
T |
115 |
|
0d9ccf
|
116 |
$this->_debug("C: Bind $binddn, pass: **** [" . strlen($bindpw) . "]"); |
99de1f
|
117 |
|
d6938b
|
118 |
// Bind |
AM |
119 |
if (!ldap_bind($ds, $binddn, $bindpw)) { |
99de1f
|
120 |
$this->_debug("S: ".ldap_error($ds)); |
AM |
121 |
|
d6938b
|
122 |
ldap_unbind($ds); |
99de1f
|
123 |
|
d6938b
|
124 |
return PASSWORD_CONNECT_ERROR; |
AM |
125 |
} |
48e9c1
|
126 |
|
99de1f
|
127 |
$this->_debug("S: OK"); |
AM |
128 |
|
|
129 |
$entry[$pwattr] = $crypted_pass; |
48e9c1
|
130 |
|
d6938b
|
131 |
// Update PasswordLastChange Attribute if desired |
AM |
132 |
if ($lchattr) { |
99de1f
|
133 |
$entry[$lchattr] = (int)(time() / 86400); |
d6938b
|
134 |
} |
48e9c1
|
135 |
|
T |
136 |
// Update Samba password |
|
137 |
if ($smbpwattr) { |
99de1f
|
138 |
$entry[$smbpwattr] = $samba_pass; |
48e9c1
|
139 |
} |
T |
140 |
|
|
141 |
// Update Samba password last change |
|
142 |
if ($smblchattr) { |
99de1f
|
143 |
$entry[$smblchattr] = time(); |
48e9c1
|
144 |
} |
T |
145 |
|
99de1f
|
146 |
$this->_debug("C: Modify $user_dn: " . print_r($entry, true)); |
AM |
147 |
|
|
148 |
if (!ldap_modify($ds, $user_dn, $entry)) { |
|
149 |
$this->_debug("S: ".ldap_error($ds)); |
|
150 |
|
d6938b
|
151 |
ldap_unbind($ds); |
99de1f
|
152 |
|
d6938b
|
153 |
return PASSWORD_CONNECT_ERROR; |
AM |
154 |
} |
48e9c1
|
155 |
|
99de1f
|
156 |
$this->_debug("S: OK"); |
AM |
157 |
|
d6938b
|
158 |
// All done, no error |
AM |
159 |
ldap_unbind($ds); |
99de1f
|
160 |
|
d6938b
|
161 |
return PASSWORD_SUCCESS; |
48e9c1
|
162 |
} |
T |
163 |
|
|
164 |
/** |
|
165 |
* Bind with searchDN and searchPW and search for the user's DN |
|
166 |
* Use search_base and search_filter defined in config file |
|
167 |
* Return the found DN |
|
168 |
*/ |
|
169 |
function search_userdn($rcmail, $ds) |
|
170 |
{ |
2a700d
|
171 |
$search_user = $rcmail->config->get('password_ldap_searchDN'); |
AM |
172 |
$search_pass = $rcmail->config->get('password_ldap_searchPW'); |
|
173 |
$search_base = $rcmail->config->get('password_ldap_search_base'); |
|
174 |
$search_filter = $rcmail->config->get('password_ldap_search_filter'); |
19884e
|
175 |
|
2a700d
|
176 |
if (empty($search_filter)) { |
AM |
177 |
return false; |
99de1f
|
178 |
} |
AM |
179 |
|
2a700d
|
180 |
$this->_debug("C: Bind " . ($search_user ? $search_user : '[anonymous]')); |
99de1f
|
181 |
|
19884e
|
182 |
// Bind |
AM |
183 |
if (!ldap_bind($ds, $search_user, $search_pass)) { |
99de1f
|
184 |
$this->_debug("S: ".ldap_error($ds)); |
d6938b
|
185 |
return false; |
AM |
186 |
} |
99de1f
|
187 |
|
AM |
188 |
$this->_debug("S: OK"); |
393c86
|
189 |
|
AM |
190 |
$search_base = rcube_ldap_password::substitute_vars($search_base); |
19884e
|
191 |
$search_filter = rcube_ldap_password::substitute_vars($search_filter); |
AM |
192 |
|
99de1f
|
193 |
$this->_debug("C: Search $search_base for $search_filter"); |
AM |
194 |
|
19884e
|
195 |
// Search for the DN |
AM |
196 |
if (!$sr = ldap_search($ds, $search_base, $search_filter)) { |
99de1f
|
197 |
$this->_debug("S: ".ldap_error($ds)); |
d6938b
|
198 |
return false; |
AM |
199 |
} |
48e9c1
|
200 |
|
99de1f
|
201 |
$found = ldap_count_entries($ds, $sr); |
AM |
202 |
|
|
203 |
$this->_debug("S: OK [found $found records]"); |
|
204 |
|
19884e
|
205 |
// If no or more entries were found, return false |
99de1f
|
206 |
if ($found != 1) { |
d6938b
|
207 |
return false; |
AM |
208 |
} |
48e9c1
|
209 |
|
d6938b
|
210 |
return ldap_get_dn($ds, ldap_first_entry($ds, $sr)); |
48e9c1
|
211 |
} |
99de1f
|
212 |
|
AM |
213 |
/** |
|
214 |
* Prints debug info to the log |
|
215 |
*/ |
|
216 |
private function _debug($str) |
|
217 |
{ |
|
218 |
if ($this->debug) { |
|
219 |
rcube::write_log('ldap', $str); |
|
220 |
} |
|
221 |
} |
|
222 |
|
48e9c1
|
223 |
} |