Version 1.61.0
Released: 2020-05-20
new
Plugins can be package items(BETA)
The plugin manager will have the ability to enable/disable each plugin in the package system.
All plugins will be enabled by default, and only shut off on a per-user basis if they're set as such by the system.
A disabled plugin will not be able to run through CMD_PLUGINS/CMD_PLUGINS_ADMIN/CMD_PLUGINS_RESELLER
PACKAGES / USER.CONF
plugins_allow=plug1:plug2
plugins_deny=plug3:plug4
If both plugins_allow and plugins_deny are absent from a package, all plugins can run.
If plugins_allow exists (even if it's blank), the plugin must be present in order to run ("plugins_allow=" will block any plugin from running)
If plugins_deny exists, any plugin listed will be denied.
Having both plugins_allow and plugins_deny has no purpose, as plugins_allow will be the 100% deciding factor.
To clear a plugin for a given list pass [clear] to the value, eg:
plugins_allow=[clear]
and/or
plugins_deny=[clear]
will delete the given variables from the package/user.conf.
Again, setting "plugins_allow=" to an empty value does not delete the variable, it simply sets it as blank, thus no plugins can run.
Saving a package or user.conf change without passing the plugins_allow (or plugins_deny) will have no effect on the value currently set (in case some skins don't support it)
JSON
The packages pages, and listing of User settings will include an array, example:
CMD_SHOW_USER_PACKAGE?package=dnsonly&json=yes
"plugins":
{
"all_plugins":
{
"custombuild": "custombuild",
"hello_world": "hello_world"
},
"plugins_deny" :
[
"hello_world"
]
},
The right-side values in "all_plugins" will eventually be swapped for translatable strings, so please use the right-side value for display, and left-side index for passing to DA.
EVO1873
new
ECC ssl certificates (SKINS)Support for ECDSA (Elliptic Curve Digital Signature Algorithm) certificates for smaller key sizes and improved security.
New internal default:
ecc_certificates=1
where, if you wish to prevent Users from creating ECC certs, run:
cd /usr/local/directadmin
./directadmin set ecc_certificates 0
service directadmin restart
POST
The calls to CMD_SSL are unaffected.
However, anywhere you can pass:
keysize=2048
keysize=4096
you can now also pass any of:
keysize=prime256v1
keysize=secp384r1
keysize=secp521r1
SKINS:
Enhanced: user/ssl.html
Swapped out the "keysize" select-box with |KEYSIZE|
LETSENCRYPT
Since the letsencrypt.sh creates it's own keys, the new ECC key creation code will need to be run there.
To tell LE that we're trying to create an ECC cert, the provided san_config file will have it's usually (non-used) value:
default_keyfile = keyfile.pem
changed to:
default_keyfile = secp521r1.pem
or whichever new keysize algorithm is being requested.
JSON
The extra key-sizes are included in the new output, so this is backwards compatible (assuming your skin is ok without numbers)
"key_sizes":
{
"2048": "",
"4096": "",
"prime256v1": "",
"secp384r1": "select",
"secp521r1": ""
}
However, a sibling array has been added in the same output, providing the standard "JSON Select" output, which includes nice name values:
CMD_SSL?domain=domain.com&json=yes
"keysize_select":
{
"0":
{
"text": "2048-bit",
"value": "2048"
},
"1":
{
"text": "4096-bit",
"value": "4096"
},
"2":
{
"text": " X9.62/SECG curve over a 256 bit prime field",
"value": "prime256v1"
},
"3":
{
"selected": "yes",
"text": " NIST/SECG curve over a 384 bit prime field",
"value": "secp384r1"
},
"4":
{
"text": " NIST/SECG curve over a 521 bit prime field",
"value": "secp521r1"
}
}
EVO1851
new
IP type global, for global shared spanning multiple resellers (SKINS)(BEHAVIOR)New IP option for a shared IP: global=yes
This will be set by the Admin in the Admin Level -> IP Manager for a given "shared" IP, so allow multiple Resellers to use it.
Once an IP is global, it can then be assigned to multiple Resellers, and will be treated as a shared IP.
Accessing the IP directly should go to the Admin's shared area, rather than the Reseller's shared area.
Replaces this guide:
https://help.directadmin.com/item.php?id=538
The Reseller Level -> IP Manager will always hide the User count for global shared IPs.
The "Remove from Reseller" button will remove any global shared IP from all Reseller/Admin ip.list files,
but as before, does require the value to be 0 prior to DA allowing removal.
Setting a "status=free" IP to be global from the details page will automatically assign this IP to the current Admin, and convert the status to shared.
IMPORTANT BEHAVIOR CHANGE
*** You can now remove the server IP from a Reseller ***
Admin Level -> IP Manager
When you select the server IP checkbox, if you previously clicked "Free from Reseller", it would throw an error.
The change is that this button is now allowed and DA will use the current drop-down Reseller selector to know which reseller to remove the server IP from.
POST
To save changes, you can either use:
CMD_IP_MANAGER_DETAILS
method: POST
action=global
ip=1.2.3.4
global=yes|no #ABSENCE of global=* counts as no, since it's a checkbox.
OR
CMD_IP_MANAGER
method: POST
action=select
set_global=<any text>
select0=1.2.3.4
(select1=1.2.3.5)
global=yes|no #DIFFERENT FROM ABOVE in that absence of global implies yes.
You can pass global=no if you want to set it to no for the selected IPs. Enhanced does not do this.
JSON
When viewing the details of an IP:
CMD_IP_MANAGER_DETAILS?ip=1.2.3.4&json=yes
if set, there will be:
"global": "yes"
the global value might not be present, which can be assumed set to "no".
If "yes", then there could be multiple Resellers/Admins managing this IP.
For ALL loads of the details of the IP, of any status, DA will scan all Reseller/Admin ip.list files to see who has this IP listed.
This array will be shown as:
"resellers_with_ip":
[
"admin"
],
this is mainly only for informational purposes, but can be handy in case the IP value is more than 0 and you're not sure who's on it (although the Show All Users page would be a giveaway)
SKINS
admin/ip_manager_details.html
Add form:
|?GLOBAL_CHECKED=|
|*if global="yes"|
|?GLOBAL_CHECKED=checked|
|*endif|
|?SHOW_GLBOAL=no|
|*if status="shared"|
|?SHOW_GLBOAL=yes|
|*endif|
|*if status="free"|
|?SHOW_GLBOAL=yes|
|*endif|
|*if SHOW_GLBOAL="yes"|
<tr><td class=list_alt>|LANG_GLOBAL|</td><td class=list_alt>
<form class='mb0' action='CMD_IP_MANAGER_DETAILS' method='POST'>
<input type='hidden' name='action' value='global'>
<input type='hidden' name='ip' value='|ip|'>
<input type='checkbox' name='global' value='yes' |GLOBAL_CHECKED|> When enabled, this IP can be used by multiple Resellers
<input type='submit' value='|LANG_SAVE|' class='float_right'>
</form>
</td></tr>
|*endif|
T25483
EVO1858
new
Direct CSF integrationDirectAdmin already supports the CSF plugin, and already integrates with it using the block_ip.sh set of scripts.
This feature will skip over the hook scripts, and instead make direct calls to csf.
Block:
csf -d 1.2.3.4
Unblock:
csf -dr 1.2.3.4
And get list of currently blocked IPs directly from CSF.
/etc/csf/csf.deny
Optional comments to be set.
ACTIVATE
The csf plugin must be installed
The /usr/local/directadmin/scripts/custom/block_ip.sh must NOT exist (so as to not affect existing CSF integrations).
Once you have this copy of DA, to flip over to this integration, delete the files;
/usr/local/directadmin/scripts/custom/block_ip.sh
/usr/local/directadmin/scripts/custom/brute_force_notice_ip.sh
/usr/local/directadmin/scripts/custom/show_blocked_ips.sh
/usr/local/directadmin/scripts/custom/unblock_ip.sh
After testing confirms feature is functional, the csf_install.sh script will be updated to not install the scripts/custom/*.sh files.
BLOCKED LIST
The BFM will use the /etc/csf/csf.deny to show the listing of blocked IPs and comments/dates.
The following files will not be related to the new method;
/root/blocked_ips.txt
/root/exempt_ips.txt
SKIP LIST
CSF does have it's own skip list.
The Brute Force Manager also has it's own skip list:
/usr/local/directadmin/data/admin/brute_skip.list
With integration, when adding an IP to the skip list through the BFM, DA will add it to both brute_skip.list and to CSF's csf.ignore.
Adding ranges in the format: 1.2.3.4-5 will only be added to the BFM.
DA will not accept 1.2.3.0/24, but CSF will.
Adding the 1.2.3.0/24 style ranges should be done in CSF, as even if DA decides to try and block an IP, the CSF csf.ignore would override the block, so the CSF allow has priority.
Listing all Skip value in DA will show the contents of both lists.
Deleting a value from DA ONLY deletes it from the skip.list, not from CSF's allow list (the value would remain showing).
There is room for improvement here, so it may come should there be sufficient demand.
T26468
Update: changed from csf.allow to csf.ignore:
Compile time: May 7 2020 at 18:04:30
new
Default Change: crypt_method=6All new binaries from now will use the internal default crypt_method=6 value.
If needed, you can set this back to 1 for the older $1$ crypt format, but where possible, $6$ is preferred.
new
Default Change: systemd=-1The internal default systemd variable will now be set to -1.
If you have a systemd value already physically set in your directadmin.conf, this set value will be used instead.
The systemd=-1 value will have DA auto-decide which setting to use, logic being:
if (systemd == -1)
{
if (pathExists("/etc/systemd/system") && (pathExists("/bin/systemctl") || pathExists("/usr/bin/systemctl")))
systemd = 1;//systemd
else
systemd = 0;//init.d
}
The Linux static 64-bit binaries were already using systemd=-1 as the default, now all binaries will use it.
new
File Manager Delete to Trash instead of immediate removal (SKINS)New File Manager feature that moves files/folders to the ~/.trash directory when deleted, rather than immediately removing them from disk.
The related filemanager_disable_features number for "trash" is 65536.
"fm_settings" will now include:
"trash": "1"
"trash": "0"
depending if the feature is enabled or not.
New directadmin.conf option, internal default:
fm_purge_trash_days=30
which indicates the age of days a file before being deleted.
For folders, the last modified time of a folder must be >= 30 days old for it to be traversed.
Valid values:
-1 never auto-purge
0, immediately purge if found
up to a max of 10000 days before being purged.
TO TRASH
When deleting a file/folder, if the "trash=yes" option is included, the item will be move from /some/path.txt to /.trash/files//path.txt
This will follow the freedestop.org trash specification: https://specifications.freedesktop.org/trash-spec/trashspec-1.0.html
If there is a duplicate file in .trash/files/path.txt, the trash file is instead moved to .trash/files/path.txt.1
A related info file will be created in .trash/info/path.txt.trashinfo or (.trash/info/path.txt.1.trashinfo depending on how it was saved).
The info file contains the Path and DeletionDate, which points to the original location (excludng any .1), and when it was deleted.
Similar behavior for directories, where deleting a dir to trash moves it to .trash/files/dir or .trash/files/dir.1 if it already exists.
Each delete-to-trash operation creates it's own instance. Deleting the same file over and over again creates a new copy, each of which can be restored.
When viewing /.trash in the Filemanager, DA will not show you what's actually there, but the listing of "Path" items file/dir names from the .trashinfo file.
There may be duplicates here.
RESTORE
Restoring the /.trash/files/* data simply renames it to where it came from.
If any parent folder is missing, the path will be created as 755.
The value given to DA to do the restore MUST be the /.trash/files/file.txt.1 path, and not the "visible" /.trash/file.txt, as that does not exist.
DA needs to reference the data file, which does not always match the original filename, as there may be duplicates.
Per file can be:
CMD_FILE_MANAGER/.trash/files/file.txt.1?action=restore
For mass restore, very similar to the POST Delete button in the Filemanager, except you can pass:
restore=<anytext>
or
button=restore
along with each select0=/.trash/files/file.txt you want to restore, and "path=/.trash"
AUTO-DELETE
Any tally, "all" or per-User, which affects disk usage, eg:
action=tally&value=all
action=tally&value=fred&type=user|reseller
action=quotatally&value=all
action=quotatally&value=fred=all&type=user|reseller
will run the fully trash clean on either all Users (value=all) or on just that User (value=fred&type=user|reseller) PRIOR to running the repquota dump.
This means that the trash is cleared before DA reads the total disk usage used, so usage shown is kept correct.
TASK QUEUE
echo 'action=delete&value=trash' >> /usr/local/directadmin/data/task.queue
echo 'action=delete&value=trash&username=fred' >> /usr/local/directadmin/data/task.queue
JSON
the fm_settings and api_flags per-file will include new info for "trash=0|1".
The api_flags for a given file will let you know if that file is in the trash, so if it should have a "restore" button beside it.
The mask for trash is:
#define FM_F_TRASH 65536
which can be used both with filemanager_disable_features but also binary-added into the api_flags.
The call to:
CMD_FILE_MANAGER?json=yes&action=json_all&path=%2F.trash&ipp=50
is "fake" in that is returns, for example (a directory called "delete"),
where the index is what should be shown, but the "truepath" is where all actions and restores should be sent from.
So the restore must use the truepath, not the index.
{
"/.trash/delete":
{
"api_flags": "65542",
"date": "1589524902",
"gid": "evoboss",
"islink": "0",
"linkpath": "",
"name": "delete",
"permission": "775",
"showsize": "8.00k",
"size": "8192",
"truepath": "/.trash/files/delete",
"uid": "evoboss",
"type": "directory",
"mtime": "1589524873",
"atime": "1589524902",
"sub_directories": "-1",
"files": "0"
}
,"/.trash/delete.1":
{
"api_flags": "65542",
"date": "1589525934",
"gid": "evoboss",
"islink": "0",
"linkpath": "",
"name": "delete.1",
"permission": "775",
"showsize": "8.00k",
"size": "8192",
"truepath": "/.trash/files/delete.1",
"uid": "evoboss",
"type": "directory",
"mtime": "1589524873",
"atime": "1589525935",
"sub_directories": "-1",
"files": "0"
}
...
Also, we should only show the "restore" button for the files/foldres in the /.trash listing.
Assuming the truepath is used to navigate into delete directories (which is allowed), then should not see a restore button on, for example:
/.trash/files/delete/test.html
but they can delete the test.html, should they wish to clear it from the trash ahead of time. (use the truepath, but here it should match).
The items in the listing of /.trash should also have a delete button, where DA will notice is a trash-deleted-item, and will also cleanup the /.trash/info/delete.trashinfo file as well.
SKINS
Enhanced/Power User:
New IMG_TRASH icon for the /.trash directory.
img/trash.png
EVO1844
T26527
new
Ability to disable Custom Httpd syntax checkingIt was found that an openlitespeed box with nearly 7000 domain (plus sub-domains), the syntax check call:
/usr/local/lsws/bin/openlitespeed -t
was taking upwards of 30 seconds.
New internal default option for the directadmin.conf:
custom_httpd_syntax_check=1
where you can disable the syntax check when viewing the custom tokens for a give domain, by running:
cd /usr/local/directadmin
./directadmin set custom_httpd_syntax_check 0
service directadmin restart
T24717
new
Option to include PID in each log entrySometimes trying to step through the logs can be confusing if there are multiple processes logging at the same time.
This option includes the PID number as [12345] to each log, just after the timestamp.
Internal directadmin.conf default:
pid_to_logs=0
to enable:
cd /usr/local/directadmin
./directadmin set pid_to_logs 1
service directadmin restart
T22739
new
Custom Domain Items: admin_restore_only=yes|no so Users cannot set a value via restoreThe Custom Domain Items feature:
Custom Domain Items (SKINS)(LANG)
now has a new option which can be added to any value inside:
/usr/local/directadmin/data/admin/custom_domain_items.conf
where you can append:
&admin_restore_only=yes
So that when restoring the custom domain items values from the User's backup,
the backup/domain.com/domain.conf custom value will only be restored if:
admin_restore_only=yes is not present in the global config
or admin_restore_only=yes is present in a line in the global config, and the restore is being done via the Admin Level.
When an item has admin_restore_only=yes set, neither triggerig the restore from Reseller Level nor User Level will restore the given custom item line from the domain.conf in the backup.
T24811
new
GUI: Subdomain php-version selection, DocumentRoot overrideNew GUI for both Enhanced and Evolution to lets Users pick a new DocumentRoot for either public_html/private_html/both, and also have the given subdomain use a different php version.
With Enhanced, this URL will have a DocumentRoot column:
CMD_SUBDOMAIN?domain=domain.com
which will show any changes to the given subdomain.
When that info is clicked, you'll end up here:
CMD_SUBDOMAIN?action=show_docroot_override&domain=domain.com&subdomain=subname
DOCUMENT ROOT OVERRIDE
To make a change to the public_html or private_html document root value in their respective VirtualHosts:
request: CMD_SUBDOMAIN
method: POST
domain=domain.com
on=document_root_override
subdomain=subname
one or both of:
- public_html=/domains/domain.com/public_html
- private_html=/domains/domain.com/private_html
where their values must be below the /domains/ directory, and must exist.
To reset the values to the default, pass the public_html or private_html (or both) but set an empty "" value.
Not passing the variable at all will not affect that value, so you can change one without changing the other.
PHP VERSION SELECTOR
A new back-end has been created for the subdomain php version selector:
Subdomain: per-sub php version selection
The back-end is a single POST:
request: CMD_SUBDOMAIN
method: POST
domain=domain.com
action=php_selector
php1_select=1|2|3|4
subdomain=subname
or:
select0=subname
(select1=othersubname)
where domain.com, 1|2|3|4 and subname should be swapped with their respective values.
T24225
EVO1847
new
Removed 'default' skinThe "default" skin will no longer be included in the update packs.
The skin, if you have it on your system, will remain in place, but new installs will not have it.
new
Prevent creating Reseller/User named "admin"Extra check when creating a Reseller or User, where the username must not be "admin".
To avoid confusion, only an Admin account may be called "admin".
new
FTP: Immediate /etc/pureftpd.pdb updates on password changePreviously, the password was changed in the /etc/proftpd.passwd file, and a task.queue call was pushed to request updating the /etc/pureftpd.pdb file by the dataskq.
This could take up to 60 seconds.
This change simply reworks the FTP task.queue trigger function to issue the /etc/pureftpd.pdb rebuild on the fly.
All instances of the /etc/proftpd.passwd.lock being cleared have been moved to just after this trigger, so the lock will be held a few moments longer.
However, the locking system does allow for time to pass as it waits for the lock to clear before giving up, so this shouldn't be an issue.
T25244
new
Nginx: CUSTOM2: ability to insert into any location path, without password protection or redirectThis applies to Nginx only installs (not nginx_apache proxy).
For nginx, the CUSTOM2 token lives within the "location /" sections of the per-user nginx.conf files.
These sections appear for either password protected directories, or the site redirection feature,
the nginx_protected_directory.conf and nginx_redirect.conf templates, respectively.
However, if you're not using either of these features, there won't be a be a location section, thus nowhere to put the CUSTOM2 token.
This feature, creates a new template:
nginx_blank.conf
which has littler more than a location for the given path, the |CUSTOM2| token, and the |NGINX_PHP_CONF| file:
location |LOCATION_PATH|/
{
|CUSTOM2|
|NGINX_PHP_CONF|
}
DirectAdmin will read a new file:
/usr/local/directadmin/data/users/fred/domains/fred.com.cust_nginx.locations
which will have something like:
/=
where it's 1 line per path, with the path being followed by = for possible future use.
Note: any variables/values you set in there will also get added to this areas tokens list (but do not carry out to global tokens).
For example, you could add:
/foo=EAT=apple
which then makes the |EAT| token available,set to "apple", when tokenizing the nginx_blank.conf for this one path.
If there are any password protected directories, or path redirections on the same path name, this nginx_blank.conf will not be used, as those 2 templates DO have the CUSTOM2 token present inside.
The extra location sections will be inserted into the EXTRA_LOCATIONS token.
Possible GUI to manage the domain.com.cust_nginx.locations to follow.
T25185
new
Exim: Include rejectlog in account "In / Out" logsNew internal variable:
brute_force_exim_reject_log=/var/log/exim/rejectlog
If this /var/log/exim/rejectlog log exists, DirectAdmin will now include it's output along with the other inbound log entries from the mainlog for the given user@domain.com.
exigrep is called twice in 1 call, separated by a semi colon, where DA reads in the output from both.
DA then loads the full output into a ListFile container, where it's sorted, as both logs share the same timestamp format.
This will allow Users to view any rejections only visible in the rejectlog, as opposed to only seeing the inbound logs from the mainlog.
new
Tokenizer: option to not clear the environment: tokenizer_clear_env=1 for scriptsNew internal directadmin.conf value:
tokenizer_clear_env=1
where you can disable it with:
tokenizer_clear_env=0
causing the Tokenizer not to wipe the environment before adding new values.
This happens when the Tokenizer::runScript function is called, to process:
|$/usr/local/bin/php
<?php echo "hi"; ?>
DONE|
Type embedded calls.. anywhere.. (skins or templates, etc).
So setting this to 0 will affect everything, just be conscious of that.
DEFAULT CHANGE
The default, which does clear the entire env, has been changed to restore the env after being wiped out.
So the env vars from before the tokenizer runs a script, will be restored after the script is done.
Thus the only benefit to the feature:
tokenizer_clear_env=0
is to pass any pre-script env vars to the script (aside from anything that is set/ovewritten for the script, as before, which will still be set)
JSON
I've also added a new CMD call so you can see all current ENV vars.. if there are any or not:
CMD_JSON_LANG?environment=yes
Generates a JSON sub-array called "environment" holding all current "environ[]" vars from the system.
You'll also get a top-level json int value:
"tokenizer_clear_env": 0
if it's on (1) or not (0).
Note that this is one of the first times the json output will generate an integer without "quotes".
Be sure your json parser is correctly handling int values.
T25096
new
Messages: "E-Mail Only" to use same encoding as skin (SKINS)If you've got a UTF-8 skin, and are sending an "email only" message to one or more Users, unless you were to specify:
|?HEADER=Content-Type: text/plain; charset=UTF-8|
the message would not get the UTF-8 encoding, and the resulting email might be garbled if you were using special characters.
This changes does 2 things:
- Includes:
<input type=hidden name=encoding value="|LANG_ENCODING|">
where |LANG_ENCODING| is replaced with the encoding, we'll use UTF-8 in the examples below,
in all email-only messaging forms, so DA knows what the encoding it.
Unfortunately, the POST does not include sufficient encoding information from the form to do this automatically, hence changes are needed.
With that, should the Content-Type header not already be set (via |?HEADER=), then DA will add headers
Content-Type: text/plain; charset=UTF-8
MIME-Version: 1.0
- The E-Mail only form now supports up to 4 headers:
HEADER, HEADER2, HEADER3, HEADER4
which you can set with, eg:
|?HEADER3=Your: header|
in the message.
Note that these e-mail only messages continue to support <html>
formatting, as before, simply by starting the message with:
<html>
which will now also include the UTF-8 charset, eg:
Content-Type: text/html; charset=UTF-8
(SKINS)
Enhanced skins changes in:
data/users/ticket/*
create.html
create_multiple.html
reply.html
which includes:
<input type=hidden name=encoding value="|LANG_ENCODING|">
in the submission form.
T25379
EVO1854
new
Custom Hooks: login_key_create_post.sh, login_key_modify_post.sh (HOOKS)2 new hook options:
login_key_create_post.sh, login_key_modify_post.sh
can be created in any valid hook script location:
Sub-locations for all script hooks (HOOKS)(PLUGINS)
and will be triggered when a Login Key is either being created or modified, or if a One-Time Login Hash URL is being created (as it essentially creates a special login key to do this)
Values passed to the scripts:
keyname=<name of the login key>
is_login_url=0|1 #if 1 we're creating the one-time login has url. 0 means a normal login key.
modifying=0|1 #new or modifying an old one
key=<secret key> #only applies to creations, it's the plaintext/raw plassword for the key to work with.
expiry_timestamp=unix timestamp for the current expiry of the key. 0 means never.
max_uses=0+
allow=list of CMDs allowed, separated by | character
deny=list of CMDs denied, separated by | character
ips=list of ips allowed, separated by | character.
login_keys_notify_on_creation=0|1|2 #based on the directadmin.conf setting, altered by DA at run-time, depending on if a notice should be sent for this call.
T25264
new
CMD_IP_MANAGER?json=yes to include extra IP infoThe new global shared IP type will now get it's own column on the CMD_IP_MANAGER table (both GUI and json)
When json=yes is passed, an extra column called "extra" will be added to the end, containing a json sub-array of info, currently with "creators", a json array of Admins/Resellers who are on this IP.
If an IP has zero creators no it, the "creators" array will be absent.
Eg:
"ips":
{
...
"3":
{
"ip": "1.2.3.4",
"status": "shared",
"global": "yes",
"reseller": "admin",
"users": "0",
"nameserver": "",
"netmask": "255.255.255.0",
"extra":
{
"creators":
[
"admin",
"reseller2"
]
}
},
...
new
Package: rename & copyEnd-point for renaming or copying a package, without needing to pass all existing information.
Both will use the respective package levels:
CMD_MANAGE_RESELLER_PACKAGES
CMD_MANAGE_USER_PACKAGES
RENAME
action=rename
old_package=oldname
new_package=newname
COPY
action=copy
old_package=oldname
new_package=newname
EVO1859
new
BubbleWrap jail for ssh/crons (BETA)(TEMPLATES)(SKINS)For CentOS 7 and up, CustomBuild now supports:
./build bubblewrap
./build jailshell
to install /usr/bin/jailshell.
DirectAdmin can make use of this with a new value (set to 0 by default)
/usr/local/directadmin/directadmin set jail 1
service directadmin restart
which enables the package/reseller/user.conf options for "jail=ON/OFF"
Any sshd related changes will save /usr/bin/jailshell (if exists) to that User's shell in /etc/passwd.
Any cron changes will save SHELL=/usr/bin/jailshell (if exists) in that User's crontab.
ssh does not need to be enabled to enable jail for the given User.
Alternatively, you can set:
/usr/local/directadmin/directadmin set jail 2
service directadmin restart
so that regardless of any package/reseller/user.conf settings, jail is ALWAYS enabled, and will always be set for ssh/cron when saved.
Note this does not work on all OSs and some VPSs due to either the kernel not supporting it, or for VPSs due to the fact the VPS may already be using this jailing technology, so it cannot be double-bubbled.
KNOWN ISSUES
exim is within the jail and is not yet able to read the exim.conf.
We're working on a solution.
GLOBAL TOKENS
HAVE_JAIL=0|1|2
Note that this is entirely based on the directadmin.conf.
CustomBuild will need to set jail=1 upon ./build jailshell and restart DA.
Admins can bump this up to level 2 if desired.
TEMPLATE TOKENS
USE_JAILSHELL=no|yes
JAIL_TRUE_FALSE= "" || "jail=true" #where if it's false, it's blank. jail=true is in the token only if it's enabled for this User.
TEMPLATES
virtual_host2*.conf
to add |JAIL_TRUE_FALSE| just after the |DOMAIN|.ini in the 2x FCGIWrapper lines.
SKINS
reseller/create_customized_user.html
reseller/modify_user.html
lang/en/lf_standard.html
lang/en/internal/command.txt
TAGS
jail chroot sandbox
Evo1866
Possible design change: da.conf:jail=1 is a feature, not a requirement. Aside from =2, some way to prevent Resellers from disabling it.
Not applicable with =2, but an Admin may want more control over forcing Resellers/Users, with control over on/off on a per-account basis.
new
gzip for jsonMany areas that generate json output will now have that output gzipped.
Instead of sending the data as the container is traversed, one large json string is generated internally, followed by standard gzip chunked encoding.
The filesizes should but about 1/10 the size, speeding things up, even with the extra internal memory usage (json data is typically not that huge, so no major issue)
new
Feature SetsPackages already give control over limits and other features.
However, it does not (easily) allow for control over which CMD values are allowed in the account.
New feature called "Feature Sets" which allow easy selection of various sets, which can be added together.
USER.CONF and PACKAGES
The user.conf file and User packages will have a new optional variable:
feature_sets=view_domain:tickets:dns_only
where the values on the right are only an example (no default value).
Submitting a blank "features_set=" for packages/user customization will delete the variable from the file.
The values must be colon separated, no spaces, and must exist.
Any bad/missing sets are ignored without errors being thrown.
TEMPLATES
All feature sets will live here:
/usr/local/directadmin/data/templates/feature_sets/
where each set is a directory.
Each set directory will have a file:
commands.allow
which acts like the usual commands.allow files (no commands.deny at the moment).
Custom sets with different names can be added or current ones can be overridden by creating a copy in a custom folder:
/usr/local/directadmin/data/templates/custom/feature_sets/
DEFAULT SETS
dns_only : Users can control their dns records.
email_only: All E-Mail related functions
tickets: Allows use of the Message and Ticket System
view_domain: A base set so User can view the domain overview, stats, change passwords and logout (this set is recommended, but not required if it's API only)
JSON
CMD_SHOW_USER_PACKAGE?json=yes
CMD_SHOW_USER_PACKAGE?package=gold&json=yes
CMD_SHOW_USER?user=fred&json=yes
CMD_MODIFY_USER?user=fred&json=yes
will include a top-level array called "feature_sets", with each element index being the code name of the feature set.
The value of this code name is another array containing "name" which is the display name, and "checked" : "yes"|"no" if that items has been checked.
"feature_sets":
{
"dns_only":
{
"checked": "yes",
"name": "DNS-Only"
},
"email_only":
{
"checked": "no",
"name": "E-Mail-Only"
},
"tickets":
{
"checked": "yes",
"name": "Tickets/Messages"
},
"view_domain":
{
"checked": "yes",
"name": "Core Commands"
}
},
EVO1872
new
Include MySQL Queries in high-load outputWhen DA triggers a high-load notice to the Admins on the box, the scripts/extra_load_info.sh will now include the output of the query:
SHOW FULL PROCESSLIST;
in case the load is caused by mysqld.
The output is only generated if:
mysqld is running
the conf/mysql.conf is has host=localhost or not host at all (default sets to localhost)
as a the queries on a remote mysqld server is not likely relevant in the output.
new
directadmin.conf: block_cracking_variables_conf=/etc/exim.blockcracking/variables.confNew directadmin.conf internal variable:
block_cracking_variables_conf=/etc/exim.blockcracking/variables.conf
Note that DirectAdmin will also append .custom to the end of the value in some cases, meaning the variable will affect both the default and a custom override file.
new
getLicense.sh from GUI (SKINS)New button in the Admin Level >> Licenses/Updates page:
"Update License Auto"
in addition to the existing "Update License" button.
The new auto button will make a call to the "./getLicense.sh auto" script.
This is very useful if your License ID or Client ID has changed, DA will automatically figure out which license should be downloaded and will do so automatically.
No need to figure out your new LID/UID numbers.
SKINS
admin/license.html
new button, next to the existing "Update License" button to call:
/CMD_LICENSE?update=license_auto
TASK QUEUE:
echo "action=update&value=license_auto" >> /usr/local/directadmin/data/task.queue
although,if you already have root access, you could just run:
/usr/local/directadmin/scripts/getLicense.sh auto
====
EVO1878
new
Lang: Internal texts for Update classThe Update class was previously an Admin-only class, and internal translations never occurred on it.
With the introduction of the "Verify License" button for clients, this was causing confusion.
This change adds a new internal text translation file at:
/usr/local/directadmin/data/skins/enhanced/lang/en/internal/update.txt
which can be copied from "en" to the language of your choice, in the skin directory you're most likely using, eg:
/usr/local/directadmin/data/skins/evolution/lang/nl/internal/update.txt
assuming "nl" is what you're translating into. Adjust paths as needed.
GETTEXT
Changes were also made to strings in preparation for gettext() translations, already in progress.
T25834
new
rotate_log_post.sh at domains/domain.com/logs timeHook which can be triggered after the logs from /var/log/httpd/domains/domain.com.log.1 are copied over to ~/domains/domain.com/logs (path variations depending on settings will apply)
Create it here, not the new path naming method:
/usr/local/directadmin/scripts/custom/rotate_log_post/my_reason.sh
where my_reason.sh is renamed to your own name/purpose for the script.
This allows multiple hooks to be called on the same trigger.
Script is called after the logs are rotated into the User logs path, but before the web logs are actually deleted/truncated.
As this script runs as root, it's not recommended to work on any data in the User's home path, or anywhere a User has write access.
If you're using this to save a copy, we recommend coyping it direct from the /var/log/httpd/domains/ path to another non-User-writeable path.
Use any su trickery to run as the User as your own risk 😃
Variables passed to the hook:
USER=fred
dest=/home/fred/domains/domain.com/logs/Apr-2020 (or /home/fred/domains/domain.com/logs/Apr-2020, etc..)
log_dir=/home/fred/domains/domain.com/logs
compress_rotated_logs=0|1
tarfile=/home/fred/domains/domain.com/logs/Apr-2020.tar.gz
files="/home/fred/domains/domain.com/logs/domain.com.log.1 /home/fred/domains/domain.com/logs/domain.com.error.log.1" #this is all one string, without quotes, used during tar call.
file=/var/log/httpd/domains/domain.com.log (or domain.com.sub.log) #note that this is not the file being worked one, but where the .1 file came from.
access_log=/var/log/httpd/domains/domain.com.log.1 (or domain.com.log or domain.com.sub.log.1, can vary depending on settings)
error_log=/var/log/httpd/domains/domain.com.error.log.1 (or domain.com.sub.error.log.1
new
php_mail_log_dir=|HOME|/.php (TEMPLATES)New internal value:
php_mail_log_dir=NULL
which is unset/missing.
If you add any string, even an empty value like "php_mail_log_dir=" this will be used (don't add an empty value)
This feature allows you to override the /home/user/.php folder to use some other location, in the event your clients have a habit of deleting their logs, eg:
php_mail_log_dir=|HOME|/.php
which would be the same as the default we already have now.
TOKENS
Available tokens for this value:
USERNAME and HOME
So if you wanted to store them elsewhere, like:
/var/log/php-mail-logs/fred/php-mail.log
You could use:
php_mail_log_dir=/var/log/php-mail-logs/|USERNAME|
PERMISSIONS
Note that DirectAdmin assumes the directory has permission to be created while running as the User.
As such, the parent folder must exist and be controllable by the User ahead of time.
In the above example, this would not be true, so using a hook like:
/usr/local/directadmin/scripts/custom/user_create_post/php_mail_log.sh
#!/bin/sh
D=/var/log/php-mail-logs/$username
mkdir -p $D
chown $username:apache $D
chmod 770 $D
exit 0;
would be needed.
Post-cleanup might be required too:
/usr/local/directadmin/scripts/custom/user_destroy_post/php_mail_log.sh
#!/bin/sh
D=/var/log/php-mail-logs/$username
rm -f $D
exit 0;
and chmod your scripts to 700.
ROTATION
Similar to permissions, rotaton of the php-mail.log file will be done as the User, hence the importance of this directory being writable by the User.
TEMPLATES
- openlitespeed_vhost.conf
- php-cron.ini
- php-fpm.conf
- unit_application.json
- user_virtual_host.conf
- virtual_host2.conf
- virtual_host2_secure.conf
- virtual_host2_sub.conf
- virtual_host2_secure_sub.conf
Replaces:
`HOME`/.php/php-mail.log
with:
`PHP_MAIL_LOG_DIR`/php-mail.log
T25729
new
Rspamd Controller WebUI (SKINS)Since rspamd can be installed:
Rspamd: binary replacement of SpamAssassin (TEMPLATES)
and rspamd come with a nice controller socket, allowing a WebUI:
https://rspamd.com/webui/
this feature will have DirectAdmin acts as a proxy to this socket.
This is an Admin-Only call, and the socket is proxied from the command:
/CMD_RSPAMD_SOCK/
note, as all included files with this call are relative to it, it needs to be treated as a directory.
Accessing "CMD_RSPAMD_SOCK" without the trailig / charcter will issue a redirect to CMD_RSPAMD_SOCK/
All files below this path, eg:
/CMD_RSPAMD_SOCK/img/rspamd_logo_navbar.png
are sent to the socket as http://localhost/img/rspamd_logo_navbar.png
Allowing a the rspamd WebUI to work through DirectAdmin's connection on 2222.
SKINS
The button for the rspamd controller is in the Mail Queue Admin (Enhanced skin):
admin/mail_queue.html
Only change is an added button:
|*if HAVE_RPSAMD_CONTROLLER_SOCK="yes"|
<input type=button onclick="location.href='/CMD_RSPAMD_SOCK/'" value='Rspamd Controller'>
|*endif|
where the HAVE_RPSAMD_CONTROLLER_SOCK token will be yes or no.
JSON
CMD_MAIL_QUEUE?json=yes
will include:
"settings":
{
"HAVE_RPSAMD_CONTROLLER_SOCK": "yes"
},
to indicate if the button is available.
OR
you can also just call:
/CMD_RSPAMD_SOCK/
and if the feature is not available, it will throw a standard json error.
EVO1885
new
Netdata MetricsNetdata Metrics for realtime, highly detailed server information.
https://www.netdata.cloud/
INSTALL
cd /usr/local/directadmin/custombuild
./build netdata
COMMAND
The new command in DA will be:
CMD_NETDATA_SOCK
where DA is nothing more than a proxy over to:
/var/run/netdata/netdata.sock
This is an Admin Level only command.
Evolution: Admin Level -> Admin Tools -> Netdata server metrics
Enhanced: Admin Level -> Complete Usage Stats -> Netdata Controller
TROUBLESHOOTING
Ensure the sock exists:
/var/run/netdata/netdata.sock
if not, try a full stop/start of the service:
service netdata stop
service netdata start
Once the sock exists, in DA, issue a full ctrl-F5 to ensure the latest checks have been done for the service.
new
Forwarders: other create optionsWhen creating a forwarder with the standard method:
- CMD_EMAIL_FORWARDER
method: POST
action=create
domain=domain.com
user=fred
email=some@value.com, other@value.com
This change lets you use other method of creation:
- CMD_EMAIL_FORWARDER
method: POST
action=create
user=fred@domain.com
email=some@value.com, other@value.com
- CMD_EMAIL_FORWARDER
method: POST
action=create
raw_forwarders=fred@domain.com --> some@value.com, other@value.com
Where the #1 and #2 must not have "domain" nor "DOMAIN" passed to them.
The domain will be taken from the user variable.
For #3 it must not have "domain", nor "DOMAIN", nor "user" passed else it will not trigger.
new
No more AllowUsers in sshd_configSince it's not really needed and only adds extra complexity to the system, DirectAdmin will now have checks to see if there are any AllowUsers lines in the sshd_config file.
If there are, the previous logic is used where Users are added/removed from the sshd_config anytime ssh is enabled/disabled for this User.
However, if there are zero lines that start with AllowUsers, then DA assumes they will not be used, and no future AllowUsers lines will be added.
TODO: The setup.sh will also be changed to only add AllowUsers root, AllowUsers admin if there are already AllowUsers entries in this file.
This must be done at or after the time of the full DA release, so that the live setup.sh still adds them for the previous DA version.
new
per-User mail_partition override in user.confIf you only want a select number of Users to use the mail_partition, or inversely, which for most to use it, and some not, you can set the directadmin.conf mail_partition as desired for all (set or blank),
and then override it for any User that needs it by setting some other partition in their user.conf file.
I you have a blank directadmin.conf mail_partition, then you can add mail_partition=/mail to the user.conf for the User to use this other path.
If you have mail_partition=/mail set in the directadmin.conf, you can add mail_partition=/home to Users who you will want to use their ~/ home directory for email.
T25937
new
doveadmn expunge to purge directoriesOn the "E-Mail Accounts" page, the "Purge From X" button (to purge from spmabox, imap folders, inbox), used to hunt in the given paths for files that match, to be removed.
This change will instead use the "doveadmn expunge" tool instead.
For the "Imap Folders" option, the command "doveadmin mailbox list" is used for the given account to obtain the list of folders to purge.
Also includes the "purge_spam_days" option, run during the tally to clear the spambox for virtual email accounts.
T26046
new
Block search engines: 2222/robots.txtBlock all search engines from showing/caching your 2222 login page.
Any call to /robots.txt on your DirectAdmin port will return:
User-agent: *
Disallow: /
T26051
new
Mailing Lists: ability to set sender (TEMPLATES)(SKINS)The majordomo 'sender' value can now be set in the List settings area.
The e-mail address specified must be on the same domain, but "owner-name" is still allowed.
SKINS
enhanced/user/email/list_modify.html
<input type=text size=16 name=sender value="|sender|">
If the "sender" is not passed, there is an internal default of owner-|NAME| set, so it will continue as it did before.
TEMPLATE
Changed:
sender = owner-|NAME|
to be:
sender = |sender|
EVO1887
new
getLicense.sh will restart DA on valid license.keySince a valid license.key download will almost always require directadmin to be restarted, calling the getLicense.sh script will now issue a task.queue.cb request for immediate restart of DA.
If you missed it, the new simple/recommended way to get a new license from ssh:
/usr/local/directadmin/scripts/getLicense.sh auto
new
Quick/minimal json listing of email accountsIf you only need the list of email accounts, you can now append &quick=yes:
CMD_EMAIL_POP?domain=domain.com&json=yes&quick=yes
Which returns an "email" array:
{
"emails" :
[
"admin",
"fred",
"bob",
"abuse",
"sales",
"support",
]
}
new
SSO: Client IP overrideThe Webmail and Database one-click login tool will always use the IP of the currently logged in User, to set into the login token.
This change allows scripts to automate a redirect for a client, so they can login without a password.
The script must pass a header with a valid IP, eg:
X-DirectAdmin-IP-Override: 1.2.3.4
in the httpd request. Again, this is a header, not a GET, nor a POST value.
T26170
new
Resend Welcome E-Mail: sets "Return-Path" to Reseller's emailWhen using the "Resend Welcome E-Mail" tool, to resend the info or reset a new password, the Return-Path value will now use the same Reply-To header.
If needed, utf8_encode_from_to=1 will encode it.
The value is passed to exim via the -f flag.
T26279
new
logs_history_as_nobodyOptional setting, off by default, which can save your User's logs folder and contents as "nobody", preventing them from deleting them from:
/home/user/domains/domain.com/logs/*
To enable:
/usr/local/directadmin/directadmin set logs_history_as_nobody 1
service directadmin restart
UPDATE: use at least ./directadmin o:
Compile time: May 6 2020 at 16:41:18
new
Allow 1.2.3.0/24 style masks in Login KeysThe IP lists for Login Keys now permit the use of standardized subnet masks, eg:
1.2.3.0/24
which would allow the login from any 1.2.3.x IP address. (Can be any sized bit /mask, doesn't not need to be per 255 block.
This also works for IPv6 addresses and /128 masks.
All types are run through inet_pton, and IPv4's are internally prefixed with ::FFFF:, so they're also worked on in an IPv6 space.
Compile time: May 3 2020 at 21:29:29
T26436
new
directadmin.conf cleanup: rely on internal defaults (TEMPLATES)The directadmin.conf is basically a means to override the internal defaults with custom values.
The only time a value is actually needed in the directadmin.conf is to use something else.
Many values that were in the template:
/usr/local/directadmin/data/templates/directadmin.conf
were redundant, in that they're values that would really never, or rarely change.
Their presence really only added more information than was needed.
The values that remain are:
- Value that are specific to this server, eg:
servername, ns1, ns2
- Values that will be set on new installs, but should not alter existing installs.
These are overrides that are different than the internal defaults.
Anything else was removed, relying on the internal default.
JSON
A new feature is able to show the "diff' from the internal defaults vs the loaded directadmin.conf:
CMD_ADMIN_SETTINGS?json=yes
where the array "directadmin_conf_diff" will show the values which differ.
Keep in mind that some of these values are internally generated/modified, so not all are entirely relevant.
For example, with OLS, we get: "apachecert": "/usr/local/lsws/ssl.crt/server.crt", which is internally modified.
Compile time: May 4 2020 at 17:36:20
new
Block Domain RenameAbility to block Users from renaming their domains.
Internal default:
users_can_rename_domains=1
To block the ability, set:
/usr/local/directadmin/directadmin set users_can_rename_domains 0
service directadmin restart
This has 2 effects:
Fully blocks the CMD_CHANGE_DOMAIN and CMD_API_CHANGE_DOMAIN calls.
Extra check where the call to execute the rename would fail (it shouldn't ever get this far)
USER.CONF OVERRIDE
You can override this setting for any User by adding:
users_can_rename_domains=0|1
to their user.conf, if you wish to have a User be exempt from whatever the directadmin.conf is set to.
fixed
Details for a given month in User History does not show last daySample URL that doesn't show the last day of the month:
/CMD_BANDWIDTH_BREAKDOWN?user=admin&year=2013&month=12
Only goes up the 2nd last day of the month.
The tally on the 1st of the month (just before the reset) is adding then entry for the wrong date.. in the above case, January 1st, 2013 (yes, 2013), which is doubly wrong.
Bug was caused by the final tally using the 1st day of the month in the bandwidth.tally.cache file, eg:
2020 01 30=...
2020 02 01=...
and the backup to the history directory filtered out the "02" month as it was for the "01" log.
Changed the read of the bandwidth.tally to always subtract 6 hours from the last "time" read, since all tallies should be done by then.
That would put the day to the previous date, giving us the correct final line for the bandwidth.tally.cache.. so the history is correctly stored.
Unfortunately, the old missing data cannot be recovered.
These binaries would need to be in place for the final tally of the month (at 12:10 am the first day of the next month, to compute the final day)
T24720
fixed
Do not continue to increased failed attempts/unauth access count, if they're blacklistedThe 2222 failed attempts and unauthorized attempts counters were trying to count up, after the IP was already added to the ip_blacklist.
The issue was that the moment the IP is added to the blacklist, the data/admin/ip_access/1.2.3.4 folder is deleted so that the IP can be cleared from the ip_blacklist and continue to login one the admin clears it, or the removal time kicks in.
This should only be a cosmetic error causing extra log entries, eg:
2020:02:22-12:55:57: Error opening ./data/admin/ip_access/1.2.3.4/unauthorized_connections for appending count: No such file or directory
which should be caused by the ip_blacklist having the 1.2.3.4 already, added in the same process just before DA tries to increase the count.. but the directory is gone, hence the error.
Future requests should blocked by the ip_blacklist, so it shouldn't get this far again.
Also bug with Evolution where it needs to check for the header:
X-DirectAdmin: blacklisted
since the block output is generated before anything is parsed, so the json=yes in the POST or headers is fully ignored, and the output isn't json (ever).
Thus the header response is the only reliable source of knowing of the blacklisted value, so it gives the proper message (bug is that it says "wrong user/pass" instead of blacklisted.)
EVO:1835
fixed
CMD_MASTER_LOGIN: don't show full list if more than 500 UsersNew internal directadmin.conf value:
master_login_max_list=500
where the Evolution call to:
CMD_MASTER_LOGIN?json=yes&action=[all_users]
will get a json error:
{
"error": "List of Users is too long",
"result": "master_login_max_list: 23003 > 500"
}
so it knows not to show the raw list, and rely solely on the search, while the creator types in the desired Username.
T24695
fixed
IMG request were always gzip encodedBug where da_gzip=0 was being ignored for IMG_* requests.
Fixed to send in gzip, only if da_gzip=1 and if the client's request supports it.
fixed
direct_crons allow LANG and LC_ALLExtra headers allowed in the crontab:
LANG
LC_ALL
to prevent cron read errors.
T24827
fixed
Plugin: hooks/*_(img|txt).html run as calling UserThe tokenizing process for the hook files in:
/usr/local/directadmin/plugins/PLUG/hooks/user_txt.html (for example)
will now be able to run the embedded scripting, with the usual format, eg:
|$/bin/sh
echo "<a href=''>Plugin</a>";
DONE|
T24853
fixed
Backup/Restore: skin_customizationsBackup and Restore Reseller skin_customizations directory.
fixed
Demo accounts using demo docsroot but not skin valueBug where a demo login is correctly setting the "docsroot" value for the demo skin, however the internally loaded "skin=" variable was not being set to the skin name from the demodocsroot variable.
If you had the docsroot and demodocsroot both set to the same value, you would not likely be affected,
but if you have enhanced for docsroot and evo for demodocsroot, the default "skin" value would have ended up as "enhanced" using the evolution path.
Fix: while loading the default demo variables, also fill the "skin=" variable based on the demodocsroot value.
fixed
Trigger user_restore_fail_post.sh on more casesPreviously, the user_restore_fail_post.sh was only triggered if the restore of the current tar.gz failed during the actual "restore" process of this file (reading it in, and merging the data, etc)
However, there are cases prior to this where the intent is to restore the file, but other pre-condition fail much earlier on, and the script was not called.
New cases to be included in the call of user_restore_fail_post.sh:
1 - Invalid or missing tar.gz filename path
2 - Username cannot be parsed from the filename.
3 - Failure during creation of the account before the restore start
4 - creator conflicts, Reseller bob already manages User fred, but Reseller george is trying to restore it
5 - bad usertype settings from the live user.conf
6 - memory allocation errors when creating a new User class instance
7 - read errors of the live User account prior to restore
Some of these cases will honestly be highly unlikely to happen, but they're included anyway.
Checks 1-4 will use "unknown" for some of the fields, depending on how much info it already has.
These fields might be:
username
usertype
reseller
All others should be filled, as they would be known regardless of the failure.
T24810
fixed
Restore: Custom Domain ItemsRestore to include any custom domain item settings saved in the User's domain.com.conf.
T24811
fixed
nginx_proxy missing www->domain or domain->www redirect when force-ssl enabledAssume:
force_redirect=non-www
force_ssl=yes
ends up with only:
if ($http_x_forwarded_proto != 'https') {
return 301 https://$host$request_uri;
}
without force_ssl, it gives the proper:
if ($host = www.domain.com){
return 301 http://domain.com$request_uri;
}
But with the first assumption, both should be present.
fixed
/var/log/user_logs/user/domain.com.log to ensure logs are 644 (webalizer/awstats)The secured way that DirectAdmin lets awstats/webalizer run as the User, while being able to read the logs from the locked-down /var/log/httpd/domains area is by using hard-links.
The issue is that some boxes either set a strict umask or apache setting to save the /var/log/httpd/domains/domain.com.log as root:root 600.
The issue arises when the hard-link is created, although the /var/log/user_logs/user is chmod 750 root:user, the root:root 600 log is not enough for the User to user read it.
Fix: added a mode check on a+r, if it's not set, DA will set it to 644.
T24450
fixed
lock_forwarder.lock: not removedRelated to the new user limit check locking:
Bug where after the modification of a forwarder, the lock_forwarder.lock was not removed, causing:
Unable to lock forwarder area: file is locked by another process
Fixed by clearing the lock after modification of the forwarder.
Workaround:
manually delete /usr/local/directadmin/data/users/username/lock_forwarder.lock
or wait 60 seconds for the lock to expire.
fixed
CMD_API_EMAIL_VACATION with json=yes generating blank outputThe CMD_API calls were not originally intended to support json, they were for URL encoded output.
However, the desire to want json output is entirely founded, so any cases where json isn't working with the CMD_API calls can be reported and will be fixed.
In this case, all CMD_API_EMAIL_* related calls call the same functions as the CMD_EMAIL style calls, however they have their own container to be passed back up to the CMD_API handler.
This container override thus trumped the JSON container, thus filling the API container, rather than the JSON container, causing empty json output when json=yes is added.
Specific call:
CMD_API_EMAIL_VACATION?domain=domain.com&json=yes
This is a blanket fix for all CMD_API_EMAIL calls* where the API container override will now be ignored in favor of the JSON container when json=yes is enabled.
Risk of affecting non-json CMD_API_EMAIL* call is present, however without json=yes, they should logically not be affected.
Confirm the URL encoding still works fine for CMD_API_EMAIL_VACATION?domain=domain.com.
T25017
fixed
ConfigFile class: read from string was ignoring last line if no newlineRelated to a similar fix for config files, where a missing newline character at the end of the file would not read that line:
readLine no longer ignores lines without trailing newlines
the similar read on a string, instead of a file, had the same behavior.
Fixed to notice there was buffered data before hitting EOL, and counting it as legitimate before returning.
fixed
JSON for CMD_API: backup sendBy default, CMD_API_* calls were not designed for JSON deliveries.
CMD_* calls (non-API) were setup for this, where action functions (eg: create an email account) have 2 flags:
api
json_out
where api==1 for CMD_API calls and json_out=1 for &json=yes calls.
As it wasn't account for in the design (CMD_API calls were coded years before we supported JSON with CMD_* calls),
there are logical scenarios where combining CMD_API calls with json=yes would not give json output.
This code change is a fall-back, where the unified CMD_API handler function now has a check for json=yes, such that JSON output will be sent,
if CMD_API and json=yes are both set.
As this is a single-level array, there might be cases where a JSON value has
"name" : "some=encoded&value=url"
in the even it's a double-encoded URL, so please let us know if you hit any and would like it resolved to be:
"name": {
"some" : "encoded",
"value" : "url"
}
as extra checks would be needed. Not yet sure if this will even happen.
March 18th, 2020:
Also reworked the header vs body "has_sent" flags, to prevent a 2nd call from trying to send data again.
This was caused by some functions sending their own data, while CMD_API calls send from outside the function, after it's exited.
fixed
Optimization on cleaning of brute_log_entries.listThe file:
/usr/local/directadmin/data/admin/brute_log_entries.list
is used to track each attack on a service, by logging the time it happened, the log entrie, which IP did it, etc..
This file can get large, hence the importance of regular cleaning (Admin Settings: clear_brute_log_entry_time)
The previous cleaning method would load this file into a ConfigFile container, step through each item, and write any entries with a newer timestamp to a temp file, line-by-line.
After the write is done, the new file is renamed over the old one.
This new optimization does something similar as to the old line-by-line write, in that it now does a line-by-line read before deciding what to do with each line.
This prevents the need to save the entire file in memory, which for larger files, this can grow very large, causing an out-of-memory situation in some cases, causing the dataskq process to quit,
and leaving the uncleaned brute_log_entries.list file in place, allowed it to continue to grow, amplifying the issue on the next run.
fixed
Reuse Client IP bufferBug recently introduced where the client's IP is returning a deleted buffer.
Fix: if buffer is already set, don't delete/re-create, but rather re-use the existing buffer as a client's IP for a given connection will never change.
T25114
fixed
Linux 64-bit static binaries: dynamic named.conf /var/named path (TEMPLATE)New internal defaults for the namedconfig and nameddir variables.
The default data/templates/directadmin.conf will no longer have these vaules (All OSs)
the values in the conf/directadmin.conf have priority over everything at startup.
Static bins will have internal default to NULL, meaning OS checks are done at startup to determine the path to be used
non-static bins will default to their respective OS
T25030
fixed
OpenLiteSpeed: LetsEncrypt on owned IP non-Vh items: eg: mail.domain.com (TEMPLATES)With an owned IP, there is no global VirtualHost(VH) for in the OLS ips.conf file.
Some A records, like "mail.domain.com" also do not have a VirtualHost.
The result, is there is no VH at all for mail.domain.com, and no include of the httpd-aliases.conf file.
This is where things like the LetsEncrypt /.well-known/challenge and /roundcube aliases live.
Solutiuno: Added * to the main domain of an owned IP, eg:
vhDomain domain.com
vhAliases *
so that mail.domain.com is caught on this IP in this master alias.
The vhAliases is ONLY set for the default domain on a given owned IP, for both 80/443.. but not for any subdomains.
Other domain on the same IP under this User will not get the vhAliases * setting.
================
TEMPLATES
Update to openlitespeed_vhost.conf
Replace:
vhAliases www.|SDOMAIN||SERVER_ALIASES|
with:
|*if WILDCARD_VHALIASES|
vhAliases |WILDCARD_VHALIASES|
|*else|
vhAliases www.|SDOMAIN||SERVER_ALIASES|
|*endif|
where DA only adds
WILDCARD_VHALIASES=*
when the case is needed.
The WILDCARD_VHALIASES token never exists if the above case is not true, eg:
owned IP
default/main domain
not a subdomain
is for both 80/443
T25175
fixed
Restore to box with dnssec=0 should not sign the zoneA domain backed up with dnssec data, being restored to a box with dnssec=0 was signing the zone, simply due to the fact that the dnssec keys were present.
A box with dnssec=0 should never sign a zone, even if the zone was previously signed on another box.
However, the keys will still be restored, but simply not signed.
Also changed the deletion of a dns zone to always delete the 4 keys and d.com.db.signed files, else they would not have been deleted on a dnssec=0 box
(the .signed file shouldn't exist, but could if you did have dnssec=1, and shut it off later)
fixed
scripts/hostname.sh: also set directadmin.confPreviously, when changing the hostname from the Admin Settings, DA would run the hostname.sh script, then DA would set the directadmin.conf.
This is fine unless you're only trying to change the hostname from the script, but also want the directadmin.conf to be updated.
This is a change to the scripts/hostname.sh script, such that it will always run:
./directadmin set servername host.name.com
and issue a task.queue restart of directadmin, even if the Admin Settings calls it.
This allows the hostname to be set everywhere, regardless of how it's triggered, without needing 2 calls if done from ssh.
Now, when done from Admin Settings, the directadmin.conf will be set twice, no harm there, and because both DA and the hostname.sh use a task.queue restart,
the duplicate restart will be filtered out by the dataskq, so directadmin only gets restarted once.
T25240
fixed
Nginx: Subdomains :redirect to/from s.domain.com / www.s.domain.comThe "Force Redirect" domain option to redirect domain.com to www.domain.com or vice versa, was applying it's settings to the Nginx subdomain server{} entry, but was checking:
if ($host = www.domain.com){
instead of:
if ($host = www.sub.domain.com){
Fixed to set proper subdomain host check.
fixed
Crons: crontab returned non zero value: chown: Operation not permittedConfirm on Debian 8, the call to write the crontab was not running as root when setting a new cronjob.
T25360
fixed
One-Time Login Hash URL: allow login_keys_notify_on_creation=0 overrideWhen creating a Login Hash URL from CMD_LOGIN_KEYS or CMD_API_LOGIN_KEYS, the POST option:
login_keys_notify_on_creation=0|1
was not being respected.
When set to 0, no notice will be sent to the User at hash creation time, nor login time when the hash is used.
If set to 1, a notice will be sent at hash creation time and again when the hash is used.
If your directadmin.conf (or internally) has:
login_keys_notify_on_creation=1
Then absence of the POST value will use the directadmin.conf value.
If the directadmin.conf has login_keys_notify_on_creation=2, then notices will always be given, the POST may not override it.
If the directadmin.conf has login_keys_notify_on_creation=0, then no notices will ever be given. the POST may not override it.
Creating the Login Hash URL from ssh using --create-login-url, no notices will ever be given when the hash is created.
A notice will be given when the hash is used (unless directadmin.conf has login_keys_notify_on_creation=0)
T25348
fixed
CMD_JSON_LANG to optionally touch session file to extend session time, and new: upload_idle_timeout=120If you're uploading a very large file through the FileManager, the main upload request does not bump the session expiry time.
The skin could end up logging out prior to finishing the upload.
During the upload, the CMD_JSON_LANG is triggered often, so code has been added to optionally touch the atime on the session file with the utime() function to extend the session time from this point, if the touch_session=yes is passed in the request.
So to maintain the login session during a file upload, change the GET call to CMD_JSON_LANG to include the touch_session=yes variable.
Once the upload is done, return the CMD_JSON_LANG to not include this variable.
UPLOAD IDLE TIMEOUT
Also, new internal variable for multi-part/form-data uploads:
upload_idle_timeout=120
where:
chunk size has been bumped from 2048 to 16384 bytes, for both socket reads, and buffer read/writes during parsing.
Every 10 read cycles, the alarm is set back to upload_idle_timeout, so a timeout for large files is far less likely, as it continuously resets.
there is a sliding max amount of time, based on the content-length, to a certain limit.
after the upload is done, the alarm is again reset to the large value to allow sufficient time for the POST data to be split into it's respective files.
=========
HEADER
Alternatively, ANY CMD call which passes header:
X-DirectAdmin-Touch-Session: yes
will also have the session file touched.
EVO1864
fixed
Access various /etc/virtual/domain.com/ files while domain is suspendedWhen a domain is suspended, the folder is renamed to:
/etc/virtual/domain.com_off
these changes automatically do checks so the various files can be read from domain.com_off automatically, if domain.com is suspended.
Mainly aimed at passwd, passwd.cache, quota, aliases files.
fixed
Swap unknown `TOKENS` with |TOKENS| for future processingDue to the order tokens are loaded (with the template being read in and processed last, after all internal and custom tokens being loaded first),
if you were to set some:
|TOK=`TOKEN`|
where TOKEN has not yet been set, the call to |TOK| would end up filling `TOKEN` in the output even if TOKEN was set before the call to |TOK|, but before TOK was set.
The solution is for DA to take note of all unknown tokens (it already had this list), and for unknown values where they're set to `TOKEN`, swap that TOK value to be |TOKEN|.
When the |TOK| is called later on, it will fill |TOKEN| which can then be tokenized into whatever value TOKEN should have had set in the first place.
This currently applies to the apache/nginx/litespeed/openlitespeed custom templates.
fixed
dovecot_proxy: action=rewrite&value=email_passwd was not setting the caller IP in email passwdRelated to dovecot_proxy=1 feature:
https://help.directadmin.com/item.php?id=2077
but combined with email sync feature where DA's multi-server setup can keep both ends synced:
Cluster: Remote E-Mail Account sync
The issue was with master box A, issuing a local rewrite, eg:
echo "action=rewrite&value=email_passwd" >> /usr/local/directadmin/data/task.queue
where the slave box B was not setting the master box A's host=A-IP in the /etc/virtual/domain.com/passwd file.
It was incorrectly setting host=B-IP.
This fix tracked down the missing proxy_ip=connection flag, being passed to B, thus having B correctly use the client IP in the host (A's IP).
During the debug process, a similar bug was also found in the "modify" code, where changing a password or quota from GUI/API on A would also result in the wrong B-IP in B's passwd file.
fixed
Enforce vacation start time to be before end timeYou were previously able to set a vacation message's start time ahead of the end time.
This wold prevent the vacation message from ever activating.
This change ensures that the start is always before the end, to avoid confusion.
To disable a vacation message, simply set the end time to the past, (or delete the whole message)
The start time would still need to be before this time.
T25646
fixed
swap da_sso definers for PROCEDURES/FUNCTIONSIf you use the one-click single sign-on (SSO) feature for phpMyAdmin, the username used for the login has a prefix of:
da_sso_
If an import of a routine or function is done through PMA using this account, it will set the "definer" as this da_sso_* account name.
This is only a temporary account, and DA deletes it after it expires, thus leaving the functions/procedures without a valid definer, causing errors such as:
Connection failed: SQLSTATE[HY000]: General error: 1449 The user specified as a definer ('da_sso_1234ASDF'@'localhost') does not exist
========
FIX
The solution is that when DA runs through the list of da_sso accounts to clear out, if ANY function or procedure in the mysql.proc table has a definer LIKE da\sso\%@%, DA will use the "db" column, eg:
username_dbname
to obtain the actual owner, and swap the definer to be username@<host>
, where DA also maintains the host value from the old definer.
This check is done anytime the list is saved.. including adding a new value, or with the nightly cron to clear them.
T25637
fixed
Domain Pointers & named_rndc_addzone=1: write order swapWhen the instant dns reload is enabled, eg:
named_rndc=1
named_rndc_addzone=1
The zone db must exist first. Domains were fine, but pointers needed to be swapped (db zone first, then addzone call).
T25735
fixed
Custom mail_partition and system_user_to_virtual_passwd=1 needs Maildir symlinkRelating to the mail_partition:
Custom partition location for email
in combination with:
system_user_to_virtual_passwd=1
which is enabled by default now...
The login for system account "fred" will use /etc/passwd
The login to the same fred@fred.com will use /etc/virtual/domain.com/passwd
The /etc/passwd files does not have it's directory changed with mail_parition is changed, thus the different logins end up in different folders.
The fix sets a symlink from /home/fred/Maildir -> /mail/fred/Maildir
T25896
fixed
Remove additional User IP to ensure more than zero zone IPsSay you have User with IPs:
1.2.3.4
1.2.3.5
The domain only has the additional IP:
1.2.3.5
When removing 1.2.3.5 from the User (with dns removed too), DA would remove it from the zone and if it ended up with zero IPs, it would re-add the default IP again.
This check was fine for apache, but as the only remaining records were removed prior to the new IP being added, there was no record data to duplicate, so the default 1.2.3.4 didn't add any A records, etc.
Fix: change order of check to add any needed IP prior to removing the last IPs from the domain. This will ensure A/AAAA values (etc.) are duplicated prior to removing the only remaining IP, thus not an empty zone.
fixed
Database: do not allow domain access hosts if skip_name_resolve=ONFor MySQL and MariaDB, if you disble dns lookups with the skip_name_resolve=ON option in the my.cnf, the means lookups are not done on hosts.
This also means that any login IP checks will fail if the value entered needs to be resolved (rDNS).
As a result, when you try to add an access host in DA, if you have skip_name_resolve=ON, DA will block any host.name.com or %.host.name wildcard values from being added with message:
access hosts cannot be domains because skip_name_resolve=ON
That is not a valid access host
Without this check, MySQL/MariaDB gets into a broken state where the mysql.user table/view DOES have the values,
but any GRANT calls to also add it to the mysql.db table fail, resulting in a broken state.. not visible in DA for removal, and cannot add them.
Also causes errors during password changes since DA tries to update all access hosts in mysql.db but they don't exist.
T26123
fixed
Restore from system_user_to_virtual_passwd=0 to box with =1 not adding system account to email passwdDirectAdmin was not adding the system account to /etc/virtual/domain.com/passwd when system_user_to_virtual_passwd=1 is enabled on the restore box,
when the system account was not in the same file on the backup server.
Extra check added to ensure it exists, and add it if missing using same system account call as task.queue action=rewrite&value=email_passwd does (surgically for this one account, not a full rewrite/check)
Password crypt taken from /etc/shadow.
When this check and add is triggered, you'll get a note in the errortaskq.log:
Email::restoreEmail: system account %s did not exist in the %s passwd file. Adding it to restored file.
where %s is replaced with the system account name, and the 2nd %s is replaced with the domain being restored.
T26204
fixed
Office365 MX template: extra spacesThe 2 records in data/templates/mx/office365.txt:
lyncdiscover 3600 IN CNAME webdir.online.lync.com.
_sip._tls 3600 IN SRV 1 100 443 sipdir.online.lync.com.
had extra spaces cause DNS syntax issues.
Note, the wording for 1.60.5 will rename this template string to "Microsoft 365"
The template filename and selct-box value will remain as office365.txt / office365.
fixed
Upload files: Use mkstemp instead of tmpfile for location controlThe upload of files using multipart/form-data was using tmpfile() to create a file location for upload.
This usually ended up in /tmp.
For very large files, this might not have been large enough.
Changed to use mkstemp, so we can use the tmpdir=/home/tmp directadmin.conf variable, thus using /home/tmp (or any desired path, via tmpdir var), so you can control where this larger data might end up.
Note the tmpdir is used for various other things, not just uploads.
Compile time: May 6 2020 at 16:41:18
fixed
FileManager: Trash restore: restore correct parent folder permissionsWhen restoring a file or folder from the /.trash folder, or similarly when creating a parent /.trash/* path to move a deleted file/folder into, ensure that if a new parent path matches the old one.
This is to ensure that if DA is creating any paths upon restore, the created parent values correctly match what was previously there.
T26484
fixed
Clear stale users.list from memory to prevent race conditionRelating to the change here:
Race condition during account deletion
added missing item to clear the live memory data prior to the re-read, prior to the write.
Without the clear, the memory would be stale.
Example:
biguser takes 1 minute to delete.
smalluser triggerd 2s after biguser, takes 5s to delete.
smaller user is done being deleted first, the users.list only has biguser left.
The process deleting biguser still has smalluser in it's list, thus smalluser ended up being re-added to the users.list.
There was a re-read of the users.list to catch new accounts, but it didn't clear deleted accounts, thus the full wipe was needed first.
T22739
Compile time: May 18 2020 at 16:05:05