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.
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.
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>The first configuration directive you will want to use is the
ControlsEngine
directive, which enables the processing of
Controls requests by the engine within the mod_ctrls
engine.
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.
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.
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 /tmp/ctrls.sock ControlsSocketOwner ftpd ftpdoverrides the default location of the Unix domain socket, and tells
mod_ctrls
to use /tmp/ctrls.sock
, and to make
the socket owned by user ftpd
and group ftpd
.
The default ownership of the socket is user root
, group
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 allow group ftpadmonly the system group
ftpadm
would be allowed to send Controls
requests to the Unix domain socket; all other users and groups will be
denied.
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 all allow group ftpadmwhich allows only the system group
ftpadm
to use all of the
control actions provided by mod_ctrls
. If one wanted to
allow all users to use all of the control actions, it would be:
ControlsACLs allow user *However, if one wanted to specify separate ACLs for separate actions, then the
ControlsACLs
directive would be used multiple times, like
so:
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
:
# 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)Note that the
foo
action is not listed by lsctrl
.
Now, reenable that action:
# 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)And now the
foo
action, provided by the module
mod_foo.c
, appears in the lsctrl
listing.
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
:
# 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 deniedThe "access denied" message happens because of the special status of the
lsctrl
action which keeps it from being disablable.
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:
debug
dump
kick
restart
shutdown
start
status
stop
proftpd
daemon; see the mod_ctrls_admin
documentation for more information.
A basic mod_ctrls_admin
configuration is:
<IfModule mod_ctrls_admin.c> AdminControlsACLs all allow user * </IfModule>will allows anyone to use any
mod_ctrls_admin
control action.
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>In this configuration, users
dave
, bob
, and
lisa
are allowed to use all of the control actions supplied
by mod_ctrls_admin
. However, unless these users are members
of group ftpadm
, access will be denied. Only group
ftpadm
has been allowed access to the mod_ctrls
socket itself by the ControlsSocketACL
directive.
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 ftpadmWhat if user
dave
is not a member of group ftpadm
?
If configured, both user and group ACLs must deny the client.
If either allows access, the client can use that control action.