All about API
Using an API: Starting point
DirectAdmin has a feature-set which allows you to control almost everything you can via a browser, but using socket based scripts instead. This is called an "API".
There are hundreds of possible API commands. Essentially, anything you can do normally in a browser, you can also do with the API. Just swap CMD_name to CMD_API_name (replace "name" with whatever the browser had), and use the same variables as the browser does running directadmin in debug mode ). Search for that CMD_API_name value in the Versions System for more information.
Starting point and main API documentation:
http://www.directadmin.com/api.html
Php communication class:
http://forum.directadmin.com/threads/258
Some API command are listed in the api.html page above, but most only exist in the versions system:
http://www.directadmin.com/search_versions.php?query=CMD_API
More examples:
http://www.directadmin.com/sample_api.txt
http://files.directadmin.com/services/all/httpsocket/examples/
You can pass valid JSON into the POST parameter when using the API if you prefer JSON over url-encoded data.
Also, we recommend creating a "Login Key" for any permanent API login values so you can restrict that key to login only from certain IPs and to allow access to only the certain CMD_API calls that you specify.
The "key" is just a different password for a user. The same username is used with the key that is normally used with the password. So, if you normally log in as fred, then the username will still be fred, but you'll use the key instead of the password to authenticate.
Creating a Login Key
Multiple Levels of security are mandatory these days. A single password is only 1 level, and if lost or stolen, an attacker would be able to login if there are no other levels of security. If you need to give out your DirectAdmin password for any reason, either for an API script, or even to a remote tech, it's best not to hand out your true password.
DirectAdmin has a feature called Login Keys which allows you to have multiple other passwords for your DirectAdmin account, and these other passwords can be set with heavy restrictions. These include:
- Number of CMD_ requests can be limited to a specific number, or unlimited.
- Login Key can be set to expire at a certain time
- Key can be deleted after expiry or after all requests are used.
- Key can be set to not allow HTM_, IMG_ or CSS_ requests, making it very difficult to use DA with a browser.
- Ability to restrict the key to a limited number of commands (CMD_*) or Level groupings.
- Key can be set to only allow specific IPs or simple ranges (1.2.3.4-5)
To create your own Login Key, first log in to DirectAdmin as the user the key is for, e.g., "admin".
- Browse to the Login Keys page User Level -> Login Keys . If you don't yet have any domains created, then you can manually access the page via this URL:
/CMD_LOGIN_KEYS
Click "Create new Login Key" to get started with a new key.
Enter all fields as needed.
- You'll need to specify a Key Name. Note that this is only for your own tracking purposes, it will not be the username for the login. Your current DirectAdmin username will still be used, along with the key as the password.
- Specify a Key Value, or use the random button for a longer value. The text will be shown to your when the key is created.
- Expiry can be set if you only want this key to be temporary.
- You can specify the Number of Uses if you only want the given key to be valid for a certain number of requests. For long-term APIs, you'd use 0 for unlimited.
- The Clear Key option will typically only be used with temporary keys, and is handy for temporary tech logins and such so that you don't need to worry about forgetting to disable the key after its expiry is passed (or all "uses" are consumed).
- The Allow HTM option is only used if this key is going to be used for a person to log in with a browser. API keys should not have this option enabled.
- Commands will let you specify which CMD_ or CMD_API_ calls are allowed to be used with this key. This will depend on what your key needs. If you are creating this key for an API/script, then you'd want to limit it to the smallest set of CMD_API commands you can. Contact the author of the script to find out which commands the script needs. Restricting the commands allowed will make the key significantly more secure by vastly limiting the damage an attacker could cause since their privileges are limited to only those commands listed.
- Remember that the commands ALL_USER, CMD_LOGIN_KEYS, or CMD_API_LOGIN_KEYS all allow access to the Login Keys for this, meaning that with this access, they can change the keys, which defeats the purpose, so make sure that you select your list of commands carefully.
- The Allowed IPs options lets you limit which IPs can connect with this key, one entry per line. You can specify a simple IP range such as 1.2.3.4-6.
- When testing your Login Key, it's often useful to run DA in debug mode, level 2000, which will have DA tell you why a login is being rejected.
Login Key Examples
A) Power Reseller
Although this has not be tested, in theory, you can create a 2nd Admin account, and only allow them these commands:
All_RESELLER
ALL_USER
CMD_ACCOUNT_RESELLER
CMD_RESELLER_SHOW
and deny these commands:
CMD_LOGIN_KEYS
CMD_API_LOGIN_KEYS
CMD_PASSWD
Also, set the key with these attributes enabled: Never expires, unlimited uses, clear key disabled, and allow HTM. This will give someone a Reseller Account, plus some Admin privileges. Note that this is not fool-proof. There are overlapping commands that would still allow them to delete an Admin account or change their true password (via non-obvious means), so you would still need a certain degree of trust of this account. However, it would be useful to help prevent accidents/errors by that account.
B) User Level API to create/manage email accounts
As this is a script, it will never expire, will have unlimited uses, we don't need "clear key", and "allow htm" is not required. The list of commands should only need to be:
CMD_API_POP
CMD_API_EMAIL_VACATION
and lastly, the IP field should contain just 1 IP, which is the IP that will connect to DA from the script. If the script is local, you'd specify 127.0.0.1. If your connecting from a remote server, you'd enter the main IP of the remote server.
C) DNS Clustering with the Multi Server Setup
DA only needs a small set of commands to control the DNS on a remote box. The "allow" list would be as follows:
CMD_API_DNS_ADMIN
CMD_API_LOGIN_TEST
CMD_API_USER_EXISTS
and you can set the IP of the remote box that needs to connect to this slave, as nobody else should be connecting with this key other than the master.
D) Key for Technical Support
If access to your server is requested, instead of providing the true admin password, you could provide a full-access Login Key instead. For this, use any key name (e.g., "support"), a random password (use the generator button), set an Expiry to say 5 days in the future (however long you thing it will be needed), Uses=0, Clear Key = yes, Allow HTM = yes, and enter the current admin password at the bottom. It can be restricted to an IP, but if different techs may be logging in, it's simplest to allow any.
Simple API request using CURL
If you want to make an API call from a script or shell, without using a more complicated class, curl can do it for you. Here is a sample request to make an API request to DA, requesting the details of package unlimited.
Command:
Data:
IP:
Port:
Ssl:
Method:
User:
Password:
The command to use in console is as follows:
curl --request "POST" --user 'admin:123' --data 'package=newpackage' "https://127.0.0.1:2222/CMD_API_PACKAGES_USER"
Command line key/URL generation for CLI API calls.
If you have a script/tool that needs to use DA, you'll make a binary call to generate a login key. This key will be passed to curl/API, generated on the fly if needed.
eg: 2 new calls: 1) da api-url --user=fred
which generates output: https://fred:password@hostname:2222
where password is replaced with the actual password that should be used.
da api-url
generates: https://admin:password@hostname:2222
You'd be able to use it like this:
curl -k -X -u "$(da api-url --user=fred)/CMD_API_USERS?json=yes"
The generated key will be temporary thus the da api-url
calls must be ran for each attempt.
Why my API script is not working
If you're trying to post some data to DirectAdmin with the API, but are not getting the desired results, rather than trying to figure out what's wrong with your script, it's usually easier to be shown what you're passing and what should be passed.
To do this, run DirectAdmin in debug mode, with the
| grep string
option. This will show you what's being passed.Then test the function you want with your browser normally through DA (without your script). The posted data will be shown in the debug output. Log the POST parameters passed and their syntax so that you may emulate this data in your own script as desired.
Lastly, test the function using your API script. Again, the data being passed will be shown. Compare the output generated from your script with the output generated from the browser. Adjust your script to match, and it should work.
Notes
- You can only show CMD_* class in the output by setting
./directadmin set debug_only_cmd 1
- DA binaries compiled after April 1, 2020 can use debug level exactly 188 to show only the request information.
How to auto-login from an external site
If an external site should redirect the client to DirectAdmin, but you don't want the account to enter a user/pass for this redirection, you can create a hidden form, and use JavaScript to submit it automatically.
A sample auto-submission form, to be generated in a temporary HTML code:
<form action="http://www.domain.com:2222/CMD_LOGIN" method="POST" name="form">
<input type=hidden name=referer value="/">
<input type=hidden name=FAIL_URL value="http://www.domain.com/login_failed.html">
<input type=hidden name=LOGOUT_URL value="http://www.domain.com/logged_out.html">
<input type=hidden name=username value="username">
<input type=hidden name=password value="password">
</form>
<script>
document.form.submit();
</script>
As you may have noticed, the plain-text password is set in the form, so it might be more secure to leave the value blank, and try and set the value via ajax, or some dynamic option, and/or specify that this page must not be cached by the browser so it cannot be retrieved from disk later on.
A better option would be to preset a short-term use Login Keys, just for this client's IP address. It would expire after a certain amount of time, and only allow this client's IP to login with it. Much more secure.
Use the created Login Key for the password, along with this account's usual username (not the login key name).
How to change the password for all users
If, for whatever reason, you wish to change the password for all of your many DA accounts, and there are too many to do manually, you can use the following script to change the password.
- Prepare the scripts:
cd /root
wget -O change_pass.php http://files.directadmin.com/services/all/httpsocket/examples/example.change_pass.php
wget http://files.directadmin.com/services/all/httpsocket/httpsocket.php
chmod 700 change_pass.php
Edit the file change_pass.php and set the $server_pass value to your admin password value. Also, if you're running DA with https (SSL), set $server_ssl="Y" .
With these in place, you can change user passwords one at a time, like this:
./change_pass.php username "password"
where username is the name of the DA User account, and password is the password the User will be set to. It's important to use the API or DA to change User passwords, because DA updates many locations (system, ftp, email, database), which the "passwd" command does not do.
- Now, to make the above script work on all of your accounts automatically, we'll create another script. Create the file
/root/change_all_user_pass.sh
with the code inside:
#!/bin/sh
ADMIN_USER=admin
for i in `ls /usr/local/directadmin/data/users`; do
{
if [ "$i" = "$ADMIN_USER" ]; then
continue;
fi
PASSWORD=`tr -cd '[:alnum:]' < /dev/urandom | fold -w22 | head -n1`
./change_pass.php $i "$PASSWORD"
};
done;
exit 0;
The above code will generate random password of 22 symbols.
If you wish for all User accounts to be set to the same password, then set the PASSWORD= value to that single desired password. Note that the admin account (set to ADMIN_USER) will be skipped, as the change_pass.php script needs to have a correct password all the time.
Save/exit.
- Run the script:
chmod 755 /root/change_all_user_pass.sh
/root/change_all_user_pass.sh
How to create an account when only the crypted password is known
This is useful when creating an account with an API, for a restore, when the plain-text password is not known, for example.
When creating a User with one of the following commands:
CMD_API_ACCOUNT_USER
CMD_ACCOUNT_USER
CMD_API_ACCOUNT_RESELLER
CMD_ACCOUNT_RESELLER
CMD_API_ACCOUNT_ADMIN
CMD_ACCOUNT_ADMIN
and passing the "passwd" field, if you also set:
passwd_is_crypted=1
this will allow you to set:
passwd=$some$cryptedpass
during the account creation, thus allowing you to create the User using the crypted password.
How to change an email password without logging in
If you would like your pop users to be able to change their own email passwords without having to log in to the control panel, simply give them this link:
http://www.domain.com:2222/CMD_CHANGE_EMAIL_PASSWORD
Where www.domain.com is either your domain, hostname, or IP address.
More information on this function and how you can use it via API can be found Here.
There is also a DA plugin that also gives email users the ability to change their passwords and vacation messages, and show them their email stats, all in once place:
https://forum.directadmin.com/threads/22715
For automated vacation message changes by email users, it can be implemented via API here, or just use the plugin above:
https://forum.directadmin.com/threads/13112
How to run command X from DirectAdmin API
We get many emails about how to run certain commands that are run with a browser, to be run through the API.
For most cases, the API command does already exist. Searching the Versions System is the best place to start with regards to that.
However, not all cases have specific CMD_API documentation.
Since the CMD_API_X commands are almost always exactly the same as the CMD_X commands (minus the command name and output), the simplest way to figure out what variables you need to pass would be to run DA in debug mode and use the very last:
| grep string
The | grep string
option will filter the large amounts of debug output and only show you what variables are being passed.
Once DA is running in debug mode with the | grep string
option, you can then go into your browser, log in to DA and submit the function of DA that you'd like to use in your API. After you post the command you're looking for, you'll notice output in your console that has variables. These are the variables that you'll need for the CMD_API_X version of the CMD_X command you just ran.
Take these variables, add them into your API script, and see if it works.
A good PHP URL decoder for API testing
This is the PHP code that our developers use to test all new API output:
<html>
<head>
<title>url decode</title>
<style>
pre {
margin: 0px;
}
div {
border: 1px solid #d9d9d9;
}
</style>
</head>
<?php
$str_s='';
if (isset($_POST['str']))
$str_s=$_POST['str'];
$sub_array = true;
if ($str_s!='' && !(isset($_POST['sub_array']) && $_POST['sub_array'] == 'yes'))
$sub_array = false;
?>
<form action='?' method=POST>
<textarea name=str cols=120 rows=10><?php
echo html_char($str_s);
?>
</textarea>
<input type=checkbox name='sub_array' value='yes' <?php if ($sub_array) echo 'checked';?>> Contains multi-level URL encoding<br>
<input type=submit>
</form><br><br>
<?php
show_enc($str_s);
function show_enc($str2, $tab=0)
{
global $sub_array;
$c = "style='margin-left: ".(($tab+1)*20)."px'";
echo "<div $c>";
parse_str($str2, $output);
foreach ($output as $key => $value)
{
echo "<pre><b>".html_char(urldecode($key))."</b> = ";
if ($sub_array && strpos($value, '=') !== false)
show_enc($value, $tab+1);
else
echo html_char(urldecode($value));
echo "</pre>";
}
echo "</div>\n";
}
function html_char($str)
{
$h = htmlspecialchars(stripslashes($str), ENT_QUOTES | ENT_HTML401);
if ($h == '' && $str != '')
return htmlspecialchars(utf8_encode(stripslashes($str)), ENT_QUOTES | ENT_HTML401);
else
return $h;
}
?>
</html>
If you need to decode a list similar to:
list[]=value1&list[]=value2&list[]=value3&list[]=value4
then use something similar to this:
$str="list[]=value1&list[]=value2&list[]=value3&list[]=value4";
$a = explode('&', $str);
$values = Array();
$i=0;
foreach ($a as $v)
{
$values[$i++] = substr(strstr($v, '='), 1);
}
print_r($values);
API for Verifying a User Exists
When called by an Admin, CMD_API_USER_EXISTS
will return exists=1
or exists=0
if the account exists for any account type (Admin, Reseller, or User).error=1|0
is also returned. If error=1
, then text=
will be set to the reason for the error.