I might get flagged by the admins as this is more of a Roundcube thing than a Virtualmin thing but the virtualmin.php driver included with Roundcube’s (optional) Password button did not work for me out of the box and neither did the LeeWells version posted on their forum in 2013 (so I tweaked that one). Since I don’t have a Roundcube forum account, since this only applies to Virtualmin users, and since I am more likely to find it again here than anywhere else if I ever forget how it works, I am recording it here in case it helps someone else. (Also since I am not particularly qualified to be tweaking any such thing, someone might come along and say “Oh no, you musn’t do it that way, no no no”, which would be good for me to know.)
To make the Password button appear (I guess on a live site you might want to do this part last) once you have added Roundcube to your Virtualmin site (under a virtual’s “Manage Web Apps”) you should find a file here:
/home/[domain’s-home-folder]/public_html/config/config.inc.php
or here (depending if you installed roundcube in the root or the suggested folder):
/home/[domain’s-home-folder]/public_html/roundcube/config/config.inc.php
Edit this file to include: ‘password’ in its $config[‘plugins’] array, mine looks like this (the other two things were already there):
// List of active plugins (in plugins/ directory)
$config['plugins'] = [
'archive',
'zipdownload',
'password',
];
Which gives you this:
It then needs to know which driver it should use to change passwords (Roundcube being a generic webmail client and not Virtualmin specific, obviously) which you set by copying or renaming this file to remove the “.inc” at the end:
/home/[domain’s-home-folder]/public_html/plugins/password/config.inc.php.inc
or here:
/home/[domain’s-home-folder]/public_html/roundcube/plugins/password/config.inc.php.inc
Edit the resulting /plugins/password/config.inc.php file’s $config[‘password_driver’] line thusly:
// Password Plugin options
// -----------------------
// A driver to use for password change. Default: "sql".
// See README file for list of supported driver names.
$config['password_driver'] = 'virtualmin';
(It will have defaulted to ‘sql’, type over that.)
Note that his adds confirmation of the current password to the form:
Then edit:
/home/[domain’s-home-folder]/public_html/plugins/password/drivers/virtualmin.php
or here:
/home/[domain’s-home-folder]/public_html/roundcube/plugins/password/drivers/virtualmin.php
Replacing its text with the following, but note that you must replace the instances of “localhost” with your-mail-domain (whatever you would put here to use virtualmin’s webmail: “https://your-mail-domain:20000”):
<?php
/**
* Virtualmin Password Driver Fixed
*
*
* Adapted and fixed by LeeWells
* Tweaked to only expect "successful" by Ron E James DO
*
* This script can run the server from ANY host, just replace localhost with the remote host
* that virtualmin runs on.
*
* @version 1.0
* @author LeeWells
*
* Copyright (C) 2005-2013, LeeWells
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
class rcube_virtualmin_password
{
function save($currpass, $newpass)
{
$rcmail = rcmail::get_instance();
$format = $rcmail->config->get('password_virtualmin_format', 0);
$username = $_SESSION['username'];
$cook = md5($username);
$username = escapeshellcmd($username);
$newpass = escapeshellcmd($newpass);
$curdir = RCUBE_PLUGINS_DIR . 'password/helpers';
$curl_handle = curl_init ("https://localhost:20000/session_login.cgi?user=$username&pass=$currpass");
curl_setopt($curl_handle, CURLOPT_COOKIEJAR, 'usermin.'.$cook.'.txt');
curl_setopt($curl_handle, CURLOPT_COOKIEFILE, 'usermin.'.$cook.'.txt');
curl_setopt($curl_handle, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0');
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_handle, CURLOPT_HEADER, 1);
curl_setopt($curl_handle, CURLOPT_STDERR, fopen('php://stdout', 'w'));
curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, 1);
$output = curl_exec ($curl_handle);
curl_close($curl_handle);
$post_array2 = array( 'old' => $currpass, 'new1' => $newpass, 'new2' => $newpass, );
$curl_handle = curl_init ("https://localhost:20000/changepass/changepass.cgi");
curl_setopt($curl_handle, CURLOPT_POST, 3);
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, 'old='.$currpass.'&new1='.$newpass.'&new2='.$newpass);
curl_setopt($curl_handle, CURLOPT_COOKIEJAR, 'usermin.'.$cook.'.txt');
curl_setopt($curl_handle, CURLOPT_COOKIEFILE, 'usermin.'.$cook.'.txt');
curl_setopt($curl_handle, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0');
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_handle, CURLOPT_REFERER, 'https://localhost:20000/changepass/');
curl_setopt($curl_handle, CURLOPT_HEADER, 1);
$content = curl_exec($curl_handle);
// Check if cURL execution was successful
if ($content === false) {
// Log the cURL error
rcube::raise_error(array(
'code' => 601,
'type' => 'php',
'file' => __FILE__,
'line' => __LINE__,
'message' => 'cURL error: ' . curl_error($curl_handle)
), true, false);
curl_close($curl_handle); // Close the handle before returning
return PASSWORD_ERROR;
}
// Check if content is not empty
if (empty($content)) {
rcube::raise_error(array(
'code' => 602,
'type' => 'php',
'file' => __FILE__,
'line' => __LINE__,
'message' => 'No content returned from cURL request.'
), true, false);
curl_close($curl_handle); // Close the handle before returning
return PASSWORD_ERROR;
}
curl_close($curl_handle); // Close the handle after all checks
if (stripos($content, 'successful') !== false) {
return PASSWORD_SUCCESS;
} else {
rcube::raise_error(array(
'code' => 600,
'type' => 'php',
'file' => __FILE__,
'line' => __LINE__,
'message' => 'Password change failed. Response: ' . $content
), true, false);
return PASSWORD_ERROR;
}
}
}
The driver in the box apparently requires some compiling and/or some permissions stuff… it didn’t sound like a good idea to LeeWells so he made an alternative that uses curl to visit the Virtualmin web interface and make the change for you. His version, from here down curl_setopt($curl_handle, CURLOPT_HEADER, 1);
looks like this:
curl_setopt($curl_handle, CURLOPT_HEADER, 1);
$content = curl_exec ($curl_handle);
curl_close($curl_handle);
$newcontent = explode('</tt>', $content);
$success = explode('.', $newcontent[1]);
if($success[0] == ' has been changed successfully')
{
return PASSWORD_SUCCESS;
} else {
rcube::raise_error(array(
'code' => 600,
'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => $success[0]
), true, false);
return PASSWORD_ERROR;
}
}
}
(So overwriting my version from that same line to the bottom would switch this back to the original.)
I am not skilled enough to go line-by-line through that but generally I understand it to be looking for " has been changed successfully" in a specific spot in the output of Virtualmin’s password change response in order to declare the operation a success. That response must have changed somewhere along the way (or between his site’s response and mine anyway) because if I use it as-is it says “Could not save new password” even though it does change the password (and since it didn’t declare success the plugin doesn’t automatically switch to the new password in the background so you also find yourself kicked out and weren’t told that your password was changed correctly).
My version looks only for “successful” anywhere in the response. (I suppose Virtualmin could someday change its response to “You were successful in reaching the site but the password change failed” or “Password change happily completed” and that would break this my version as well, but today it works.)
No warranty is implied.
Ron
SYSTEM INFORMATION | |
---|---|
OS type and version | Ubuntu 24.04.2 |
Virtualmin version | 7.30.8 |