1<?php
2/**
3 * Copyright 2000-2017 Horde LLC (http://www.horde.org/)
4 *
5 * See the enclosed file COPYING for license information (GPL). If you
6 * did not receive this file, see http://www.horde.org/licenses/gpl.
7 *
8 * @category  Horde
9 * @copyright 2000-2017 Horde LLC
10 * @license   http://www.horde.org/licenses/gpl GPL
11 * @package   Passwd
12 */
13
14/**
15 * Changes a password via a poppassd server.
16 *
17 * @author    Eric Jon Rostetter <eric.rostetter@physics.utexas.edu>
18 * @category  Horde
19 * @copyright 2000-2017 Horde LLC
20 * @license   http://www.horde.org/licenses/gpl GPL
21 * @package   Passwd
22 */
23class Passwd_Driver_Poppassd extends Passwd_Driver
24{
25    /**
26     */
27    public function __construct(array $params = array())
28    {
29        parent::__construct(array_merge(array(
30            'host' => 'localhost',
31            'port' => 106
32        ), $params));
33    }
34
35    /**
36     * Connects to the server.
37     *
38     * @throws Passwd_Exception
39     */
40    protected function _connect()
41    {
42        $this->_fp = fsockopen(
43            $this->_params['host'],
44            $this->_params['port'],
45            $errno,
46            $errstr,
47            30
48        );
49        if (!$this->_fp) {
50            throw new Passwd_Exception($errstr);
51        }
52
53        $this->_getPrompt();
54    }
55
56    /**
57     * Disconnects from the server.
58     */
59    protected function _disconnect()
60    {
61        if (isset($this->_fp)) {
62            fputs($this->_fp, "quit\n");
63            fclose($this->_fp);
64        }
65    }
66
67    /**
68     * Parses a response from the server to see what it was.
69     *
70     * @throws Passwd_Exception
71     */
72    protected function _getPrompt()
73    {
74        if (!($prompt = fgets($this->_fp, 4096))) {
75            throw new Passwd_Exception(_("No prompt returned from server."));
76        }
77
78        if (!preg_match('/^[1-5][0-9][0-9]/', $prompt)) {
79            throw new Passwd_Exception($prompt);
80        }
81
82        /* This should probably be a regex match for 2?0 or 3?0, no? */
83        $rc = substr($prompt, 0, 3);
84        if (!in_array($rc, array('200', '220', '250', '300'))) {
85            throw new Passwd_Exception($prompt);
86        }
87    }
88
89    /**
90     * Sends a command to the server.
91     *
92     * @throws Passwd_Exception
93     */
94    protected function _sendCommand($cmd, $arg)
95    {
96        $line = $cmd . ' ' . $arg . "\n";
97        if (!($res_fputs = fputs($this->_fp, $line))) {
98            throw new Passwd_Exception(_("Cannot send command to server."));
99        }
100        $this->_getPrompt();
101    }
102
103    /**
104     */
105    protected function _changePassword($user, $oldpass, $newpass)
106    {
107        $this->_connect();
108
109        try {
110            $this->_sendCommand('user', $user);
111        } catch (Passwd_Exception $e) {
112            $this->_disconnect();
113            throw new Passwd_Exception(_("User not found") . ': ' . $e->getMessage());
114        }
115
116        try {
117            $this->_sendCommand('pass', $oldpass);
118        } catch (Passwd_Exception $e) {
119            $this->_disconnect();
120            throw new Passwd_Exception(_("Incorrect old password.") . ': ' . $e->getMessage());
121        }
122
123        try {
124            $this->_sendCommand('newpass', $newpass);
125        } catch (Passwd_Exception $e) {
126            $this->_disconnect();
127            throw $e;
128        }
129    }
130
131}
132