Function Hooks
Note: Information about parsing XML data can be found
here.
Introduction
Function hooks allow one to automatically perform actions after an API1 or API2 function is executed. This works by running a script inside of
/usr/local/cpanel/hooks/ and sending XML data to the function hook script's
STDIN.
One of the most important advantages to function hook scripts is that they can be written in any language. These scripts are run as the
root user and are generally easier to write than
CustomEventHandlers.
Note: Unlike CustomEventHandlers, function hooks
cannot be used for denying or modifying cPanel events.
Stub files for function hooks exist inside of
/usr/local/cpanel/hooks/. These all contain the
.example extension in order to prevent their execution. A function hook's filename should never contain an actual extension.
To create a function hook, you will need to place a script in the following location:
/usr/local/cpanel/hooks/$module/$function
- For example, to create a hook for
Email:listpopswithdisk, place a script or binary at /usr/local/cpanel/hooks/Email/listpopswithdisk
-
Remember: This script will be called automatically whenever that API function is called.
-
Note: cPanel function hooks will be run as the root user. These scripts should have file permissions set to 700 and follow strong security practices.
Important: In order for the function hook to take effect, you will need to run the following script:
/usr/local/cpanel/bin/register_hooks. Only hooks with valid permissions are registered. You must run
register_hooks anytime you modify a hook's permissions.
Usage
cPanel function hooks operate by sending data to the
STDIN (standard input) of a script with a predefined name. There are 2 sections included with the input sent to the function hook script:
- Parameters passed to the API call (cpanelevent).
- The
CPUSER data.
A basic example of this input can be seen below in the output for an
addpop script:
Show Hide
<xml><cpanelevent>
<errors></errors>
<event>addpop</event>
<module>email</module>
<params>
<param0>emailuser</param0>
<param1>emailpassword</param1>
<param2>250</param2>
<param3>testdomain.com</param3>
</params>
</cpanelevent>
<CPDATA>
<BWLIMIT>unlimited</BWLIMIT>
<CONTACTEMAIL></CONTACTEMAIL>
<CONTACTEMAIL2></CONTACTEMAIL2>
<DEMO>0</DEMO>
<DOMAIN>testdomain.com</DOMAIN>
<FEATURELIST>default</FEATURELIST>
<HASCGI>1</HASCGI>
<IP>192.168.1.1 </IP>
<LANG>english</LANG>
<MAXADDON>100</MAXADDON>
<MAXFTP>100</MAXFTP>
<MAXLST>100</MAXLST>
<MAXMONGREL>4</MAXMONGREL>
<MAXPARK>100</MAXPARK>
<MAXPOP>unlimited</MAXPOP>
<MAXSQL>100</MAXSQL>
<MAXSUB>100</MAXSUB>
<OWNER>root</OWNER>
<PLAN>default</PLAN>
<RS>x3</RS>
<STARTDATE>1244646861</STARTDATE>
<USER>testdoma</USER>
</CPDATA>
</xml>
You can see in the example above that there are 2 sets of results contained within the data sent to the function hook. The first is contained within the cpanelevent container. This data is passed to the API.
The second set of data, contained within the
<CPDATA> tags, corresponds to the information contained within
/var/cpanel/users/__USERNAME__. Here, you can find information you may need about the user running the API call.
Data inside these tags will be HTML-escaped. While most XML parsers (such as
XML::Simple) automatically decode the escape, you may need to use one of the following tools:
- PHP —
html_entity_decode can be found here.
- Perl —
HTML::Entities::decode_entities can be found here.
A note about function hooks
Function hooks should
not produce any output. Any output printed to STDOUT will be returned prior to the response of the calling function. This will result in a mal-formed response. You will need to silence any header content generated by your script's interpreter.
Reading input from STDIN
PHP
Show Hide
Reading input from
STDIN in PHP is never done through a CGI application. You will need to treat it as a CLI application by adding the following shebang line at the top of the script:
#!/usr/bin/php-cgi -q
After the shebang, you will need to open
STDIN for writing so that you can add and manipulate data contained within a variable. This is usually accomplished by looping
fgets on the file opened to store data from
STDIN, like so:
<?php
$stdin_fh = fopen('php://stdin', 'r');
while ($line = fgets( $stdin_fh )) {
$xml_string .= $line;
}
fclose($stdin_fh);
?>
Perl
Show Hide
Reading data from
STDIN in Perl is easier than PHP, as Perl is a native shell-scripting language. To read from
STDIN, we simply loop over the
<STDIN> container and assign the data contained within to variables, like so:
my $xml_string;
while(<STDIN>) {
$xml_string .= $_;
}
Perl example
The following example will create a log at
/root/email_password_log of all new email accounts and their passwords. It should be noted that this type of script should never be used in a "live" environment.
Download Example
use strict;
use warnings;
use XML::Simple;
use Data::Dumper;
my $xml;
while (<STDIN>) {
$xml .= $_;
}
my $xml_hashed = XMLin($xml);
my $username = $xml_hashed->{'cpanelevent'}->{'params'}->{'email'} . '@' . $xml_hashed->{'cpanelevent'}->{'params'}->{'domain'};
my $password = $xml_hashed->{'cpanelevent'}->{'params'}->{'password'};
open(my $fh, ">>", "/root/email_password_log");
print {$fh} "Email Account Created:\n";
print {$fh} "\tusername: $username\n";
print {$fh} "\tpassword: $password\n\n";
close($fh);