1<?php
2/**
3 * Copyright 2002-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 2002-2017 Horde LLC
10 * @license   http://www.horde.org/licenses/gpl GPL
11 * @package   Passwd
12 */
13
14/**
15 * The vpopmail class attempts to change a user's password for vpopmail based
16 * servers.  It is very similar to the more generic sql driver, and the two
17 * should probably be merged into one driver if possible.
18 *
19 * @author    Mike Cochrane <mike@graftonhall.co.nz>
20 * @author    Mattias Webjörn Eriksson <mattias@webjorn.org>
21 * @author    Ilya Krel <mail@krel.org>
22 * @author    Ralf Lang <lang@b1-systems.de>
23 * @author    Anton Nekhoroshikh <anton@valuehost.ru>
24 * @author    Eric Jon Rostetter <eric.rostetter@physics.utexas.edu>
25 * @author    Tjeerd van der Zee <admin@xar.nl>
26 * @category  Horde
27 * @copyright 2002-2017 Horde LLC
28 * @license   http://www.horde.org/licenses/gpl GPL
29 * @package   Passwd
30 */
31class Passwd_Driver_Vpopmail extends Passwd_Driver
32{
33    /**
34     * The Horde_Db object.
35     *
36     * @var Horde_Db_Adapter
37     */
38    protected  $_db;
39
40    /**
41     * State of SQL connection.
42     *
43     * @var boolean
44     */
45    protected  $_connected = false;
46
47    /**
48     */
49    public function __construct($params = array())
50    {
51        if (!isset($params['db'])) {
52            throw new Passwd_Exception('Missing required Horde_Db_Adapter object');
53        }
54
55        $this->_db = $params['db'];
56        unset($params['db']);
57
58        /* Use defaults from Horde. */
59        parent::__construct(array_merge(
60            Horde::getDriverConfig('', 'sql'),
61            array(
62                'clear_passwd' => 'pw_clear_passwd',
63                'domain' => 'pw_domain',
64                'encryption' => 'crypt',
65                'name' => 'pw_name',
66                'passwd' => 'pw_passwd',
67                'show_encryption' => false,
68                'table' => 'horde_users',
69                'use_clear_passwd' => false
70            ),
71            $params
72        ));
73    }
74
75
76    /**
77     * Finds out if a username and password is valid.
78     *
79     * @param string $user     The username to check.
80     * @param string $oldpass  An old password to check.
81     *
82     * @throws Passwd_Exception
83     */
84    protected function _lookup($user, $oldpass)
85    {
86        /* Only split up username if domain is set in backend configuration. */
87        if (!empty($this->_params['domain'])) {
88            list($name, $domain) = explode('@', $user);
89        } else {
90            $name = $user;
91        }
92
93        /* Build the SQL query. */
94        $sql = 'SELECT ' . $this->_params['passwd'] .
95               ' FROM ' . $this->_params['table'] .
96               ' WHERE ' . $this->_params['name'] . ' = ?';
97        $values = array($name);
98        if ($this->_params['domain']) {
99            $sql .= ' AND ' . $this->_params['domain'] . ' = ?';
100            $values[] = $domain;
101        }
102
103        /* Execute the query. */
104        try {
105            $result = $this->_db->selectOne($sql, $values);
106        } catch (Horde_Db_Exception $e) {
107            throw new Passwd_Exception($e);
108        }
109
110        if (!is_array($result)) {
111            throw new Passwd_Exception(_("User not found"));
112        }
113
114        /* Check the passwords match. */
115        $this->_comparePasswords($result[$this->_params['passwd']], $oldpass);
116    }
117
118    /**
119     * Modifies a SQL password record for a user.
120     *
121     * @param string $user     The user whose record we will udpate.
122     * @param string $newpass  The new password value to set.
123     *
124     * @throws Passwd_Exception
125     */
126    protected function _modify($user, $newpass)
127    {
128        /* Only split up username if domain is set in backend. */
129        if ($this->_params['domain']) {
130            list($name, $domain) = explode('@', $user);
131        } else {
132            $name = $user;
133        }
134
135        /* Encrypt the password. */
136        $clear_password = $newpass;
137        $newpass = $this->_encryptPassword($newpass);
138
139        /* Build the SQL query. */
140        $sql = 'UPDATE ' . $this->_params['table'] .
141               ' SET ' . $this->_params['passwd'] . ' = ?';
142        $values = array($newpass);
143        if ($this->_params['use_clear_passwd']) {
144            $sql .= ', ' . $this->_params['clear_passwd'] . ' = ?';
145            $values[] = $clear_password;
146        }
147        $sql .= ' WHERE ' . $this->_params['name'] . ' = ?';
148        $values[] = $name;
149        if ($this->_params['domain']) {
150            $sql .= ' AND ' . $this->_params['domain'] . ' = ?';
151            $values[] = $domain;
152        }
153
154        /* Execute the query. */
155        try {
156            $this->_db->update($sql, $values);
157        } catch (Horde_Db_Exception $e) {
158            throw new Passwd_Exception($e);
159        }
160    }
161
162    /**
163     */
164    protected function _changePassword($user, $oldpass, $newpass)
165    {
166        $this->_lookup($user, $oldpass);
167        $this->_modify($user, $newpass);
168    }
169
170}
171