Browse Source

Merge pull request #505 from BotoX/master-crypt

Improve dovecot mail-crypt postpassword script security
pull/509/head
David Goodwin 4 years ago
committed by GitHub
parent
commit
1b8bfc62df
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      ADDITIONS/postfixadmin-mailbox-postpassword.sh
  2. 5
      config.inc.php
  3. 34
      model/Login.php
  4. 36
      model/MailboxHandler.php

11
ADDITIONS/postfixadmin-mailbox-postpassword.sh

@ -3,11 +3,14 @@
# Example script for dovecot mail-crypt-plugin
# https://doc.dovecot.org/configuration_manual/mail_crypt_plugin/
IFS= read -r -d $'\0' OLD_PASSWORD
IFS= read -r -d $'\0' NEW_PASSWORD
# New user
if [ -z "$3" ]; then
doveadm -o plugin/mail_crypt_private_password="$4" mailbox cryptokey generate -u "$1" -U
exit 0
if [ -z "$OLD_PASSWORD" ]; then
OLD_PASSWORD="$(openssl rand -hex 16)"
doveadm -o plugin/mail_crypt_private_password="$OLD_PASSWORD" mailbox cryptokey generate -u "$1" -U
fi
# Password change
doveadm mailbox cryptokey password -u "$1" -o "$3" -n "$4"
printf "%s\n%s\n" "$OLD_PASSWORD" "$NEW_PASSWORD" | doveadm mailbox cryptokey password -u "$1" -N -O ""

5
config.inc.php

@ -600,9 +600,10 @@ $CONF['mailbox_postedit_script'] = '';
$CONF['mailbox_postdeletion_script'] = '';
// Optional: See NOTE above.
// Script to run after setting a mailbox password. (New mailbox [$4 = empty] or change existing password)
// Script to run after setting a mailbox password. (New mailbox [old password = empty] or change existing password)
// Disables changing password without entering old password.
// Parameters: (1) username (2) domain (3) old password (4) new password
// Parameters: (1) username (2) domain
// STDIN: old password + \0 + new password
// $CONF['mailbox_postpassword_script']='sudo -u dovecot /usr/local/bin/postfixadmin-mailbox-postpassword.sh';
$CONF['mailbox_postpassword_script'] = '';

34
model/Login.php

@ -166,15 +166,31 @@ class Login
// If we have a mailbox_postpassword_script (dovecot only?)
$cmdarg1=escapeshellarg($username);
$cmdarg2=escapeshellarg($domain);
$cmdarg3=escapeshellarg($old_password);
$cmdarg4=escapeshellarg($new_password);
$command= "$cmd_pw $cmdarg1 $cmdarg2 $cmdarg3 $cmdarg4";
$retval=0;
$output=array();
$firstline='';
$firstline=exec($command, $output, $retval);
// Use proc_open call to avoid safe_mode problems and to prevent showing plain password in process table
$spec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
);
$cmdarg1 = escapeshellarg($username);
$cmdarg2 = escapeshellarg($domain);
$command = "$cmd_pw $cmdarg1 $cmdarg2 2>&1";
$proc = proc_open($command, $spec, $pipes);
if (!$proc) {
throw new \Exception("can't proc_open $cmd_pw");
}
// Write passwords through pipe to command stdin -- provide old password, then new password.
fwrite($pipes[0], $old_password . "\0", 1+strlen($old_password));
fwrite($pipes[0], $new_password . "\0", 1+strlen($new_password));
$output = stream_get_contents($pipes[1]);
fclose($pipes[0]);
fclose($pipes[1]);
$retval = proc_close($proc);
if (0 != $retval) {
error_log("Running $command yielded return value=$retval, output was: " . json_encode($output));
throw new \Exception($warnmsg_pw);

36
model/MailboxHandler.php

@ -650,17 +650,35 @@ class MailboxHandler extends PFAHandler
}
if (!empty($cmd_pw)) {
$cmdarg3='""';
$cmdarg4=escapeshellarg($this->values['password']);
$command= "$cmd_pw $cmdarg1 $cmdarg2 $cmdarg3 $cmdarg4";
$retval=0;
$output=array();
$firstline='';
$firstline=exec($command, $output, $retval);
if (0!=$retval) {
error_log("Running $command yielded return value=$retval, first line of output=$firstline");
// Use proc_open call to avoid safe_mode problems and to prevent showing plain password in process table
$spec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
);
$command = "$cmd_pw $cmdarg1 $cmdarg2 2>&1";
$proc = proc_open($command, $spec, $pipes);
if (!$proc) {
error_log("can't proc_open $cmd_pw");
$this->errormsg[] .= $warnmsg_pw;
$status = false;
} else {
// Write passwords through pipe to command stdin -- provide old password, then new password.
fwrite($pipes[0], "\0", 1);
fwrite($pipes[0], $this->values['password'] . "\0", 1+strlen($this->values['password']));
$output = stream_get_contents($pipes[1]);
fclose($pipes[0]);
fclose($pipes[1]);
$retval = proc_close($proc);
if (0!=$retval) {
error_log("Running $command yielded return value=$retval, output was: " . json_encode($output));
$this->errormsg[] .= $warnmsg_pw;
$status = false;
}
}
}

Loading…
Cancel
Save