Skip to content

Instantly share code, notes, and snippets.

@oempire
Forked from gmariani/disable_email_forward_hook.php
Last active November 23, 2020 20:35
Show Gist options
  • Save oempire/b45aa73473cbd129ac97e458deeb3192 to your computer and use it in GitHub Desktop.
Save oempire/b45aa73473cbd129ac97e458deeb3192 to your computer and use it in GitHub Desktop.
Disable email forwarding to external domains in cPanel
#!/usr/local/cpanel/3rdparty/bin/php -q
<?php
/**
* @version 1.0.0
* @package Disable Email Forwards
* @author Gabriel Mariani
* @url https://coursevector.com
* @copyright Copyright (c) 2020 CourseVector LLC. All rights reserved.
* @license GNU/GPL license: https://www.gnu.org/copyleft/gpl.html
*/
// file - /usr/local/src/coursevector/disable_email_forward_hook.php
// Save hook action scripts in the /usr/local/cpanel/3rdparty/bin directory.
// Scripts must have root:root ownership and 755 permissions.
// Hook modules execute as part of the cPanel Server daemon (cpsrvd).
// Hook action code as a script cannot access cPanel environment variables.
// https://features.cpanel.net/topic/option-to-prevent-forwarders-to-free-email-accounts
// https://documentation.cpanel.net/display/DD/Guide+to+Standardized+Hooks+-+The+manage_hooks+Utility
// https://documentation.cpanel.net/display/DD/Guide+to+Standardized+Hooks+-+The+describe()+Method
// PHP Log
// /usr/local/cpanel/logs/error_log
// Registered hooks
// /usr/local/cpanel/bin/manage_hooks list
// Toggle debug mode
// Debug Mode option in the Development section of WHM's Tweak Settings (WHM >> Home >> Server Configuration >> Tweak Settings)
// Install
// cd /usr/local/src/coursevector;
// copy file to folder
// chown root:root /usr/local/src/coursevector/disable_email_forward_hook.php;
// chmod 755 /usr/local/src/coursevector/disable_email_forward_hook.php;
// /usr/local/cpanel/bin/manage_hooks add script /usr/local/src/coursevector/disable_email_forward_hook.php
// Uninstall
// /usr/local/cpanel/bin/manage_hooks delete script /usr/local/src/coursevector/disable_email_forward_hook.php
// Embed hook attribute information
function describe()
{
$api2_add_hook = array(
'blocking' => 1,
'category' => 'Cpanel',
'event' => 'Api2::Email::addforward',
'stage' => 'pre',
'hook' => '/usr/local/src/coursevector/disable_email_forward_hook.php --add_api2',
'exectype' => 'script',
);
$uapi_add_hook = array(
'blocking' => 1,
'category' => 'Cpanel',
'event' => 'UAPI::Email::add_forwarder',
'stage' => 'pre',
'hook' => '/usr/local/src/coursevector/disable_email_forward_hook.php --add_uapi',
'exectype' => 'script',
);
return array($api2_add_hook, $uapi_add_hook);
}
// Process data from STDIN
function get_passed_data()
{
// Get input from STDIN
$raw_data = '';
$stdin_fh = fopen('php://stdin', 'r');
if (is_resource($stdin_fh)) {
stream_set_blocking($stdin_fh, 0);
while (($line = fgets($stdin_fh, 1024)) !== false) {
$raw_data .= trim($line);
}
fclose($stdin_fh);
}
// Process and JSON-decode the raw output
if ($raw_data) {
$input_data = json_decode($raw_data, true);
} else {
$input_data = array('context' => array(), 'data' => array(), 'hook' => array());
}
// Return the output
return $input_data;
}
// Cpanel::UAPI::Email::add_forwarder
// We strongly recommend that you use UAPI::Email::add_forwarder instead of Api2::Email::addforward
// https://documentation.cpanel.net/display/DD/UAPI+Functions+-+Email%3A%3Aadd_forwarder
function add_uapi($input = array())
{
//error_log("add_uapi\n");
//error_log(print_r($input, true));
return add($input, 'uapi');
}
// Cpanel::Api2::Email::addforward
// We strongly recommend that you use UAPI::Email::add_forwarder instead of Api2::Email::addforward
// https://documentation.cpanel.net/display/DD/cPanel+API+2+Functions+-+Email%3A%3Aaddforward
function add_api2($input = array())
{
//error_log("add_api2\n");
//error_log(print_r($input, true));
return add($input, 'api2');
}
function add($input, $api_type)
{
$api_function = 'uapi' === $api_type ? 'UAPI::Email::add_forwarder' : 'Api2::Email::addforward';
$input_context = $input['context'];
$input_args = $input['data']['args'];
//$email_from = $input_args['email'];
$email_to = trim($input_args['fwdemail']);
$domain = $input_args['domain'];
$action_api = $input_context['event'];
$action_forward = $input_args['fwdopt'];
// $result = Set success boolean value
// 1 — Success
// 0 — Failure
// $message = This string is a reason for $result.
// To block the hook event on failure, you must set the blocking value to 1
// in the describe() method and include BAILOUT in the failure message. If
// the message does not include BAILOUT, the system will not block the event.
// If forwarding destination does not end in the same domain as the account, deny it.
if ($api_function === $action_api && 'fwd' === $action_forward) {
// Is valid email?
if (filter_var($email_to, FILTER_VALIDATE_EMAIL)) {
// We might echo the domain, so make sure it's clean first
$sanitized_email_to = filter_var($email_to, FILTER_SANITIZE_EMAIL);
// Split on @ and return last value of array (the domain)
$email_to_domain = array_pop(explode('@', $sanitized_email_to));
// Return a boolean if the domain matches
//$result = ($domain === $email_to_domain) ? 1 : 0;
//$message = 0 === $result ? "Forwarding to external domains not allowed, {$domain} is not equal to {$email_to_domain}." : '';
// Populate list of bad domain names
$baddomains = array(
'hotmail.com',
'outlook.com',
'live.com',
'live.com.au',
'hotmail.com.au',
'outlook.com.au'
);
if (in_array($email_to_domain, $baddomains)) {
$result = 0;
$message = "Forwarding to free email services including {$email_to_domain} is currently not supported due to complaints of SPAM emails being forwarded (leading to us being blacklisted as we appear to be spammers). Please forward to an on server email or add it as a new email account and configure outlook.com to check it as an external account.";
}
else {
$result = 1;
$message = '';
}
} else {
// invalid email, fail
$result = 0;
$message = "Invalid email address.";
}
} else {
// we're not filtering: fail, blackhole, pipe, system
$result = 1;
$message = "";
}
// On error, use:
// throw new RuntimeException("BAILOUT $message");
// Return the hook result and message
return array($result, $message);
}
// Any switches passed to this script
$switches = (count($argv) > 1) ? $argv : array();
// Argument evaluation
if (in_array('--describe', $switches)) {
echo json_encode(describe());
exit;
} elseif (in_array('--add_api2', $switches)) {
$input = get_passed_data();
list($result, $message) = add_api2($input);
echo "$result $message";
exit;
} elseif (in_array('--add_uapi', $switches)) {
$input = get_passed_data();
list($result, $message) = add_uapi($input);
echo "$result $message";
exit;
} else {
echo '0 coursevector/disable_email_forward_hook.php needs a valid switch';
exit(1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment