commit | author | age
|
5fec6d
|
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 1.0 (2010-07-31) |
|
11 |
* @author Wout Decre <wout@canodus.be> |
|
12 |
*/ |
|
13 |
function password_save($curpass, $passwd) |
|
14 |
{ |
|
15 |
$rcmail = rcmail::get_instance(); |
|
16 |
|
|
17 |
/* Connect */ |
|
18 |
if (!$ds = ldap_connect($rcmail->config->get('password_ldap_host'), $rcmail->config->get('password_ldap_port'))) { |
|
19 |
ldap_unbind($ds); |
|
20 |
return PASSWORD_CONNECT_ERROR; |
|
21 |
} |
|
22 |
|
db1a87
|
23 |
/* Set protocol version */ |
5fec6d
|
24 |
if (!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $rcmail->config->get('password_ldap_version'))) { |
T |
25 |
ldap_unbind($ds); |
|
26 |
return PASSWORD_CONNECT_ERROR; |
|
27 |
} |
|
28 |
|
|
29 |
/* Start TLS */ |
|
30 |
if ($rcmail->config->get('password_ldap_starttls')) { |
|
31 |
if (!ldap_start_tls($ds)) { |
|
32 |
ldap_unbind($ds); |
|
33 |
return PASSWORD_CONNECT_ERROR; |
|
34 |
} |
|
35 |
} |
|
36 |
|
|
37 |
/* Build user DN */ |
|
38 |
if ($user_dn = $rcmail->config->get('password_ldap_userDN_mask')) { |
|
39 |
$user_dn = ldap_simple_substitute_vars($user_dn); |
|
40 |
} else { |
|
41 |
$user_dn = ldap_simple_search_userdn($rcmail, $ds); |
|
42 |
} |
db1a87
|
43 |
|
5fec6d
|
44 |
if (empty($user_dn)) { |
T |
45 |
ldap_unbind($ds); |
|
46 |
return PASSWORD_CONNECT_ERROR; |
|
47 |
} |
db1a87
|
48 |
|
5fec6d
|
49 |
/* Connection method */ |
T |
50 |
switch ($rcmail->config->get('password_ldap_method')) { |
|
51 |
case 'admin': |
|
52 |
$binddn = $rcmail->config->get('password_ldap_adminDN'); |
|
53 |
$bindpw = $rcmail->config->get('password_ldap_adminPW'); |
|
54 |
break; |
|
55 |
case 'user': |
|
56 |
default: |
|
57 |
$binddn = $user_dn; |
|
58 |
$bindpw = $curpass; |
|
59 |
break; |
|
60 |
} |
|
61 |
|
|
62 |
/* Bind */ |
|
63 |
if (!ldap_bind($ds, $binddn, $bindpw)) { |
|
64 |
ldap_unbind($ds); |
|
65 |
return PASSWORD_CONNECT_ERROR; |
|
66 |
} |
db1a87
|
67 |
|
5fec6d
|
68 |
/* Crypting new password */ |
T |
69 |
$passwd = ldap_simple_hash_password($passwd, $rcmail->config->get('password_ldap_encodage')); |
|
70 |
if (!$passwd) { |
|
71 |
ldap_unbind($ds); |
|
72 |
return PASSWORD_CRYPT_ERROR; |
|
73 |
} |
db1a87
|
74 |
|
5fec6d
|
75 |
$entree[$rcmail->config->get('password_ldap_pwattr')] = $passwd; |
T |
76 |
|
|
77 |
/* Updating PasswordLastChange Attribute if desired */ |
|
78 |
if ($lchattr = $rcmail->config->get('password_ldap_lchattr')) { |
db1a87
|
79 |
$entree[$lchattr] = (int)(time() / 86400); |
5fec6d
|
80 |
} |
T |
81 |
|
db1a87
|
82 |
|
5fec6d
|
83 |
if (!ldap_modify($ds, $user_dn, $entree)) { |
T |
84 |
ldap_unbind($ds); |
|
85 |
return PASSWORD_CONNECT_ERROR; |
|
86 |
} |
db1a87
|
87 |
|
5fec6d
|
88 |
/* All done, no error */ |
T |
89 |
ldap_unbind($ds); |
|
90 |
return PASSWORD_SUCCESS; |
|
91 |
} |
|
92 |
|
|
93 |
/** |
|
94 |
* Bind with searchDN and searchPW and search for the user's DN |
|
95 |
* Use search_base and search_filter defined in config file |
|
96 |
* Return the found DN |
|
97 |
*/ |
|
98 |
function ldap_simple_search_userdn($rcmail, $ds) |
|
99 |
{ |
|
100 |
/* Bind */ |
|
101 |
if (!ldap_bind($ds, $rcmail->config->get('password_ldap_searchDN'), $rcmail->config->get('password_ldap_searchPW'))) { |
|
102 |
return false; |
|
103 |
} |
db1a87
|
104 |
|
5fec6d
|
105 |
/* Search for the DN */ |
T |
106 |
if (!$sr = ldap_search($ds, $rcmail->config->get('password_ldap_search_base'), ldap_simple_substitute_vars($rcmail->config->get('password_ldap_search_filter')))) { |
|
107 |
return false; |
|
108 |
} |
db1a87
|
109 |
|
5fec6d
|
110 |
/* If no or more entries were found, return false */ |
T |
111 |
if (ldap_count_entries($ds, $sr) != 1) { |
|
112 |
return false; |
|
113 |
} |
db1a87
|
114 |
|
5fec6d
|
115 |
return ldap_get_dn($ds, ldap_first_entry($ds, $sr)); |
T |
116 |
} |
|
117 |
|
|
118 |
/** |
db1a87
|
119 |
* Substitute %login, %name, %domain, %dc in $str |
5fec6d
|
120 |
* See plugin config for details |
T |
121 |
*/ |
|
122 |
function ldap_simple_substitute_vars($str) |
|
123 |
{ |
|
124 |
$str = str_replace('%login', $_SESSION['username'], $str); |
|
125 |
$str = str_replace('%l', $_SESSION['username'], $str); |
db1a87
|
126 |
|
5fec6d
|
127 |
$parts = explode('@', $_SESSION['username']); |
db1a87
|
128 |
|
5fec6d
|
129 |
if (count($parts) == 2) { |
db1a87
|
130 |
$dc = 'dc='.strtr($parts[1], array('.' => ',dc=')); // hierarchal domain string |
T |
131 |
|
5fec6d
|
132 |
$str = str_replace('%name', $parts[0], $str); |
db1a87
|
133 |
$str = str_replace('%n', $parts[0], $str); |
T |
134 |
$str = str_replace('%dc', $dc, $str); |
5fec6d
|
135 |
$str = str_replace('%domain', $parts[1], $str); |
T |
136 |
$str = str_replace('%d', $parts[1], $str); |
|
137 |
} |
|
138 |
|
|
139 |
return $str; |
|
140 |
} |
|
141 |
|
|
142 |
/** |
|
143 |
* Code originaly from the phpLDAPadmin development team |
|
144 |
* http://phpldapadmin.sourceforge.net/ |
|
145 |
* |
|
146 |
* Hashes a password and returns the hash based on the specified enc_type |
|
147 |
*/ |
|
148 |
function ldap_simple_hash_password($password_clear, $encodage_type) |
|
149 |
{ |
|
150 |
$encodage_type = strtolower($encodage_type); |
|
151 |
switch ($encodage_type) { |
|
152 |
case 'crypt': |
|
153 |
$crypted_password = '{CRYPT}' . crypt($password_clear, ldap_simple_random_salt(2)); |
|
154 |
break; |
|
155 |
case 'ext_des': |
|
156 |
/* Extended DES crypt. see OpenBSD crypt man page */ |
|
157 |
if (!defined('CRYPT_EXT_DES') || CRYPT_EXT_DES == 0) { |
|
158 |
/* Your system crypt library does not support extended DES encryption */ |
|
159 |
return false; |
|
160 |
} |
|
161 |
$crypted_password = '{CRYPT}' . crypt($password_clear, '_' . ldap_simple_random_salt(8)); |
|
162 |
break; |
|
163 |
case 'md5crypt': |
|
164 |
if (!defined('CRYPT_MD5') || CRYPT_MD5 == 0) { |
|
165 |
/* Your system crypt library does not support md5crypt encryption */ |
|
166 |
return false; |
|
167 |
} |
|
168 |
$crypted_password = '{CRYPT}' . crypt($password_clear, '$1$' . ldap_simple_random_salt(9)); |
|
169 |
break; |
|
170 |
case 'blowfish': |
|
171 |
if (!defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH == 0) { |
|
172 |
/* Your system crypt library does not support blowfish encryption */ |
|
173 |
return false; |
|
174 |
} |
|
175 |
/* Hardcoded to second blowfish version and set number of rounds */ |
|
176 |
$crypted_password = '{CRYPT}' . crypt($password_clear, '$2a$12$' . ldap_simple_random_salt(13)); |
|
177 |
break; |
|
178 |
case 'md5': |
|
179 |
$crypted_password = '{MD5}' . base64_encode(pack('H*', md5($password_clear))); |
|
180 |
break; |
|
181 |
case 'sha': |
|
182 |
if (function_exists('sha1')) { |
|
183 |
/* Use PHP 4.3.0+ sha1 function, if it is available */ |
|
184 |
$crypted_password = '{SHA}' . base64_encode(pack('H*', sha1($password_clear))); |
|
185 |
} else if (function_exists('mhash')) { |
|
186 |
$crypted_password = '{SHA}' . base64_encode(mhash(MHASH_SHA1, $password_clear)); |
|
187 |
} else { |
|
188 |
/* Your PHP install does not have the mhash() function */ |
|
189 |
return false; |
|
190 |
} |
|
191 |
break; |
|
192 |
case 'ssha': |
|
193 |
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) { |
|
194 |
mt_srand((double) microtime() * 1000000 ); |
|
195 |
$salt = mhash_keygen_s2k(MHASH_SHA1, $password_clear, substr(pack('h*', md5(mt_rand())), 0, 8), 4); |
|
196 |
$crypted_password = '{SSHA}' . base64_encode(mhash(MHASH_SHA1, $password_clear . $salt) . $salt); |
|
197 |
} else { |
|
198 |
/* Your PHP install does not have the mhash() function */ |
|
199 |
return false; |
|
200 |
} |
|
201 |
break; |
|
202 |
case 'smd5': |
|
203 |
if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) { |
|
204 |
mt_srand((double) microtime() * 1000000 ); |
|
205 |
$salt = mhash_keygen_s2k(MHASH_MD5, $password_clear, substr(pack('h*', md5(mt_rand())), 0, 8), 4); |
|
206 |
$crypted_password = '{SMD5}' . base64_encode(mhash(MHASH_MD5, $password_clear . $salt) . $salt); |
|
207 |
} else { |
|
208 |
/* Your PHP install does not have the mhash() function */ |
|
209 |
return false; |
|
210 |
} |
|
211 |
break; |
|
212 |
case 'clear': |
|
213 |
default: |
|
214 |
$crypted_password = $password_clear; |
|
215 |
} |
|
216 |
|
|
217 |
return $crypted_password; |
|
218 |
} |
|
219 |
|
|
220 |
/** |
|
221 |
* Code originaly from the phpLDAPadmin development team |
|
222 |
* http://phpldapadmin.sourceforge.net/ |
|
223 |
* |
|
224 |
* Used to generate a random salt for crypt-style passwords |
|
225 |
*/ |
|
226 |
function ldap_simple_random_salt($length) |
|
227 |
{ |
|
228 |
$possible = '0123456789' . 'abcdefghijklmnopqrstuvwxyz' . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . './'; |
|
229 |
$str = ''; |
|
230 |
// mt_srand((double)microtime() * 1000000); |
|
231 |
while (strlen($str) < $length) { |
|
232 |
$str .= substr($possible, (rand() % strlen($possible)), 1); |
|
233 |
} |
db1a87
|
234 |
|
5fec6d
|
235 |
return $str; |
T |
236 |
} |