mod_ctrls
What Controls Are ProFTPD version 1.2.10rc1 introduced a new capability: Controls. Controls are a way to communicate directly with a standalone proftpd daemon while it is running. This provides administrators a way to alter the daemon's behavior in real time, without having to restart the daemon and have it re-read its configuration. Changing log levels, kicking connected clients, disabling individual virtual servers, etc. are all possible. The Controls functionality includes an API that third-party modules can use to add new control actions.
proftpd
The functionality involves a client and a server communicating over a Unix domain socket, using a simple text-based protocol. A new program, ftpdctl, is distributed with ProFTPD; ftpdctl is a Controls client. The server side of the Controls functionality is the mod_ctrls module, which is compiled into a proftpd daemon when the --enable-ctrls configure option is used. Note, however, that the Controls functionality only works for proftpd daemons whose ServerType is standalone; proftpd daemons run via inetd/xinetd cannot support Controls and the ftpdctl program.
ftpdctl
ServerType
standalone
Configuring mod_ctrls Here's an example configuration for mod_ctrls:
<IfModule mod_ctrls.c> ControlsEngine on ControlsACLs all allow group ftpadm ControlsMaxClients 2 ControlsLog /var/log/proftpd/controls.log ControlsInterval 5 ControlsSocket /tmp/ctrls.sock ControlsSocketOwner ftpd ftpd ControlsSocketACL allow group ftpadm </IfModule>
ControlsEngine
When first configuring mod_ctrls and its modules, you will probably want to configure a ControlsLog. The mod_ctrls modules will log any errors they have to this file (unless the module has its own module-specific log), as well as all control requests made using ftpdctl. Like most proftpd log files, the directive should use the full path to the log file, and the file cannot be in a world-writeable directory.
ControlsLog
The ControlsInterval directive configures how often mod_ctrls checks for connecting clients such as ftpdctl. Often when using ftpdctl, the system administrator may notice a long pause before ftpdct responds. This delay is probably caused by the configured ControlsInterval. A related directive is ControlsMaxClients, which sets how many clients are handled at one time. If more than the configured maximum number of clients are attempting to send control requests, mod_ctrls will wait to handle the remaining clients until its next check.
ControlsInterval
ftpdct
ControlsMaxClients
The ControlsSocket directive is used to configure the path to the Unix domain socket on which mod_ctrls should listen. This path should be in a place where ftpdctl users have access to it, and should have read and write permissions. The ControlsSocketOwner directive explicitly configures the ownership the created Unix domain socket file should have. This means that the configuration above:
ControlsSocket
ControlsSocketOwner
ControlsSocket /tmp/ctrls.sock ControlsSocketOwner ftpd ftpd
/tmp/ctrls.sock
ftpd
root
Controls Access Control Lists Communicating with the daemon process allows for some great features, but it also allows the potential to easily abuse the system. Thus, by default, all users including user root are denied access to all ftpdctl actions. Access for control actions must be explicitly granted. Also, be aware that the users and groups configured in these ACLs are system users and groups, not the virtual users and groups that proftpd may have been configured to use. The group will be only the primary group of the user; supplemental group memberships are currently ignored.
The mod_ctrls first checks whether the connecting client has been granted the ability to use the Unix domain socket itself. This access list is controlled by the ControlsSocketACL directive. By default, every Controls client can use the socket. Thus, in the example configuration above:
ControlsSocketACL
ControlsSocketACL allow group ftpadm
ftpadm
Next, ACLs on the specific control action requested by the connecting client will be check. Most modules that use the Controls API will have their own module-specific directives for setting ACLs on the specific actions implemented by that module. For mod_ctrls, the ControlsACLs configuration directive is used. In the example configuration we see:
ControlsACLs
ControlsACLs all allow group ftpadm
ControlsACLs all allow user *
ControlsACLs insctrl allow group wheel ControlsACLs lsctrl allow user * ControlsACLs rmctrl deny group ftp
Why is there such complexity for a simple client/server interaction? The primary answer is that the running proftpd daemon has a lot of privileges, and access to the running daemon should be strictly controlled. Allow few people to have access via control actions; those few should be able to use only the control actions necessary.
What Controls Do The mod_ctrls module provides basic control actions, or commands that ftpdctl can send to the daemon:
help
insctrl
lsctrl
rmctrl
Denied Actions Versus Disabled Actions What is the difference between an action that has been denied via an ACL versus an action that has been disabled using the rmctrl action? A disabled action cannot be used by any client, regardless of any ACLs that have been configured for that action. Thus if a system administrator deemed that a particular control action should not be used by anyone, that action can be disabled. The rmctrl action can disable any action implemented by any module using the Controls API, not just actions provided by mod_ctrls. Once disabled, a given action can be re-enabled using the insctrl action. The insctrl and rmctrl actions, in addition to lsctrl, cannot themselves be disabled. For example, to disable an action called foo:
foo
# ftpdctl rmctrl foo ftpdctl: 'foo' control disabled # ftpdctl lsctrl ftpdctl: help (mod_ctrls.c) ftpdctl: insctrl (mod_ctrls.c) ftpdctl: lsctrl (mod_ctrls.c) ftpdctl: rmctrl (mod_ctrls.c)
# ftpdctl insctrl foo ftpdctl: 'foo' control enabled # ftpdctl lsctrl ftpdctl: foo (mod_foo.c) ftpdctl: help (mod_ctrls.c) ftpdctl: insctrl (mod_ctrls.c) ftpdctl: lsctrl (mod_ctrls.c) ftpdctl: permit (mod_ban.c) ftpdctl: rmctrl (mod_ctrls.c)
mod_foo.c
The following shows an example of attempting to disable the lsctrl action. It demonstrates the use of the -v command-line option for ftpdctl, for showing a verbose interaction with mod_ctrls:
-v
# ftpdctl -v lsctrl ftpdctl: adding "lsctrl" to reqargv ftpdctl: contacting server ftpdctl: sending control request ftpdctl: receiving control response ftpdctl: debug (mod_ctrls_admin.c) ... # ftpdctl rmctrl lsctrl # ftpdctl -v lsctrl ftpdctl: adding "lsctrl" to reqargv ftpdctl: contacting server ftpdctl: sending control request ftpdctl: receiving control response ftpdctl: access denied
Admin Controls The mod_ctrls module, by itself, is rather unexciting. Other modules, such as mod_ctrls_admin, provide more interesting and useful control actions, including:
mod_ctrls_admin
debug
dump
kick
restart
shutdown
start
status
stop
trace
A basic mod_ctrls_admin configuration is:
<IfModule mod_ctrls_admin.c> AdminControlsACLs all allow user * </IfModule>
Here is another configuration, encompassing both mod_ctrls and mod_ctrls_admin:
<IfModule mod_ctrls.c> ControlsEngine on ControlsACLs all allow group ftpadm ControlsMaxClients 2 ControlsLog /var/log/proftpd/controls.log ControlsInterval 5 ControlsSocketACL allow group ftpadm ControlsSocket /tmp/ctrls.sock ControlsSocketOwner ftpd ftpd <IfModule mod_ctrls_admin.c> AdminControlsACLs all allow user dave,bob,lisa </IfModule> </IfModule>
dave
bob
lisa
What about configuring an ACL for a given control that includes both users and groups? Use:
AdminControlsACLs restart allow user dave,lisa AdminControlsACLs restart allow group ftpadm