Overview

Packages

  • None
  • Passwd

Classes

  • Passwd
  • Passwd_Driver
  • Passwd_Driver_Adsi
  • Passwd_Driver_Composite
  • Passwd_Driver_Expect
  • Passwd_Driver_Expectpecl
  • Passwd_Driver_Horde
  • Passwd_Driver_Http
  • Passwd_Driver_Kolab
  • Passwd_Driver_Ldap
  • Passwd_Driver_Pine
  • Passwd_Driver_Poppassd
  • Passwd_Driver_Procopen
  • Passwd_Driver_Pspasswd
  • Passwd_Driver_Servuftp
  • Passwd_Driver_Smbldap
  • Passwd_Driver_Smbpasswd
  • Passwd_Driver_Soap
  • Passwd_Driver_Sql
  • Passwd_Driver_Vmailmgr
  • Passwd_Driver_Vpopmail
  • Passwd_Exception
  • Passwd_Factory_Driver
  • Overview
  • Package
  • Class
  • Tree
  1: <?php
  2: /**
  3:  * The Pine class attempts to change a user's password on a in a pine password
  4:  * file.
  5:  *
  6:  * Copyright 2003-2012 Horde LLC (http://www.horde.org/)
  7:  *
  8:  * See the enclosed file COPYING for license information (GPL). If you
  9:  * did not receive this file, see http://www.horde.org/licenses/gpl.php.
 10:  *
 11:  * @author  Max Kalika <max@horde.org>
 12:  * @package Passwd
 13:  */
 14: class Passwd_Driver_Pine extends Passwd_Driver
 15: {
 16:     /**
 17:      * Lower boundary character.
 18:      */
 19:     const FIRSTCH = 0x20;
 20: 
 21:     /**
 22:      * Upper boundary character.
 23:      */
 24:     const LASTCH = 0x7e;
 25: 
 26:     /**
 27:      * Median character.
 28:      */
 29:     const TABSZ = 0x5f;
 30: 
 31:     /**
 32:      * Horde_Vfs instance.
 33:      *
 34:      * @var VFS
 35:      */
 36:     protected $_ftp;
 37: 
 38:     /**
 39:      * Boolean which contains state of the ftp connection.
 40:      *
 41:      * @var boolean
 42:      */
 43:     protected $_connected = false;
 44: 
 45:     /**
 46:      * Contents array of the pine password file.
 47:      *
 48:      * @var array
 49:      */
 50:     protected $_contents = array();
 51: 
 52:     /**
 53:      * Constructor.
 54:      *
 55:      * @param array $params  A hash containing connection parameters.
 56:      */
 57:     public function __construct($params = array())
 58:     {
 59:         $this->_params = array_merge(
 60:             array(
 61:                 /* We self-encrypt here, so plaintext is needed. */
 62:                 'encryption' => 'plain',
 63:                 'show_encryption' => false,
 64: 
 65:                 /* Sensible FTP server parameters. */
 66:                 'host' => 'localhost',
 67:                 'port' => 21,
 68:                 'path' => '',
 69:                 'file' => '.pinepw',
 70: 
 71:                 /* Connect to FTP server using just-passed-in credentials?
 72:                  * Only useful if using the composite driver and changing
 73:                  * system (FTP) password prior to this one. */
 74:                 'use_new_passwd' => false,
 75: 
 76:                 /* What host to look for on each line? */
 77:                 'imaphost' => 'localhost'),
 78:             $params);
 79:     }
 80: 
 81:     /**
 82:      * Connects to the FTP server.
 83:      *
 84:      * @throws Passwd_Exception
 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:      * Disconnect from the FTP server.
111:      *
112:      * @throws Passwd_Exception
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:      * Decodes a Pine-encoded password string.
130:      *
131:      * The algorithm is borrowed from read_passfile() and xlate_out() functions
132:      * in pine/imap.c file distributed in the Pine source archive.
133:      *
134:      * @param string $string  The contents of a pine-encoded password file.
135:      *
136:      * @return array  List of lines of decoded elements.
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:      * Encodes an array of elements into a Pine-readable password string.
177:      *
178:      * The algorith is borrowed from write_passfile() and xlate_in() functions
179:      * in pine/imap.c file distributed in the Pine source archive.
180:      *
181:      * @param array  $lines  List of lines of decoded elements
182:      *
183:      * @return array  Contents of a pine-readable password file.
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:      * Finds out if a username and password is valid.
218:      *
219:      * @param string $user         The userID to check.
220:      * @param string $oldPassword  An old password to check.
221:      *
222:      * @throws Passwd_Exception
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:      * Modifies a pine password record for a user.
248:      *
249:      * @param string $user         The user whose record we will udpate.
250:      * @param string $newPassword  The new password value to set.
251:      *
252:      * @throws Passwd_Exception
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:      * Changes the user's password.
277:      *
278:      * @param string $username     The user for which to change the password.
279:      * @param string $oldPassword  The old (current) user password.
280:      * @param string $newPassword  The new user password to set.
281:      *
282:      * @throws Passwd_Exception
283:      */
284:     public function changePassword($username,  $oldPassword, $newPassword)
285:     {
286:         /* Connect to the ftp server. */
287:         $this->_connect($username, $this->_params['use_new_passwd'] ? $newPassword : $oldPassword);
288: 
289:         /* Check the current password. */
290:         $this->_lookup($username, $oldPassword);
291: 
292:         $this->_modify($username, $newPassword);
293: 
294:         $this->_disconnect();
295:     }
296: }
297: 
API documentation generated by ApiGen