Aleksander Machniak
2014-06-24 2a700d7c00e20815602dc0e20c9c71b436abfce0
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 }