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:
Joachim Nilsson committed 2015-06-15 14:15:39 +02:00
1 parent b0c759e518
commit 03573b41ca
7 files changed
+177 -195

No files matched your search

+43 -91
View File
@@ -219,14 +219,28 @@ static int getent(char *service, char *proto, struct servent **sv, struct protoe
{
*sv = getservbyname(service, proto);
if (!*sv) {
_pe("Invalid inetd %s/%s (service/proto), skipping", service, proto);
return errno = EINVAL;
static struct servent s;
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) {
*pv = getprotobyname((*sv)->s_proto);
if (!*pv) {
_pe("Cannot find proto %s, skipping.", (*sv)->s_proto);
_e("Cannot find proto %s, skipping.", (*sv)->s_proto);
return errno = EINVAL;
}
}
@@ -242,7 +256,7 @@ static inetd_filter_t *find_filter(inetd_t *inetd, char *ifname)
inetd_filter_t *filter;
if (!ifname)
ifname = "";
ifname = "*";
LIST_FOREACH(filter, &inetd->filters, link) {
_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)
return filter;
if (!ifname)
ifname = "";
LIST_FOREACH(filter, &inetd->filters, link) {
_d("Checking filters for %s: '%s' vs '%s' (any match) ...",
inetd->name, filter->ifname, ifname);
if (!strlen(filter->ifname))
if (!strcmp(filter->ifname, "*"))
return filter;
}
return NULL;
}
/* Poor man's tcpwrappers filtering */
int inetd_allow(inetd_t *inetd, char *ifname)
{
inetd_filter_t *filter;
@@ -286,21 +298,22 @@ int inetd_allow(inetd_t *inetd, char *ifname)
if (!inetd)
return errno = EINVAL;
if (!ifname)
ifname = "*";
filter = inetd_filter_match(inetd, ifname);
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;
}
_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));
if (!filter) {
_e("Out of memory, cannot add filter to service %s", inetd->name);
return errno = ENOMEM;
}
if (!ifname)
ifname = "";
filter->deny = 0;
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
LIST_INSERT_HEAD(&inetd->filters, filter, link);
@@ -315,26 +328,23 @@ int inetd_deny(inetd_t *inetd, char *ifname)
if (!inetd)
return errno = EINVAL;
/* Reset to NULL for debug output below */
if (!ifname[0])
ifname = NULL;
if (!ifname)
ifname = "*";
filter = find_filter(inetd, ifname);
if (filter) {
_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;
}
_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));
if (!filter) {
_e("Out of memory, cannot add filter to service %s", inetd->name);
return errno = ENOMEM;
}
if (!ifname)
ifname = "";
filter->deny = 1;
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
LIST_INSERT_HEAD(&inetd->filters, filter, link);
@@ -362,9 +372,10 @@ int inetd_is_allowed(inetd_t *inetd, char *ifname)
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)
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)))
return 0;
if (cport != -1) {
if (inetd->port == cport)
return 1;
} else {
struct servent *sv = NULL;
struct protoent *pv = NULL;
if (getent(service, proto, &sv, &pv))
return 0;
if (getent(service, proto, &sv, &pv))
return 0;
if (inetd->proto == ntohs(pv->p_proto) &&
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;
}
@@ -410,7 +413,7 @@ int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
continue;
if (!strlen(filter->ifname))
snprintf(ifname, sizeof(ifname), "ANY");
snprintf(ifname, sizeof(ifname), "*");
else
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))
snprintf(ifname, sizeof(ifname), "ANY");
snprintf(ifname, sizeof(ifname), "*");
else
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
* 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;
struct servent *sv = NULL;
@@ -494,6 +497,9 @@ int inetd_new(inetd_t *inetd, char *service, char *proto, int forking)
/* Reset descriptor, used internally */
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);
return 0;
@@ -509,60 +515,6 @@ int inetd_del(inetd_t *inetd)
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:
* version-control: t