mirror of
https://github.com/troglobit/finit.git
synced 2026-11-09 16:21:24 +00:00
Add support for a deny filter syntax to inetd services
This patch changes the syntax for custom inetd services and adds support
for deny filters. The new syntax is:
inetd service/proto[@iface,!iface,...] </path/to/cmd | internal[.service]>
This means the second column now defines what@from and the third to/what
process. For internal services on a custom port the internal.service
syntax must be specified, so Finit can properly bind the inetd service
to the correct plugin. Here follows a few examples:
inetd time/udp wait [2345] internal -- UNIX rdate service
inetd time/tcp nowait [2345] internal -- UNIX rdate service
inetd 3737/tcp nowait [2345] internal.time -- UNIX rdate service
inetd telnet/tcp@*,!eth1,!eth0, nowait [2345] /sbin/telnetd -i -F -- Telnet service
inetd 2323/tcp@eth1,eth2,eth0 nowait [2345] /sbin/telnetd -i -F -- Telnet service
inetd 222/tcp@eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
inetd ssh/tcp@*,!eth0 nowait [2345] /sbin/dropbear -i -R -F -- SSH service
Access to telnet on port `2323` is only possible from interfaces `eth0`,
`eth1` and `eth2`. The standard telnet port (`23`) is available from
all other interfaces, but also `eth2`. The `*` notation used in the ssh
stanza means *any* interface, however, here `eth0` is not allowed.
NOTE: This patch breaks syntax compatibility with Finit v1.12!
Signed-off-by: Joachim Nilsson <troglobit@gmail.com>
This commit is contained in:
1 parent
b0c759e518
commit
03573b41ca
7 files changed
+177
-195
No files matched your search
@@ -235,18 +235,17 @@ the static configuration from `/etc/finit.conf`. This is the default
|
|||||||
behavior, so no include directives are necessary.
|
behavior, so no include directives are necessary.
|
||||||
|
|
||||||
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
To add a new service, simply drop a `.conf` file in `/etc/finit.d` and
|
||||||
send `SIGHUP` to finit, or call `init q`. Any service read from this
|
send `SIGHUP` to PID 1, or call `finit q`. Any service read from this
|
||||||
directory is flagged as a dynamic service, so changes to their .conf
|
directory is flagged as a dynamic service, so changes to their `.conf`
|
||||||
files, or even removal of the files, is detected at `SIGHUP`.
|
files, or even removal of the files, is detected at `SIGHUP`.
|
||||||
|
|
||||||
- If a service's .conf file has been removed, the service is stopped.
|
- If a service's `.conf` file has been removed, the service is stopped.
|
||||||
- If the file has changed the service is reloaded, stopped and
|
- If the file is modified, the service is reloaded, stopped and started.
|
||||||
restarted.
|
- If a new service is detected, it is started -- respecting runlevels
|
||||||
- If it is a new service, it is started -- respecting runlevels and
|
and return values from any callbacks.
|
||||||
callbacks.
|
|
||||||
|
|
||||||
The `/etc/finit.d` directory was previously the default Finit `runparts`
|
The `/etc/finit.d` directory was previously the default Finit `runparts`
|
||||||
directory. Finit no longer has a default runparts, so make sure to
|
directory. Finit no longer has a default `runparts`, so make sure to
|
||||||
update your setup, or the finit configuration, accordingly.
|
update your setup, or the finit configuration, accordingly.
|
||||||
|
|
||||||
**Note:** Configurations read from `/etc/finit.d` are read *after*
|
**Note:** Configurations read from `/etc/finit.d` are read *after*
|
||||||
@@ -314,8 +313,14 @@ default all services, tasks, run commands and TTYs listed without a set
|
|||||||
of runlevels get a default set `[234]` assigned. The default runlevel
|
of runlevels get a default set `[234]` assigned. The default runlevel
|
||||||
after boot is 2.
|
after boot is 2.
|
||||||
|
|
||||||
To specify an allowed set of runlevels for a `service`, `run` command, `task`,
|
Finit supports runlevels 0-9, and S, with 0 reserved for halt, 6 reboot
|
||||||
or `tty`, add `[NNN]` to it in your `/etc/finit.conf`, like this:
|
and S for services to only run at bootstrap. Runlevel 1 is the single
|
||||||
|
user level, where usually no networking is enabled. In Finit this is
|
||||||
|
more of a policy for the user to define. Normally only runlevels 1-6
|
||||||
|
are used, and even more commonly, only the default runlevel is used.
|
||||||
|
|
||||||
|
To specify an allowed set of runlevels for a `service`, `run` command,
|
||||||
|
`task`, or `tty`, add `[NNN]` to your `/etc/finit.conf`, like this:
|
||||||
|
|
||||||
service [S12345] /sbin/syslogd -n -x -- System log daemon
|
service [S12345] /sbin/syslogd -n -x -- System log daemon
|
||||||
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
run [S] /etc/init.d/acpid start -- Starting ACPI Daemon
|
||||||
@@ -340,7 +345,13 @@ are called in the order listed and subsequent commands are not started
|
|||||||
until a run command has completed.
|
until a run command has completed.
|
||||||
|
|
||||||
Switching between runlevels can be done by calling init with a single
|
Switching between runlevels can be done by calling init with a single
|
||||||
argument, e.g. <kbd>init 5</kbd> switches to runlevel 5.
|
argument, e.g. <kbd>init 5</kbd> switches to runlevel 5. When changing
|
||||||
|
runlevels Finit also automatically reloads all `.conf` files in the
|
||||||
|
`/etc/finit.d/` directory. So if you want to set a new system config,
|
||||||
|
switch to runlevel 1, change all config files in the system, and touch
|
||||||
|
all `.conf` files in `/etc/finit.d` before switching back to the
|
||||||
|
previous runlevel again -- that way Finit can both stop old services and
|
||||||
|
start any new ones for you, without rebooting the system.
|
||||||
|
|
||||||
|
|
||||||
Inetd
|
Inetd
|
||||||
@@ -360,29 +371,25 @@ traffic using a poor man's [TCP wrappers]. The syntax is very similar to
|
|||||||
the traditional `/etc/inetd.conf`, yet keeping with the style of Finit:
|
the traditional `/etc/inetd.conf`, yet keeping with the style of Finit:
|
||||||
|
|
||||||
# Launch SSH on demand, in runlevels 2-5 as root
|
# Launch SSH on demand, in runlevels 2-5 as root
|
||||||
inetd ssh/tcp nowait [2345] @root:root /usr/sbin/sshd -i
|
inetd ssh/tcp nowait [2345] @root:root /usr/sbin/sshd -i
|
||||||
|
|
||||||
A more advanced example:
|
A more advanced example is listed below, please not the *incompatible
|
||||||
|
syntax change* that was made between Finit v1.12 and v1.13 to support
|
||||||
|
deny filters:
|
||||||
|
|
||||||
# Start sshd if inbound connection on eth0, port 222, or
|
# Start sshd if inbound connection on eth0, port 222, or
|
||||||
# inbound on eth1, port 22. Ignore on other interfaces.
|
# inbound on eth1, port 22. Ignore on other interfaces.
|
||||||
inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i
|
inetd 222/tcp@eth0 nowait [2345] /usr/sbin/sshd -i
|
||||||
inetd ssh@eth1:22/tcp nowait [2345] /usr/sbin/sshd -i
|
inetd ssh/tcp@eth1,eth1 nowait [2345] /usr/sbin/sshd -i
|
||||||
|
|
||||||
If `eth0` is your Internet interface you may want to avoid using the
|
If `eth0` is your Internet interface you may want to avoid using the
|
||||||
default port. To run ssh on port 222, and all others on port 22:
|
default port. To run ssh on port 222, and all others on port 22:
|
||||||
|
|
||||||
inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i
|
inetd 222/tcp@eth0 nowait [2345] /usr/sbin/sshd -i
|
||||||
inetd ssh/tcp nowait [2345] /usr/sbin/sshd -i
|
inetd ssh/tcp@*,!eth0 nowait [2345] /usr/sbin/sshd -i
|
||||||
|
|
||||||
|
Compared to Finit v1.12 you must *explicitly deny* access from `eth0`!
|
||||||
|
|
||||||
*This actually adds a deny rule for eth0 on ssh/tcp, implicitly.* You
|
|
||||||
can even list the services in reverse order with the same result:
|
|
||||||
|
|
||||||
inetd ssh/tcp nowait [2345] /usr/sbin/sshd -i
|
|
||||||
inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i
|
|
||||||
|
|
||||||
There is no specific deny syntax available yet, see the TODO file for
|
|
||||||
more details on how this can be implemented.
|
|
||||||
|
|
||||||
**Internal Services**
|
**Internal Services**
|
||||||
|
|
||||||
@@ -415,8 +422,8 @@ Also, remember the UNIX year 2038 bug, or in the case of RFC 868 (and
|
|||||||
some NTP implementations), year 2036!
|
some NTP implementations), year 2036!
|
||||||
|
|
||||||
**Note:** There is currently no verification that the same port is used
|
**Note:** There is currently no verification that the same port is used
|
||||||
more than once. So a standard http service will clash with an ssh
|
more than once. So a standard `inetd http/tcp` service will clash
|
||||||
entry `ssh@*:80/tcp`.
|
with an ssh entry for the same port `inetd 80/tcp` ...
|
||||||
|
|
||||||
|
|
||||||
Hooks, Callbacks & Plugins
|
Hooks, Callbacks & Plugins
|
||||||
@@ -517,42 +524,58 @@ Rebooting & Halting
|
|||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
Finit handles `SIGUSR1` and `SIGUSR2` for reboot and halt, and listens
|
Finit handles `SIGUSR1` and `SIGUSR2` for reboot and halt, and listens
|
||||||
to `/dev/initctl` so system reboot and halt commands should also work.
|
to `/dev/initctl` so system reboot and halt commands also work. This
|
||||||
This latter functionality is implemented in the optional `initctl.so`
|
latter functionality is implemented in the optional `initctl.so` plugin
|
||||||
plugin and can be accessed with the `initctl` command line tool (which
|
and can be accessed with the `telinit` command line tool, symlinked to
|
||||||
is symlinked to `finit`).
|
`finit`).
|
||||||
|
|
||||||
~ # initctl
|
~ # telinit
|
||||||
Usage: initctl [OPTIONS] [<COMMAND> | <q | 1-6>]
|
Usage: telinit [OPTIONS] [q | Q | 0-9]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-h, --help This help text
|
||||||
|
-v, --version Show Finit version
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
q | Q Reload *.conf in /etc/finit.d/, like SIGHUP
|
||||||
|
0 - 9 Change runlevel: 0 halt, 6 reboot
|
||||||
|
|
||||||
|
Finit also implements a more modern API to query status, and start/stop
|
||||||
|
services, called `initctl`.
|
||||||
|
|
||||||
|
~ # initctl -h
|
||||||
|
Usage: initctl [OPTIONS] <COMMAND>
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
-d, --debug Toggle Finit debug
|
|
||||||
-v, --verbose Verbose output
|
-v, --verbose Verbose output
|
||||||
-h, --help This help text
|
-h, --help This help text
|
||||||
|
|
||||||
Commands:
|
Commands:
|
||||||
debug Toggle Finit debug
|
debug Toggle Finit debug
|
||||||
q | reload Reload *.conf in /etc/finit.d/
|
reload Reload *.conf in /etc/finit.d/
|
||||||
runlevel <1-6> Set new runlevel
|
runlevel <0-9> Change runlevel: 0 halt, 6 reboot
|
||||||
status Show status of services
|
status Show status of services
|
||||||
start <JOB#> Start stopped service
|
start <JOB#> Start stopped service
|
||||||
stop <JOB#> Stop running service
|
stop <JOB#> Stop running service
|
||||||
restart <JOB#> Restart (stop/start) running service
|
restart <JOB#> Restart (stop/start) running service
|
||||||
reload <JOB#> Reload (SIGHUP) running service
|
reload <JOB#> Reload (SIGHUP) running service
|
||||||
version Show Finit version
|
version Show Finit version
|
||||||
|
|
||||||
~ # initctl status
|
Remember, you can only start/stop services that match the current
|
||||||
# Status PID Runlevels Service Description
|
runlevel. Hence, if the runlevel is 2, the below Dropbear SSH service
|
||||||
====================================================================================
|
cannot be started.
|
||||||
1 running 480 [S12345] /sbin/watchdog System watchdog daemon
|
|
||||||
2 running 481 [S12345] /sbin/syslogd System log daemon
|
~ # initctl status -v
|
||||||
3 running 519 [S12345] /sbin/klogd Kernel log daemon
|
1 running 476 [S12345] /sbin/watchdog -T 16 -t 2 -F /dev/watchdog
|
||||||
4:1 stopped 0 [345] /sbin/dropbear SSH daemon
|
2 running 477 [S12345] /sbin/syslogd -n -b 3 -D
|
||||||
4:2 stopped 0 [345] /sbin/dropbear SSH daemon
|
3 running 478 [S12345] /sbin/klogd -n
|
||||||
5:1 waiting 0 [2345] internal UNIX rdate service
|
4:1 inetd 0 [2345] internal time allow *:37
|
||||||
5:2 waiting 0 [2345] internal UNIX rdate service
|
4:2 inetd 0 [2345] internal time allow *:37
|
||||||
6:1 waiting 0 [2345] /sbin/telnetd Telnet service
|
4:3 inetd 0 [2345] internal 3737 allow *:3737
|
||||||
6:2 waiting 0 [2345] /sbin/telnetd Telnet service
|
5:1 inetd 0 [2345] /sbin/telnetd allow *:23 deny eth0,eth1
|
||||||
|
5:2 inetd 0 [2345] /sbin/telnetd allow eth0:2323,eth2:2323,eth1:2323
|
||||||
|
6:1 inetd 0 [2345] /sbin/dropbear allow eth0:222
|
||||||
|
6:2 inetd 0 [2345] /sbin/dropbear allow *:22 deny eth0
|
||||||
|
|
||||||
|
|
||||||
Building
|
Building
|
||||||
|
|||||||
@@ -59,17 +59,6 @@ to achieve compatibility would be to add a plugin to finit which reads
|
|||||||
Inetd
|
Inetd
|
||||||
-----
|
-----
|
||||||
|
|
||||||
wkz says we need deny rules and better syntax! we agrees
|
|
||||||
|
|
||||||
|
|
||||||
wkz --> inetd telnet/tcp @!eth0
|
|
||||||
wkz --> inetd 2323/tcp @eth0
|
|
||||||
wkz --> 77/udp wait [2345] @finit/time
|
|
||||||
|
|
||||||
jnn --> telnet@eth0,eth1/tcp
|
|
||||||
jnn --> 2323@eth2/tcp
|
|
||||||
jnn --> 3000/udp wait [2345] time/internal
|
|
||||||
|
|
||||||
Optimize interface filtering by using socket filter. The functions
|
Optimize interface filtering by using socket filter. The functions
|
||||||
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
|
`inet_*_peek()` and `inetd_is_allowed()` used for interace filtering
|
||||||
should be possible to rewrite as socket filters.
|
should be possible to rewrite as socket filters.
|
||||||
|
|||||||
@@ -59,14 +59,16 @@ static int do_send(int cmd, int runlevel)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* telinit q | telinit <1-6> */
|
/* telinit q | telinit <0-9> */
|
||||||
static int usage(int rc)
|
static int usage(int rc)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s <q | 1-6>\n\n"
|
fprintf(stderr, "Usage: %s [OPTIONS] [q | Q | 0-9]\n\n"
|
||||||
"Options:\n"
|
"Options:\n"
|
||||||
" -v, --verbose Verbose output\n"
|
|
||||||
" -h, --help This help text\n\n"
|
" -h, --help This help text\n\n"
|
||||||
" -V, --version Show Finit version\n\n", __progname);
|
" -V, --version Show Finit version\n\n"
|
||||||
|
"Commands:\n"
|
||||||
|
" q | Q Reload *.conf in /etc/finit.d/, like SIGHUP\n"
|
||||||
|
" 0 - 9 Change runlevel: 0 halt, 6 reboot\n\n", __progname);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -95,7 +97,7 @@ int client(int argc, char *argv[])
|
|||||||
if (optind < argc) {
|
if (optind < argc) {
|
||||||
int req = (int)argv[optind][0];
|
int req = (int)argv[optind][0];
|
||||||
|
|
||||||
/* Compat: 'init <1-9>' */
|
/* Compat: 'init <0-9>' */
|
||||||
if (isdigit(req))
|
if (isdigit(req))
|
||||||
return do_send(INIT_CMD_RUNLVL, req);
|
return do_send(INIT_CMD_RUNLVL, req);
|
||||||
|
|
||||||
|
|||||||
@@ -219,14 +219,28 @@ static int getent(char *service, char *proto, struct servent **sv, struct protoe
|
|||||||
{
|
{
|
||||||
*sv = getservbyname(service, proto);
|
*sv = getservbyname(service, proto);
|
||||||
if (!*sv) {
|
if (!*sv) {
|
||||||
_pe("Invalid inetd %s/%s (service/proto), skipping", service, proto);
|
static struct servent s;
|
||||||
return errno = EINVAL;
|
|
||||||
|
s.s_name = service;
|
||||||
|
s.s_port = atonum(service);
|
||||||
|
s.s_proto = NULL;
|
||||||
|
if (!strcmp("tcp", proto) || !strcmp("udp", proto))
|
||||||
|
s.s_proto = proto;
|
||||||
|
|
||||||
|
if (s.s_port == -1 || !s.s_proto) {
|
||||||
|
_e("Invalid/unknown inetd service, cannot create custom entry.");
|
||||||
|
return errno = EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
_d("Creating cutom inetd service %s/%s.", service, proto);
|
||||||
|
s.s_port = htons(s.s_port);
|
||||||
|
*sv = &s;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pv) {
|
if (pv) {
|
||||||
*pv = getprotobyname((*sv)->s_proto);
|
*pv = getprotobyname((*sv)->s_proto);
|
||||||
if (!*pv) {
|
if (!*pv) {
|
||||||
_pe("Cannot find proto %s, skipping.", (*sv)->s_proto);
|
_e("Cannot find proto %s, skipping.", (*sv)->s_proto);
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -242,7 +256,7 @@ static inetd_filter_t *find_filter(inetd_t *inetd, char *ifname)
|
|||||||
inetd_filter_t *filter;
|
inetd_filter_t *filter;
|
||||||
|
|
||||||
if (!ifname)
|
if (!ifname)
|
||||||
ifname = "";
|
ifname = "*";
|
||||||
|
|
||||||
LIST_FOREACH(filter, &inetd->filters, link) {
|
LIST_FOREACH(filter, &inetd->filters, link) {
|
||||||
_d("Checking filters for %s: '%s' vs '%s' (exact match) ...",
|
_d("Checking filters for %s: '%s' vs '%s' (exact match) ...",
|
||||||
@@ -265,20 +279,18 @@ inetd_filter_t *inetd_filter_match(inetd_t *inetd, char *ifname)
|
|||||||
if (filter)
|
if (filter)
|
||||||
return filter;
|
return filter;
|
||||||
|
|
||||||
if (!ifname)
|
|
||||||
ifname = "";
|
|
||||||
|
|
||||||
LIST_FOREACH(filter, &inetd->filters, link) {
|
LIST_FOREACH(filter, &inetd->filters, link) {
|
||||||
_d("Checking filters for %s: '%s' vs '%s' (any match) ...",
|
_d("Checking filters for %s: '%s' vs '%s' (any match) ...",
|
||||||
inetd->name, filter->ifname, ifname);
|
inetd->name, filter->ifname, ifname);
|
||||||
|
|
||||||
if (!strlen(filter->ifname))
|
if (!strcmp(filter->ifname, "*"))
|
||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Poor man's tcpwrappers filtering */
|
||||||
int inetd_allow(inetd_t *inetd, char *ifname)
|
int inetd_allow(inetd_t *inetd, char *ifname)
|
||||||
{
|
{
|
||||||
inetd_filter_t *filter;
|
inetd_filter_t *filter;
|
||||||
@@ -286,21 +298,22 @@ int inetd_allow(inetd_t *inetd, char *ifname)
|
|||||||
if (!inetd)
|
if (!inetd)
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
|
|
||||||
|
if (!ifname)
|
||||||
|
ifname = "*";
|
||||||
|
|
||||||
filter = inetd_filter_match(inetd, ifname);
|
filter = inetd_filter_match(inetd, ifname);
|
||||||
if (filter) {
|
if (filter) {
|
||||||
_d("Filter %s for inetd %s already exists, skipping.", ifname ?: "*", inetd->name);
|
_d("Filter %s for inetd %s already exists, skipping.", ifname, inetd->name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Allow iface %s for service %s (port %d)", ifname ?: "*", inetd->name, inetd->port);
|
_d("Allow iface %s for service %s (port %d)", ifname, inetd->name, inetd->port);
|
||||||
filter = calloc(1, sizeof(*filter));
|
filter = calloc(1, sizeof(*filter));
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
_e("Out of memory, cannot add filter to service %s", inetd->name);
|
_e("Out of memory, cannot add filter to service %s", inetd->name);
|
||||||
return errno = ENOMEM;
|
return errno = ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ifname)
|
|
||||||
ifname = "";
|
|
||||||
filter->deny = 0;
|
filter->deny = 0;
|
||||||
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
|
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
|
||||||
LIST_INSERT_HEAD(&inetd->filters, filter, link);
|
LIST_INSERT_HEAD(&inetd->filters, filter, link);
|
||||||
@@ -315,26 +328,23 @@ int inetd_deny(inetd_t *inetd, char *ifname)
|
|||||||
if (!inetd)
|
if (!inetd)
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
|
|
||||||
/* Reset to NULL for debug output below */
|
if (!ifname)
|
||||||
if (!ifname[0])
|
ifname = "*";
|
||||||
ifname = NULL;
|
|
||||||
|
|
||||||
filter = find_filter(inetd, ifname);
|
filter = find_filter(inetd, ifname);
|
||||||
if (filter) {
|
if (filter) {
|
||||||
_d("%s filter %s for inetd %s already exists, cannot set deny filter for same, skipping.",
|
_d("%s filter %s for inetd %s already exists, cannot set deny filter for same, skipping.",
|
||||||
filter->deny ? "Deny" : "Allow", ifname ?: "*", inetd->name);
|
filter->deny ? "Deny" : "Allow", ifname, inetd->name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
_d("Deny iface %s for service %s (port %d)", ifname ?: "*", inetd->name, inetd->port);
|
_d("Deny iface %s for service %s (port %d)", ifname, inetd->name, inetd->port);
|
||||||
filter = calloc(1, sizeof(*filter));
|
filter = calloc(1, sizeof(*filter));
|
||||||
if (!filter) {
|
if (!filter) {
|
||||||
_e("Out of memory, cannot add filter to service %s", inetd->name);
|
_e("Out of memory, cannot add filter to service %s", inetd->name);
|
||||||
return errno = ENOMEM;
|
return errno = ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ifname)
|
|
||||||
ifname = "";
|
|
||||||
filter->deny = 1;
|
filter->deny = 1;
|
||||||
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
|
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
|
||||||
LIST_INSERT_HEAD(&inetd->filters, filter, link);
|
LIST_INSERT_HEAD(&inetd->filters, filter, link);
|
||||||
@@ -362,9 +372,10 @@ int inetd_is_allowed(inetd_t *inetd, char *ifname)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inetd_match(inetd_t *inetd, char *service, char *proto, char *port)
|
int inetd_match(inetd_t *inetd, char *service, char *proto)
|
||||||
{
|
{
|
||||||
int cport = port ? atonum(port) : -1;
|
struct servent *sv = NULL;
|
||||||
|
struct protoent *pv = NULL;
|
||||||
|
|
||||||
if (!inetd || !service || !proto)
|
if (!inetd || !service || !proto)
|
||||||
return errno = EINVAL;
|
return errno = EINVAL;
|
||||||
@@ -372,20 +383,12 @@ int inetd_match(inetd_t *inetd, char *service, char *proto, char *port)
|
|||||||
if (strncmp(inetd->name, service, sizeof(inetd->name)))
|
if (strncmp(inetd->name, service, sizeof(inetd->name)))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (cport != -1) {
|
if (getent(service, proto, &sv, &pv))
|
||||||
if (inetd->port == cport)
|
return 0;
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
struct servent *sv = NULL;
|
|
||||||
struct protoent *pv = NULL;
|
|
||||||
|
|
||||||
if (getent(service, proto, &sv, &pv))
|
if (inetd->proto == ntohs(pv->p_proto) &&
|
||||||
return 0;
|
inetd->port == ntohs(sv->s_port))
|
||||||
|
return 1;
|
||||||
if (inetd->proto == ntohs(pv->p_proto) &&
|
|
||||||
inetd->port == ntohs(sv->s_port))
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -410,7 +413,7 @@ int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!strlen(filter->ifname))
|
if (!strlen(filter->ifname))
|
||||||
snprintf(ifname, sizeof(ifname), "ANY");
|
snprintf(ifname, sizeof(ifname), "*");
|
||||||
else
|
else
|
||||||
strlcpy(ifname, filter->ifname, sizeof(ifname));
|
strlcpy(ifname, filter->ifname, sizeof(ifname));
|
||||||
|
|
||||||
@@ -432,7 +435,7 @@ int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!strlen(filter->ifname))
|
if (!strlen(filter->ifname))
|
||||||
snprintf(ifname, sizeof(ifname), "ANY");
|
snprintf(ifname, sizeof(ifname), "*");
|
||||||
else
|
else
|
||||||
strlcpy(ifname, filter->ifname, sizeof(ifname));
|
strlcpy(ifname, filter->ifname, sizeof(ifname));
|
||||||
|
|
||||||
@@ -465,7 +468,7 @@ int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
|
|||||||
* If equivalent service exists already service_register() will instead call
|
* If equivalent service exists already service_register() will instead call
|
||||||
* inetd_allow().
|
* inetd_allow().
|
||||||
*/
|
*/
|
||||||
int inetd_new(inetd_t *inetd, char *service, char *proto, int forking)
|
int inetd_new(inetd_t *inetd, char *service, char *proto, int forking, void *arg)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
struct servent *sv = NULL;
|
struct servent *sv = NULL;
|
||||||
@@ -494,6 +497,9 @@ int inetd_new(inetd_t *inetd, char *service, char *proto, int forking)
|
|||||||
/* Reset descriptor, used internally */
|
/* Reset descriptor, used internally */
|
||||||
inetd->watcher.fd = -1;
|
inetd->watcher.fd = -1;
|
||||||
|
|
||||||
|
/* Setup socket callback argument */
|
||||||
|
inetd->arg = arg;
|
||||||
|
|
||||||
_d("New service %s (default port %d proto %s:%d)", service, inetd->port, sv->s_proto, pv->p_proto);
|
_d("New service %s (default port %d proto %s:%d)", service, inetd->port, sv->s_proto, pv->p_proto);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -509,60 +515,6 @@ int inetd_del(inetd_t *inetd)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int inetd_init(inetd_t *inetd, void *arg, char *ifname, char *port)
|
|
||||||
{
|
|
||||||
int result, cport = -1;
|
|
||||||
svc_t *svc;
|
|
||||||
|
|
||||||
if (!inetd || !arg)
|
|
||||||
return errno = EINVAL;
|
|
||||||
|
|
||||||
if (port)
|
|
||||||
cport = atonum(port);
|
|
||||||
|
|
||||||
if (cport != -1 && cport != inetd->port) {
|
|
||||||
inetd->std = 0;
|
|
||||||
inetd->port = cport;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup socket callback argument */
|
|
||||||
inetd->arg = arg;
|
|
||||||
|
|
||||||
/* Poor man's tcpwrappers filtering */
|
|
||||||
result = inetd_allow(inetd, ifname);
|
|
||||||
|
|
||||||
/* For each similar service, on other port, add their ifnames as deny to ours. */
|
|
||||||
for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(0)) {
|
|
||||||
inetd_filter_t *filter;
|
|
||||||
|
|
||||||
/* Skip ourselves */
|
|
||||||
if (&svc->inetd == inetd)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Skip different service types (telnet != ssh) */
|
|
||||||
if (strcmp(svc->inetd.name, inetd->name))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Deny all their interfaces from using my service */
|
|
||||||
LIST_FOREACH(filter, &svc->inetd.filters, link) {
|
|
||||||
if (filter->deny)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
inetd_deny(inetd, filter->ifname);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Deny my interfaces from using their service ... */
|
|
||||||
LIST_FOREACH(filter, &inetd->filters, link) {
|
|
||||||
if (filter->deny)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
inetd_deny(&svc->inetd, filter->ifname);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local Variables:
|
* Local Variables:
|
||||||
* version-control: t
|
* version-control: t
|
||||||
|
|||||||
@@ -60,11 +60,10 @@ void inetd_stop (inetd_t *inetd);
|
|||||||
|
|
||||||
int inetd_respawn (pid_t pid);
|
int inetd_respawn (pid_t pid);
|
||||||
|
|
||||||
int inetd_new (inetd_t *inetd, char *service, char *proto, int forking);
|
int inetd_new (inetd_t *inetd, char *service, char *proto, int forking, void *arg);
|
||||||
int inetd_del (inetd_t *inetd);
|
int inetd_del (inetd_t *inetd);
|
||||||
|
|
||||||
int inetd_init (inetd_t *inetd, void *arg, char *ifname, char *port);
|
int inetd_match (inetd_t *inetd, char *service, char *proto);
|
||||||
int inetd_match (inetd_t *inetd, char *service, char *proto, char *port);
|
|
||||||
int inetd_filter_str (inetd_t *inetd, char *str, size_t len);
|
int inetd_filter_str (inetd_t *inetd, char *str, size_t len);
|
||||||
|
|
||||||
int inetd_allow (inetd_t *inetd, char *ifname);
|
int inetd_allow (inetd_t *inetd, char *ifname);
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ static int usage(int rc)
|
|||||||
"Commands:\n"
|
"Commands:\n"
|
||||||
" debug Toggle Finit debug\n"
|
" debug Toggle Finit debug\n"
|
||||||
" reload Reload *.conf in /etc/finit.d/\n"
|
" reload Reload *.conf in /etc/finit.d/\n"
|
||||||
" runlevel <1-6> Set new runlevel\n"
|
" runlevel <0-9> Change runlevel: 0 halt, 6 reboot\n"
|
||||||
" status Show status of services\n"
|
" status Show status of services\n"
|
||||||
" start <JOB#> Start stopped service\n"
|
" start <JOB#> Start stopped service\n"
|
||||||
" stop <JOB#> Stop running service\n"
|
" stop <JOB#> Stop running service\n"
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ static int is_norespawn (void);
|
|||||||
static void restart_lost_procs (void);
|
static void restart_lost_procs (void);
|
||||||
static void svc_dance (svc_t *svc);
|
static void svc_dance (svc_t *svc);
|
||||||
static void utmp_save (int pre, int now);
|
static void utmp_save (int pre, int now);
|
||||||
static svc_t *find_inetd_svc (char *path, char *service, char *proto, char *port);
|
static svc_t *find_inetd_svc (char *path, char *service, char *proto);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -537,7 +537,7 @@ int service_register(int type, char *line, time_t mtime, char *username)
|
|||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
int forking = 0;
|
int forking = 0;
|
||||||
#endif
|
#endif
|
||||||
char *service = NULL, *proto = NULL, *iface = NULL, *port = NULL;
|
char *service = NULL, *proto = NULL, *ifaces = NULL;
|
||||||
char *cmd, *desc, *runlevels = NULL;
|
char *cmd, *desc, *runlevels = NULL;
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
plugin_t *plugin = NULL;
|
plugin_t *plugin = NULL;
|
||||||
@@ -582,37 +582,42 @@ int service_register(int type, char *line, time_t mtime, char *username)
|
|||||||
goto incomplete;
|
goto incomplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Example: inetd ssh@eth0:222/tcp */
|
/* Example: inetd ssh/tcp@eth0,eth1 or 222/tcp@eth2 */
|
||||||
if (service) {
|
if (service) {
|
||||||
|
ifaces = strchr(service, '@');
|
||||||
|
if (ifaces)
|
||||||
|
*ifaces++ = 0;
|
||||||
|
|
||||||
proto = strchr(service, '/');
|
proto = strchr(service, '/');
|
||||||
if (!proto)
|
if (!proto)
|
||||||
goto incomplete;
|
goto incomplete;
|
||||||
*proto++ = 0;
|
*proto++ = 0;
|
||||||
|
|
||||||
port = strchr(service, ':');
|
|
||||||
if (port)
|
|
||||||
*port++ = 0;
|
|
||||||
|
|
||||||
iface = strchr(service, '@');
|
|
||||||
if (iface)
|
|
||||||
*iface++ = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
/* Find plugin that provides a callback for this inetd service */
|
/* Find plugin that provides a callback for this inetd service */
|
||||||
if (type == SVC_TYPE_INETD) {
|
if (type == SVC_TYPE_INETD) {
|
||||||
if (!strncasecmp(cmd, "internal", 8)) {
|
if (!strncasecmp(cmd, "internal", 8)) {
|
||||||
plugin = plugin_find(service);
|
char *ptr, *ps = service;
|
||||||
|
|
||||||
|
/* internal.service */
|
||||||
|
ptr = strchr(cmd, '.');
|
||||||
|
if (ptr) {
|
||||||
|
*ptr++ = 0;
|
||||||
|
ps = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin = plugin_find(ps);
|
||||||
if (!plugin || !plugin->inetd.cmd) {
|
if (!plugin || !plugin->inetd.cmd) {
|
||||||
_e("Inetd service %s has no internal plugin, skipping.", service);
|
_e("Inetd service %s has no internal plugin, skipping.", service);
|
||||||
return errno = ENOENT;
|
return errno = ENOENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if known inetd, then add ifname for filtering only. */
|
/* Check if known inetd, then add ifnames for filtering only. */
|
||||||
svc = find_inetd_svc(cmd, service, proto, port);
|
svc = find_inetd_svc(cmd, service, proto);
|
||||||
if (svc)
|
if (svc)
|
||||||
return inetd_allow(&svc->inetd, iface);
|
goto inetd_setup;
|
||||||
|
|
||||||
id = svc_next_id(cmd);
|
id = svc_next_id(cmd);
|
||||||
}
|
}
|
||||||
@@ -644,23 +649,6 @@ int service_register(int type, char *line, time_t mtime, char *username)
|
|||||||
strlcpy(svc->username, username, sizeof(svc->username));
|
strlcpy(svc->username, username, sizeof(svc->username));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef INETD_DISABLED
|
|
||||||
if (svc_is_inetd(svc)) {
|
|
||||||
int result;
|
|
||||||
|
|
||||||
_d("Creating new svc job %d inetd %s proto %s iface %s port %s",
|
|
||||||
svc->job, service, proto, iface, port);
|
|
||||||
result = inetd_new(&svc->inetd, service, proto, forking);
|
|
||||||
result += inetd_init(&svc->inetd, svc, iface, port);
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
_e("Failed registering new inetd service %s.", service);
|
|
||||||
inetd_del(&svc->inetd);
|
|
||||||
return svc_del(svc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (plugin) {
|
if (plugin) {
|
||||||
/* Internal plugin provides this service */
|
/* Internal plugin provides this service */
|
||||||
svc->inetd.cmd = plugin->inetd.cmd;
|
svc->inetd.cmd = plugin->inetd.cmd;
|
||||||
@@ -681,6 +669,35 @@ int service_register(int type, char *line, time_t mtime, char *username)
|
|||||||
svc->runlevels = parse_runlevels(runlevels);
|
svc->runlevels = parse_runlevels(runlevels);
|
||||||
_d("Service %s runlevel 0x%2x", svc->cmd, svc->runlevels);
|
_d("Service %s runlevel 0x%2x", svc->cmd, svc->runlevels);
|
||||||
|
|
||||||
|
#ifndef INETD_DISABLED
|
||||||
|
if (svc_is_inetd(svc)) {
|
||||||
|
char *iface;
|
||||||
|
|
||||||
|
_d("Creating new svc job %d inetd %s proto %s iface %s",
|
||||||
|
svc->job, service, proto, ifaces);
|
||||||
|
if (inetd_new(&svc->inetd, service, proto, forking, svc)) {
|
||||||
|
_e("Failed registering new inetd service %s.", service);
|
||||||
|
inetd_del(&svc->inetd);
|
||||||
|
return svc_del(svc);
|
||||||
|
}
|
||||||
|
|
||||||
|
inetd_setup:
|
||||||
|
if (!ifaces) {
|
||||||
|
_d("No specific iface listed for %s, allowing ANY.", service);
|
||||||
|
return inetd_allow(&svc->inetd, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
_d("Setting up interface filters for inetd service %s ...", service);
|
||||||
|
for (iface = strtok(ifaces, ","); iface; iface = strtok(NULL, ",")) {
|
||||||
|
_d("Checking interface name %s ...", iface);
|
||||||
|
if (iface[0] == '!')
|
||||||
|
inetd_deny(&svc->inetd, &iface[1]);
|
||||||
|
else
|
||||||
|
inetd_allow(&svc->inetd, iface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,7 +831,7 @@ static void utmp_save(int pre, int now)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef INETD_DISABLED
|
#ifndef INETD_DISABLED
|
||||||
static svc_t *find_inetd_svc(char *path, char *service, char *proto, char *port)
|
static svc_t *find_inetd_svc(char *path, char *service, char *proto)
|
||||||
{
|
{
|
||||||
svc_t *svc;
|
svc_t *svc;
|
||||||
|
|
||||||
@@ -822,8 +839,8 @@ static svc_t *find_inetd_svc(char *path, char *service, char *proto, char *port)
|
|||||||
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (inetd_match(&svc->inetd, service, proto, port)) {
|
if (inetd_match(&svc->inetd, service, proto)) {
|
||||||
_d("Found a matching inetd svc for %s %s %s %s", path, service, proto, port);
|
_d("Found a matching inetd svc for %s %s %s", path, service, proto);
|
||||||
return svc;
|
return svc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user