1<?php
2/**
3 * Copyright 2004-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 2004-2017 Horde LLC
10 * @license   http://www.horde.org/licenses/gpl GPL
11 * @package   Passwd
12 */
13
14/**
15 * The PSPasswd class changes a user's password on any Windows Machine
16 * (NT+) using the pspasswd free utility available at Sysinternals
17 * website: http://www.sysinternals.com/ntw2k/freeware/pspasswd.shtml
18 *
19 * IMPORTANT!
20 *
21 * This driver should be used only as a last resort when there's no
22 * possibility of using the ADSI or LDAP drivers, which are far more
23 * secure and fast. This driver needs administrative credentials
24 * exposed on the backends.php file, which is required by the
25 * pspasswd.exe tool. It's an alternative driver that should be
26 * avoided, but could also be the only option for a few scenarios.
27 * (eg: When you don't have ADSI or LDAP support)
28 *
29 * Sample backend configuration:
30 * <code>
31 * $backends['pspasswd'] = array(
32 *   'name' => 'Sample pspasswd backend',
33 *   'preferred' => 'localhost',
34 *   'policy' => array(
35 *       'minLength' => 8,
36 *       'maxLength' => 14
37 *   ),
38 *   'driver' => 'pspasswd',
39 *   'params' => array(
40 *		 'server' => 'YOUR_SERVER_NAME',
41 *		 'bin' => 'DRIVE:\\DIR\\pspasswd.exe', // Notice: "\\"
42 *		 'admusr' => 'Administrator',
43 *	  	 'admpwd' => 'Password',
44 *       'domain' => 'YOUR_DOMAIN_NAME'
45 *   )
46 * );
47 * </code>
48 *
49 * Backend parameters:<pre>
50 * server	= Machine where you want to change the password (Required)
51 * bin		= Full pathname of the pspasswd.exe program (Required)
52 * admusr	= User with administrative privileges (Required)
53 * admpwd	= Password of the administrative user (Required)
54 * domain	= Windows domain name (Optional)
55 * </pre>
56 *
57 * For example: Passing a NT4 PDC server name to the server parameter
58 * means you can change the user's password on that NT4 Domain.
59 *
60 * Special thanks to Mark Russinovich (mark@sysinternals.com) for the
61 * tool and helping me solve some questions about it.
62 *
63 * @author    Luiz R Malheiros (malheiros@gmail.com)
64 * @category  Horde
65 * @copyright 2000-2017 Horde LLC
66 * @license   http://www.horde.org/licenses/gpl GPL
67 * @package   Passwd
68 */
69class Passwd_Driver_Pspasswd extends Passwd_Driver
70{
71    /**
72     */
73    public function __construct(array $params = array())
74    {
75        if (empty($params['server']) ||
76            empty($params['bin']) ||
77            empty($params['admusr']) ||
78            empty($params['admpwd'])) {
79            throw new Passwd_Exception(_("Password module is missing required parameters."));
80        }
81
82        if (!file_exists($params['bin'])) {
83            throw new Passwd_Exception(_("Password module can't find the supplied bin."));
84        }
85
86        parent::__construct($params);
87    }
88
89    /**
90     */
91    protected function _changePassword($user, $oldpass, $newpass)
92    {
93        $server = $this->_params['server'];
94        $chpwd_adm = $this->_params['admusr'];
95        $chpwd_usr = $user;
96
97        if (!empty($this->_params['domain'])) {
98            $chpwd_adm = $this->_params['domain'] . "\\" . $chpwd_adm;
99            $chpwd_usr = $this->_params['domain'] . "\\" . $chpwd_usr_name;
100        }
101
102        exec('NET USE \\\\' . $server . '\\IPC$ /D >NUL 2>NUL');
103
104        $cmdline = 'NET USE \\\\' . $server . '\\IPC$ "' . $oldpass
105            . '" /USER:' . $chpwd_usr;
106        exec($cmdline, $cmdreply, $retval);
107
108        if (strpos(implode(' ', $cmdreply), 'The command completed successfully.') === false) {
109            throw new Passwd_Exception(_("Failed to verify old password."));
110        }
111
112        exec('NET USE \\\\' . $server . '\\IPC$ /D >NUL 2>NUL');
113
114        $cmdline = $this->_params['bin'] . ' \\\\' . $server . ' -u ' . $chpwd_adm . ' -p ' . $this->_params['admpwd'] . ' ' . $user. ' ' . $newpass;
115        exec($cmdline, $cmdreply, $retval);
116        exec('NET USE \\\\' . $server . '\\IPC$ /D >NUL 2>NUL');
117
118        if (strpos(implode(' ', $cmdreply), 'Password for ' . $server . '\\' . $user. ' successfully changed.') === false) {
119            throw new Passwd_Exception(_("Access Denied."));
120        }
121    }
122
123}
124