1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: class Passwd_Driver_Pine extends Passwd_Driver
15: {
16: 17: 18:
19: const FIRSTCH = 0x20;
20:
21: 22: 23:
24: const LASTCH = 0x7e;
25:
26: 27: 28:
29: const TABSZ = 0x5f;
30:
31: 32: 33: 34: 35:
36: protected $_ftp;
37:
38: 39: 40: 41: 42:
43: protected $_connected = false;
44:
45: 46: 47: 48: 49:
50: protected $_contents = array();
51:
52: 53: 54: 55: 56:
57: public function __construct($params = array())
58: {
59: $this->_params = array_merge(
60: array(
61:
62: 'encryption' => 'plain',
63: 'show_encryption' => false,
64:
65:
66: 'host' => 'localhost',
67: 'port' => 21,
68: 'path' => '',
69: 'file' => '.pinepw',
70:
71: 72: 73:
74: 'use_new_passwd' => false,
75:
76:
77: 'imaphost' => 'localhost'),
78: $params);
79: }
80:
81: 82: 83: 84: 85:
86: protected function _connect($user, $password)
87: {
88: if ($this->_connected) {
89: return;
90: }
91:
92: $params = array(
93: 'username' => $user,
94: 'password' => $password,
95: 'hostspec' => $this->_params['host'],
96: 'port' => $this->_params['port'],
97: );
98:
99: try {
100: $this->_ftp = Horde_Vfs::factory('ftp', $params);
101: $this->_ftp->checkCredentials();
102: } catch (Horde_Vfs_Exception $e) {
103: throw new Passwd_Exception($e);
104: }
105:
106: $this->_connected = true;
107: }
108:
109: 110: 111: 112: 113:
114: protected function _disconnect()
115: {
116: if (!$this->_connected) {
117: return;
118: }
119:
120: try {
121: $this->_ftp->disconnect();
122: } catch (Horde_Vfs_Exception $e) {
123: throw new Passwd_Exception($e);
124: }
125: $this->_connected = false;
126: }
127:
128: 129: 130: 131: 132: 133: 134: 135: 136: 137:
138: protected function _decode($string)
139: {
140: $list = array();
141:
142: $lines = explode("\n", $string);
143: for ($n = 0; $n < sizeof($lines); $n++) {
144: $key = $n;
145: $tmp = $lines[$n];
146: for ($i = 0; $i < strlen($tmp); $i++) {
147: if ((ord($tmp[$i]) >= self::FIRSTCH) &&
148: (ord($tmp[$i]) <= self::LASTCH)) {
149: $xch = ord($tmp[$i]) - ($dti = $key);
150: $xch += ($xch < self::FIRSTCH - self::TABSZ)
151: ? 2 * self::TABSZ
152: : ($xch < self::FIRSTCH) ? self::TABSZ : 0;
153: $dti = ($xch - self::FIRSTCH) + $dti;
154: $dti -= ($dti >= 2 * self::TABSZ)
155: ? 2 * self::TABSZ
156: : ($dti >= self::TABSZ) ? self::TABSZ : 0;
157: $key = $dti;
158: $tmp[$i] = chr($xch);
159: }
160: }
161:
162: if ($i && $tmp[$i - 1] == "\n") {
163: $tmp = substr($tmp, 0, -1);
164: }
165:
166: $parts = explode("\t", $tmp);
167: if (count($parts) >= 4) {
168: $list[] = $parts;
169: }
170: }
171:
172: return $list;
173: }
174:
175: 176: 177: 178: 179: 180: 181: 182: 183: 184:
185: protected function _encode($lines)
186: {
187: $string = '';
188: for ($n = 0; $n < sizeof($lines); $n++) {
189: if (isset($lines[$n][4])) {
190: $lines[$n][4] = "\t" . $lines[$n][4];
191: } else {
192: $lines[$n][4] = '';
193: }
194:
195: $key = $n;
196: $tmp = vsprintf("%.100s\t%.100s\t%.100s\t%d%s\n", $lines[$n]);
197: for ($i = 0; $i < strlen($tmp); $i++) {
198: $eti = $key;
199: if ((ord($tmp[$i]) >= self::FIRSTCH) &&
200: (ord($tmp[$i]) <= self::LASTCH)) {
201: $eti += ord($tmp[$i]) - self::FIRSTCH;
202: $eti -= ($eti >= 2 * self::TABSZ)
203: ? 2 * self::TABSZ
204: : ($eti >= self::TABSZ) ? self::TABSZ : 0;
205: $key = $eti;
206: $tmp[$i] = chr($eti + self::FIRSTCH);
207: }
208: }
209:
210: $string .= $tmp;
211: }
212:
213: return $string;
214: }
215:
216: 217: 218: 219: 220: 221: 222: 223:
224: protected function _lookup($user, $oldPassword)
225: {
226: try {
227: $contents = $this->_ftp->read($this->_params['path'],
228: $this->_params['file']);
229: } catch (Horde_Vfs_Exception $e) {
230: throw new Passwd_Exception($e);
231: }
232:
233: $this->_contents = $this->_decode($contents);
234: foreach ($this->_contents as $line) {
235: if ($line[1] == $user &&
236: (($line[2] == $this->_params['imaphost']) ||
237: (!empty($line[4]) && $line[4] == $this->_params['imaphost']))) {
238: $this->_comparePasswords($line[0], $oldPassword);
239: return;
240: }
241: }
242:
243: throw new Passwd_Exception(_("User not found."));
244: }
245:
246: 247: 248: 249: 250: 251: 252: 253:
254: protected function _modify($user, $newPassword)
255: {
256: for ($i = 0; $i < sizeof($this->_contents); $i++) {
257: if ($this->_contents[$i][1] == $user &&
258: (($this->_contents[$i][2] == $this->_params['imaphost']) ||
259: (!empty($this->_contents[$i][4]) &&
260: $this->_contents[$i][4] == $this->_params['imaphost']))) {
261: $this->_contents[$i][0] = $newPassword;
262: }
263: }
264:
265: $string = $this->_encode($this->_contents);
266: try {
267: $this->_ftp->writeData($this->_params['path'],
268: $this->_params['file'],
269: $string);
270: } catch (Horde_Vfs_Exception $e) {
271: throw new Passwd_Exception($e);
272: }
273: }
274:
275: 276: 277: 278: 279: 280: 281: 282: 283:
284: public function changePassword($username, $oldPassword, $newPassword)
285: {
286:
287: $this->_connect($username, $this->_params['use_new_passwd'] ? $newPassword : $oldPassword);
288:
289:
290: $this->_lookup($username, $oldPassword);
291:
292: $this->_modify($username, $newPassword);
293:
294: $this->_disconnect();
295: }
296: }
297: