1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
18: class Passwd_Driver_Ldap extends Passwd_Driver
19: {
20: 21: 22: 23: 24:
25: protected $_ldap = false;
26:
27: 28: 29: 30: 31:
32: protected $_userdn;
33:
34: 35: 36: 37: 38: 39: 40:
41: public function __construct($params = array())
42: {
43: foreach (array('basedn', 'ldap', 'uid') as $val) {
44: if (!isset($params[$val])) {
45: throw new InvalidArgumentException(__CLASS__ . ': Missing ' . $val . ' parameter.');
46: }
47: }
48:
49: $this->_ldap = $params['ldap'];
50: unset($params['ldap']);
51:
52: $this->_params = array_merge(
53: array('host' => 'localhost',
54: 'port' => 389,
55: 'encryption' => 'crypt',
56: 'show_encryption' => 'true',
57: 'uid' => 'uid',
58: 'basedn' => '',
59: 'admindn' => '',
60: 'adminpw' => '',
61: 'realm' => '',
62: 'filter' => null,
63: 'tls' => false,
64: 'attribute' => 'userPassword',
65: 'shadowlastchange' => '',
66: 'shadowmin' => ''),
67: $params);
68:
69: if (!empty($this->_params['tls']) &&
70: empty($this->_params['sslhost'])) {
71: $this->_params['sslhost'] = $this->_params['host'];
72: }
73: }
74:
75: 76: 77: 78: 79: 80: 81: 82:
83: protected function _comparePasswords($encrypted, $plaintext)
84: {
85: $encrypted = preg_replace('/^{MD5}(.*)/i', '{MD5-BASE64}$1', $encrypted);
86: return parent::_comparePasswords($encrypted, $plaintext);
87: }
88:
89: 90: 91: 92: 93: 94: 95: 96: 97:
98: public function changePassword($username, $old_password, $new_password)
99: {
100:
101: if (!empty($this->_params['realm'])) {
102: $username .= '@' . $this->_params['realm'];
103: }
104:
105:
106: try {
107: $this->_userdn = Horde::callHook('userdn', array($username), 'passwd');
108: } catch (Horde_Exception_HookNotSet $e) {
109:
110:
111:
112: $this->_userdn = $this->_params['uid'] . '=' . $username . ',' . $this->_params['basedn'];
113: }
114:
115: try {
116:
117: $this->_ldap->bind($this->_userdn, $old_password);
118: } catch (Horde_Ldap_Exception $e) {
119: throw new Passwd_Exception($e);
120: }
121:
122:
123: if (!empty($this->_params['admindn'])) {
124: try {
125: $this->_ldap->bind();
126: } catch (Horde_Ldap_Exception $e) {
127: throw new Passwd_Exception($e);
128: }
129: }
130:
131:
132: $entry = $this->_getUserEntry();
133: if (!$entry) {
134: throw new Passwd_Exception(_("User not found."));
135: }
136:
137:
138: $lookupshadow = array('shadowlastchange' => false,
139: 'shadowmin' => false);
140:
141: if (!empty($this->_params['shadowlastchange']) &&
142: $entry->exists($this->_params['shadowlastchange'])) {
143: $lookupshadow['shadowlastchange'] = $entry->getValue($this->_params['shadowlastchange']);
144: }
145: if (!empty($this->_params['shadowmin']) &&
146: $entry->exists($this->_params['shadowmin'])) {
147: $lookupshadow['shadowmin'] = $entry->getValue($this->_params['shadowmin']);
148: }
149:
150:
151: if ($lookupshadow['shadowlastchange'] &&
152: $lookupshadow['shadowmin'] &&
153: ($lookupshadow['shadowlastchange'] + $lookupshadow['shadowmin'] > (time() / 86400))) {
154: throw new Passwd_Exception(_("Minimum password age has not yet expired"));
155: }
156:
157:
158: try {
159: $entry->replace(array($this->_params['attribute'] => $this->_encryptPassword($new_password)), true);
160:
161: if (!empty($this->_params['shadowlastchange']) &&
162: $lookupshadow['shadowlastchange']) {
163: $entry->replace(array($this->_params['shadowlastchange'] => floor(time() / 86400)));
164: }
165:
166: $entry->update();
167: } catch (Horde_Ldap_Exception $e) {
168: throw new Passwd_Exception($e);
169: }
170: }
171:
172: 173: 174: 175: 176: 177:
178: protected function _getUserEntry()
179: {
180: try {
181: return $this->_ldap->getEntry($this->_userdn);
182: } catch (Horde_Ldap_Exception $e) {
183: throw new Passwd_Exception($e);
184: }
185: }
186: }
187: