mirror of
https://github.com/troglobit/finit.git
synced 2026-10-02 22:13:01 +07:00
Fix #101: remove built-in inetd from finit
This patch removes the built-in inetd support from Finit. We recommend using an external inetd instead, e.g. xinetd. If you liked the feature set our inetd provided; filtering per interface and port redirection, then please let us know or use the code in this patch (MIT licensed) to recreate it. We are open to reintroducing it, but then as a stand-alone daemon like the bundled watchdogd and getty. So long for now, old friend. Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
+4
-17
@@ -13,6 +13,9 @@ make sure to read the whole changelog when upgrading.
|
||||
|
||||
### Changes
|
||||
* Introducing Finit progress 𝓜𝓸𝓭𝓮𝓻𝓷
|
||||
* Removed built-in inetd super server. If you need this functionality,
|
||||
use an external inetd, like xinetd, instead. A pull request for a
|
||||
stand-alone inetd, like watchdogd and getty, is most welcome!
|
||||
* Incompatible `configure` script changes, i.e., you must give proper
|
||||
path arguments to the script, no more guessing just GNU defaults.
|
||||
There are examples in the documentation and the `contrib/` section
|
||||
@@ -76,8 +79,7 @@ make sure to read the whole changelog when upgrading.
|
||||
* Drop `--enable-rw-roots` configure option, use `rw` for your `/`
|
||||
partition in `/etc/fstab` instead to trigger remount at boot
|
||||
* Drop default tty speed (38400) and use 0 (kernel default) instead
|
||||
* Make `:ID` optional for real, use NULL/zero internally and only
|
||||
force :ID (numbered) for inetd services, this allows ...
|
||||
* Make `:ID` optional, use NULL/zero internally this allows ...
|
||||
* Handle use-cases where multiple services share the same PID filem
|
||||
and thus the same condition path, e.g. different instances for
|
||||
different runlevels. Allow custom condition path with `name:foo`
|
||||
@@ -95,14 +97,8 @@ make sure to read the whole changelog when upgrading.
|
||||
|
||||
* Fix #96: Start udevd as a proper service
|
||||
* Ensure we track run commands as well as task/service, once per runlevel
|
||||
* Fix #98: FTBFS with `--disable-inetd`
|
||||
* Make sure to unblock UDP inetd services when connection terminates.
|
||||
Regression introduced in v3.1
|
||||
* Ensure run/tasks also go to stopping state on exit, like services,
|
||||
otherwise it is unnecessarily hard to restart them
|
||||
* Fix #99: Do not try to `SIGKILL` inetd services, they are not backed
|
||||
by a PID. This caused a use after free issue crashing finit. Found
|
||||
and fixed by Tobias Waldekranz, Westermo
|
||||
* Fix missing OS/Finit title bug, adds leading newline before banner
|
||||
* Remove "Failed connecting to watchdog ..." error message on systems
|
||||
that do not have a watchdog
|
||||
@@ -110,23 +106,14 @@ make sure to read the whole changelog when upgrading.
|
||||
not yet exist (symlink to `/run`). Added compat layer for access
|
||||
* Fix #103: Register multiple getty if `@console` resolves to >1 TTY,
|
||||
* Fix #105: Only remove /etc/nologin when moving from runlevel 0, 1, 6
|
||||
* Fix #106: Don't mark inetd connections for deletion at .conf reload.
|
||||
Fixed by Jonas Johansson, Westermo
|
||||
* Fix #107: Stop spawned inetd conncections when stopping inetd service.
|
||||
Fixed by Jonas Johansson, Westermo
|
||||
* Fix #109: Support for PID files in sub-directories to `/var/run`
|
||||
* Handle rename of PID files, by Robert Andersson, Atlas Copco
|
||||
* Fix #111: Only restart inetd services when necessary. E.g., if the
|
||||
listening interface is changed. Only stop established connections
|
||||
which are no longer allowed, i.e. do not touch already allowed
|
||||
established connections. Fixed by Jonas Johansson, Westermo
|
||||
* Fix #120: Redirect `stdin` to `/dev/null` for services by default
|
||||
* Fix #122: Switch to `nanosleep()` to achieve "signal safe" sleep,
|
||||
fixed by Jacques de Laval, Westermo
|
||||
* Fix #124: Lingering processes in process group when session leader
|
||||
exits. E.g., lingering `logit` processes when parent dies
|
||||
* Fix: update inetd service args on config change. Found and fixed by
|
||||
Petrus Hellgren, Westermo
|
||||
* Fix service name matching, e.g. for condition handling, may match with
|
||||
wrong service, by Jonas Holmberg, Westermo
|
||||
* Run all run-parts scripts using `/bin/sh -c foo` just like the standard
|
||||
|
||||
@@ -74,10 +74,6 @@ AC_ARG_ENABLE(redirect,
|
||||
AS_HELP_STRING([--enable-redirect], [Redirect service output to /dev/null, default: no]),,[
|
||||
enable_redirect_output=no])
|
||||
|
||||
AC_ARG_ENABLE(inetd,
|
||||
AS_HELP_STRING([--disable-inetd], [Disable built-in inetd super server, default enabled]),,[
|
||||
enable_inetd=yes])
|
||||
|
||||
AC_ARG_ENABLE(logit,
|
||||
AS_HELP_STRING([--disable-logit], [Disable logit, used for log redirection, default: enable]),,[
|
||||
enable_logit=yes])
|
||||
@@ -99,11 +95,6 @@ enable_all_plugins=auto
|
||||
AC_PLUGIN([alsa-utils], [no], [Save and restore ALSA sound settings using alsactl])
|
||||
AC_PLUGIN([dbus], [no], [Setup and start system message bus, D-Bus])
|
||||
AC_PLUGIN([hotplug], [yes], [Setup and start udev or mdev hotplug daemon])
|
||||
AC_PLUGIN([inetd-echo], [no], [Inetd plugin: echo server, RFC862])
|
||||
AC_PLUGIN([inetd-chargen], [no], [Inetd plugin: character generator, RFC864])
|
||||
AC_PLUGIN([inetd-daytime], [no], [Inetd plugin: daytime server, RFC867])
|
||||
AC_PLUGIN([inetd-discard], [no], [Inetd plugin: discard server, RFC863])
|
||||
AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868])
|
||||
AC_PLUGIN([modules-load], [no], [Scans /etc/modules-load.d for modules to load])
|
||||
AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf])
|
||||
AC_PLUGIN([x11-common], [no], [Console setup (for X)])
|
||||
@@ -174,10 +165,6 @@ AS_IF([test "x$enable_redirect" = "xyes"], [
|
||||
AC_DEFINE(REDIRECT_OUTPUT, 1, [Enable redirection of service output to /dev/null])])
|
||||
|
||||
### Disable features ###########################################################################
|
||||
AS_IF([test "x$enable_inetd" != "xno"], [
|
||||
enable_inetd="yes"
|
||||
AC_DEFINE(INETD_ENABLED, 1, [Enable built-in inetd])])
|
||||
|
||||
AS_IF([test "x$enable_logit" != "xno"], [
|
||||
AC_DEFINE(LOGIT_ENABLED, 1, [Enable logit tool, used for log redirection by Finit])])
|
||||
|
||||
@@ -232,7 +219,6 @@ AS_IF([test "x$with_random_seed" != "xno"], [
|
||||
|
||||
# Control build with automake flags
|
||||
AM_CONDITIONAL(STATIC, [test "x$enable_static" = "xyes"])
|
||||
AM_CONDITIONAL(INETD, [test "x$enable_inetd" = "xyes"])
|
||||
AM_CONDITIONAL(WATCHDOGD, [test "x$enable_watchdog" = "xyes"])
|
||||
AM_CONDITIONAL(LOGIT, [test "x$enable_logit" = "xyes"])
|
||||
AM_CONDITIONAL(DOC, [test "x$enable_doc" = "xyes"])
|
||||
@@ -278,7 +264,6 @@ Behavior:
|
||||
Optional features:
|
||||
Install doc/..........: $enable_doc
|
||||
Install contrib/......: $enable_contrib
|
||||
Built-in inetd........: $enable_inetd
|
||||
Built-in watchdogd....: $enable_watchdog
|
||||
Built-in logrotate....: $enable_logrotate
|
||||
Scripting tool logit..: $enable_logit
|
||||
|
||||
@@ -21,28 +21,6 @@ if BUILD_HOTPLUG_PLUGIN
|
||||
libplug_la_SOURCES += hotplug.c
|
||||
endif
|
||||
|
||||
if INETD
|
||||
if BUILD_INETD_ECHO_PLUGIN
|
||||
libplug_la_SOURCES += echo.c
|
||||
endif
|
||||
|
||||
if BUILD_INETD_CHARGEN_PLUGIN
|
||||
libplug_la_SOURCES += chargen.c
|
||||
endif
|
||||
|
||||
if BUILD_INETD_DAYTIME_PLUGIN
|
||||
libplug_la_SOURCES += daytime.c
|
||||
endif
|
||||
|
||||
if BUILD_INETD_DISCARD_PLUGIN
|
||||
libplug_la_SOURCES += discard.c
|
||||
endif
|
||||
|
||||
if BUILD_INETD_TIME_PLUGIN
|
||||
libplug_la_SOURCES += time.c
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_MODULES_LOAD_PLUGIN
|
||||
libplug_la_SOURCES += modules-load.c
|
||||
endif
|
||||
@@ -70,28 +48,6 @@ if BUILD_HOTPLUG_PLUGIN
|
||||
pkglib_LTLIBRARIES += hotplug.la
|
||||
endif
|
||||
|
||||
if INETD
|
||||
if BUILD_INETD_ECHO_PLUGIN
|
||||
pkglib_LTLIBRARIES += echo.la
|
||||
endif
|
||||
|
||||
if BUILD_INETD_CHARGEN_PLUGIN
|
||||
pkglib_LTLIBRARIES += chargen.la
|
||||
endif
|
||||
|
||||
if BUILD_INETD_DAYTIME_PLUGIN
|
||||
pkglib_LTLIBRARIES += daytime.la
|
||||
endif
|
||||
|
||||
if BUILD_INETD_DISCARD_PLUGIN
|
||||
pkglib_LTLIBRARIES += discard.la
|
||||
endif
|
||||
|
||||
if BUILD_INETD_TIME_PLUGIN
|
||||
pkglib_LTLIBRARIES += time.la
|
||||
endif
|
||||
endif
|
||||
|
||||
if BUILD_MODULES_LOAD_PLUGIN
|
||||
pkglib_LTLIBRARIES += modules-load.la
|
||||
endif
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
/* Optional inetd plugin for the Character Generator Protocol, RFC 864
|
||||
*
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
#define NAME "chargen"
|
||||
#define PATTERN "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ "
|
||||
|
||||
static char *generator(char *buf, size_t buflen)
|
||||
{
|
||||
size_t num, len, width = 72;
|
||||
static size_t pos = 0;
|
||||
const char pattern[] = PATTERN;
|
||||
|
||||
if (buflen < width)
|
||||
width = buflen;
|
||||
|
||||
len = width;
|
||||
if (len + 3 > buflen)
|
||||
len = buflen - 3;
|
||||
if (pos + len > sizeof(pattern)) {
|
||||
num = sizeof(pattern) - pos;
|
||||
len -= num;
|
||||
} else {
|
||||
num = width;
|
||||
if (num + 3 > buflen)
|
||||
num = buflen - 3;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
strncpy(buf, &pattern[pos], num--);
|
||||
if (len++)
|
||||
strncpy(&buf[num], pattern, len);
|
||||
strlcat(buf, "\r\n", width);
|
||||
|
||||
if (++pos >= sizeof(pattern) - 1)
|
||||
pos = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
|
||||
{
|
||||
len = recvfrom(sd, buf, len, MSG_DONTWAIT, sa, sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len)
|
||||
{
|
||||
char *pattern = generator(buf, len);
|
||||
|
||||
return sendto(sd, pattern, strlen(pattern), MSG_DONTWAIT, sa, sa_len);
|
||||
}
|
||||
|
||||
static int cb(int type)
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len))
|
||||
return -1;
|
||||
|
||||
return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -1,102 +0,0 @@
|
||||
/* Optional inetd plugin for Daytime Protocol, RFC 867
|
||||
*
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
#define NAME "daytime"
|
||||
|
||||
|
||||
static char *daytime(char *buf, size_t len)
|
||||
{
|
||||
time_t t;
|
||||
struct tm *tmp;
|
||||
|
||||
t = time(NULL);
|
||||
tmp = localtime(&t);
|
||||
|
||||
memset(buf, 0, len);
|
||||
strftime(buf, len, "%a, %B %d, %Y %T-%Z", tmp);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
|
||||
{
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len)
|
||||
{
|
||||
char *now = daytime(buf, len);
|
||||
|
||||
return sendto(sd, now, strlen(now), MSG_DONTWAIT, sa, sa_len);
|
||||
}
|
||||
|
||||
static int cb(int type)
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len))
|
||||
return -1;
|
||||
|
||||
return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
}
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -1,67 +0,0 @@
|
||||
/* Optional inetd plugin for the Discard Protocol, RFC 863
|
||||
*
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
static int cb(int type)
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
ssize_t len;
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *)&sa, &sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = "discard", /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
@@ -1,81 +0,0 @@
|
||||
/* Optional inetd plugin for the Echo Protocol, RFC 862
|
||||
*
|
||||
* Copyright (c) 2016-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
#define NAME "echo"
|
||||
|
||||
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
|
||||
{
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int cb(int type)
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
ssize_t len;
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
len = recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
return sendto(sd, buf, len, MSG_DONTWAIT, (struct sockaddr *)&sa, sa_len);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
},
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+1
-1
@@ -287,7 +287,7 @@ static void pidfile_reconf(void *arg)
|
||||
* WAITING to RUNNING will reassert their conditions in that loop,
|
||||
* which in turn may unlock other services, and so on.
|
||||
*/
|
||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK | SVC_TYPE_INETD);
|
||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK);
|
||||
}
|
||||
|
||||
static void pidfile_init(void *arg)
|
||||
|
||||
-116
@@ -1,116 +0,0 @@
|
||||
/* Optional inetd plugin for Time Protocol (rdate), RFC 868
|
||||
*
|
||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h> /* STDIN_FILENO */
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "plugin.h"
|
||||
|
||||
#define NAME "time"
|
||||
|
||||
/* UNIX epoch starts midnight, 1st Jan, 1970 */
|
||||
#define EPOCH_OFFSET 2208988800ULL
|
||||
|
||||
/* Return number of seconds since midnight, 1st Jan, 1900 */
|
||||
static char *rfctime(char *buf, size_t *len)
|
||||
{
|
||||
time_t now;
|
||||
|
||||
now = time(NULL);
|
||||
if ((time_t)-1 == now)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Account for UNIX epoch offset, and
|
||||
* convert to network byte order
|
||||
*/
|
||||
now += EPOCH_OFFSET;
|
||||
now = htonl(now);
|
||||
|
||||
*len = sizeof(now);
|
||||
memcpy(buf, &now, *len);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static int recv_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t *sa_len)
|
||||
{
|
||||
len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, sa, sa_len);
|
||||
if (-1 == len)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
if (inetd_check_loop(sa, *sa_len, NAME))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int send_peer(int sd, char *buf, ssize_t len, struct sockaddr *sa, socklen_t sa_len)
|
||||
{
|
||||
char *now;
|
||||
|
||||
now = rfctime(buf, (size_t *)&len);
|
||||
if (!now)
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
return sendto(sd, now, len, MSG_DONTWAIT, sa, sa_len);
|
||||
}
|
||||
|
||||
static int cb(int type)
|
||||
{
|
||||
int sd = STDIN_FILENO;
|
||||
char buf[BUFSIZ];
|
||||
struct sockaddr_storage sa;
|
||||
socklen_t sa_len = sizeof(sa);
|
||||
|
||||
if (recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len))
|
||||
return -1; /* On error, close connection. */
|
||||
|
||||
return send_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, sa_len);
|
||||
}
|
||||
|
||||
static plugin_t plugin = {
|
||||
.name = NAME, /* Must match the inetd /etc/services entry */
|
||||
.inetd = {
|
||||
.cmd = cb
|
||||
}
|
||||
};
|
||||
|
||||
PLUGIN_INIT(plugin_init)
|
||||
{
|
||||
plugin_register(&plugin);
|
||||
}
|
||||
|
||||
PLUGIN_EXIT(plugin_exit)
|
||||
{
|
||||
plugin_unregister(&plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+1
-4
@@ -39,10 +39,7 @@ finit_SOURCES = api.c cgroup.c cgroup.h \
|
||||
tty.c tty.h \
|
||||
util.c util.h \
|
||||
utmp-api.c utmp-api.h
|
||||
pkginclude_HEADERS = cond.h finit.h helpers.h inetd.h log.h plugin.h svc.h
|
||||
if INETD
|
||||
finit_SOURCES += inetd.c inetd.h
|
||||
endif
|
||||
pkginclude_HEADERS = cond.h finit.h helpers.h log.h plugin.h svc.h
|
||||
|
||||
finit_CFLAGS = -W -Wall -Wextra -Wno-unused-parameter -std=gnu99
|
||||
finit_CFLAGS += $(lite_CFLAGS) $(uev_CFLAGS)
|
||||
|
||||
@@ -158,19 +158,6 @@ static svc_t *do_find(char *buf, size_t len)
|
||||
return svc_find_by_nameid(input, id);
|
||||
}
|
||||
|
||||
#ifdef INETD_ENABLED
|
||||
static int do_query_inetd(char *buf, size_t len)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
svc = do_find(buf, len);
|
||||
if (!svc || !svc_is_inetd(svc))
|
||||
return 1;
|
||||
|
||||
return inetd_filter_str(&svc->inetd, buf, len);
|
||||
}
|
||||
#endif /* INETD_ENABLED */
|
||||
|
||||
typedef struct {
|
||||
char *event;
|
||||
void (*cb)(void);
|
||||
@@ -291,14 +278,6 @@ static void api_cb(uev_t *w, void *arg, int events)
|
||||
result = do_restart(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
|
||||
#ifdef INETD_ENABLED
|
||||
case INIT_CMD_QUERY_INETD:
|
||||
_d("query inetd");
|
||||
strterm(rq.data, sizeof(rq.data));
|
||||
result = do_query_inetd(rq.data, sizeof(rq.data));
|
||||
break;
|
||||
#endif
|
||||
|
||||
case INIT_CMD_GET_RUNLEVEL:
|
||||
_d("get runlevel");
|
||||
rq.runlevel = runlevel;
|
||||
|
||||
+2
-12
@@ -500,16 +500,6 @@ static void parse_dynamic(char *line, struct rlimit rlimit[], char *file)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Classic inetd service */
|
||||
if (MATCH_CMD(line, "inetd ", x)) {
|
||||
#ifdef INETD_ENABLED
|
||||
service_register(SVC_TYPE_INETD, x, rlimit, file);
|
||||
#else
|
||||
_e("Finit built with inetd support disabled, cannot register service inetd %s!", x);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read resource limits */
|
||||
if (MATCH_CMD(line, "rlimit ", x)) {
|
||||
conf_parse_rlimit(x, rlimit);
|
||||
@@ -574,8 +564,8 @@ static int parse_conf(char *file)
|
||||
|
||||
/*
|
||||
* Get current global limits, which may be overridden from both
|
||||
* finit.conf, for Finit and its services like inetd+getty, and
|
||||
* *.conf in finit.d/, for each service(s) listed there.
|
||||
* finit.conf, for Finit and its services like getty+watchdogd,
|
||||
* and *.conf in finit.d/, for each service(s) listed there.
|
||||
*/
|
||||
for (int i = 0; i < RLIMIT_NLIMITS; i++)
|
||||
getrlimit(i, &global_rlimit[i]);
|
||||
|
||||
-803
@@ -1,803 +0,0 @@
|
||||
/* Classic inetd services launcher for Finit
|
||||
*
|
||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <uev/uev.h>
|
||||
#include <lite/lite.h>
|
||||
|
||||
#include "finit.h"
|
||||
#include "inetd.h"
|
||||
#include "helpers.h"
|
||||
#include "private.h"
|
||||
#include "service.h"
|
||||
|
||||
#define ENABLE_SOCKOPT(sd, level, opt) \
|
||||
do { \
|
||||
int val = 1; \
|
||||
if (setsockopt(sd, level, opt, &val, sizeof(val)) < 0) \
|
||||
logit(LOG_CRIT, "Failed enabling %s on %s service", \
|
||||
#opt, inetd->name); \
|
||||
} while (0);
|
||||
|
||||
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
||||
static int inetd_dgram_peek(int sd, char *ifname, size_t len)
|
||||
{
|
||||
struct cmsghdr *cmsg;
|
||||
struct msghdr msgh;
|
||||
char cmbuf[0x100];
|
||||
|
||||
memset(ifname, 0, len);
|
||||
memset(&msgh, 0, sizeof(msgh));
|
||||
msgh.msg_control = cmbuf;
|
||||
msgh.msg_controllen = sizeof(cmbuf);
|
||||
|
||||
if (recvmsg(sd, &msgh, MSG_PEEK) < 0)
|
||||
return -1;
|
||||
|
||||
for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg; cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
|
||||
struct in_pktinfo *ipi = (struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||
char tmp[IF_NAMESIZE + 1] = { 0 };
|
||||
|
||||
if (cmsg->cmsg_level != SOL_IP || cmsg->cmsg_type != IP_PKTINFO)
|
||||
continue;
|
||||
|
||||
if_indextoname(ipi->ipi_ifindex, tmp);
|
||||
strlcpy(ifname, tmp, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Peek into SOCK_DGRAM socket to figure out where an inbound packet comes from. */
|
||||
static void inetd_dgram_drop(int sd, const char *ifname)
|
||||
{
|
||||
char pkt_interface[IF_NAMESIZE + 1];
|
||||
char buf[BUFSIZ];
|
||||
|
||||
while (1) {
|
||||
inetd_dgram_peek(sd, pkt_interface, sizeof(pkt_interface));
|
||||
if (string_compare(pkt_interface, ifname)) {
|
||||
if (recv(sd, buf, sizeof(buf), 0) < 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Peek into SOCK_STREAM on accepted client socket to figure out inbound interface */
|
||||
static int inetd_stream_peek(int sd, char *ifname, size_t ilen)
|
||||
{
|
||||
struct ifaddrs *ifaddr, *ifa;
|
||||
struct sockaddr_in sin;
|
||||
socklen_t len = sizeof(sin);
|
||||
|
||||
memset(ifname, 0, ilen);
|
||||
if (-1 == getsockname(sd, (struct sockaddr *)&sin, &len))
|
||||
return -1;
|
||||
|
||||
if (-1 == getifaddrs(&ifaddr))
|
||||
return -1;
|
||||
|
||||
for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
|
||||
size_t len = sizeof(struct in_addr);
|
||||
struct sockaddr_in *iin;
|
||||
|
||||
if (!ifa->ifa_addr)
|
||||
continue;
|
||||
|
||||
if (ifa->ifa_addr->sa_family != AF_INET)
|
||||
continue;
|
||||
|
||||
iin = (struct sockaddr_in *)ifa->ifa_addr;
|
||||
if (!memcmp(&sin.sin_addr, &iin->sin_addr, len)) {
|
||||
strlcpy(ifname, ifa->ifa_name, ilen);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
freeifaddrs(ifaddr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_stdin(svc_t *svc, char *iifname, size_t len)
|
||||
{
|
||||
int stdin = svc->inetd.watcher.fd;
|
||||
char ifname[IF_NAMESIZE + 1] = "UNKNOWN";
|
||||
|
||||
memset(iifname, 0, len);
|
||||
if (svc->inetd.type == SOCK_STREAM) {
|
||||
/* Open new client socket from server socket */
|
||||
stdin = accept(stdin, NULL, NULL);
|
||||
if (stdin < 0) {
|
||||
logit(LOG_CRIT, "Failed accepting inetd service %d/tcp", svc->inetd.port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
_d("New client socket %d accepted for inetd service %d/tcp", stdin, svc->inetd.port);
|
||||
|
||||
inetd_stream_peek(stdin, ifname, sizeof(ifname));
|
||||
} else { /* SOCK_DGRAM */
|
||||
inetd_dgram_peek(stdin, ifname, sizeof(ifname));
|
||||
}
|
||||
|
||||
if (!inetd_is_allowed(&svc->inetd, ifname)) {
|
||||
logit(LOG_INFO, "Service %s on %s:%d is not allowed", svc->inetd.name, ifname, svc->inetd.port);
|
||||
if (svc->inetd.type == SOCK_STREAM)
|
||||
close(stdin);
|
||||
else
|
||||
inetd_dgram_drop(stdin, ifname);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Return ingress interface */
|
||||
strlcpy(iifname, ifname, len);
|
||||
|
||||
return stdin;
|
||||
}
|
||||
|
||||
/* Socket callback, looks up correct svc and starts it as an inetd service */
|
||||
static void socket_cb(uev_t *w, void *arg, int events)
|
||||
{
|
||||
svc_t *svc = (svc_t *)arg, *task;
|
||||
const char *conn = " connection";
|
||||
char iifname[IF_NAMESIZE + 1] = "UNKNOWN";
|
||||
char id[MAX_ID_LEN];
|
||||
int stdin;
|
||||
|
||||
_d("%s: Got socket event ...", svc->cmd);
|
||||
if (UEV_ERROR == events) {
|
||||
logit(LOG_INFO, "%s: Socket error, aborting: %s", svc->cmd, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
stdin = get_stdin(svc, iifname, sizeof(iifname));
|
||||
if (stdin < 0) {
|
||||
logit(LOG_CRIT, "%s: Unable to accept incoming connection", svc->cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure to disable O_NONBLOCK on the descriptor before
|
||||
* passing it to the inetd service, that's what is expected.
|
||||
*/
|
||||
if (fcntl(stdin, F_SETFL, fcntl(stdin, F_GETFL, 0) & ~O_NONBLOCK) < 0) {
|
||||
logit(LOG_CRIT, "Failed disabling non-blocking on %s socket", svc->cmd);
|
||||
if (svc->inetd.type == SOCK_STREAM)
|
||||
close(stdin);
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(id, sizeof(id), "%d", svc->inetd.next_id++);
|
||||
task = svc_new(svc->cmd, id, SVC_TYPE_INETD_CONN);
|
||||
if (!task) {
|
||||
logit(LOG_CRIT, "%s: Unable to allocate service for inetd client", svc->cmd);
|
||||
if (svc->inetd.type == SOCK_STREAM)
|
||||
close(stdin);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!svc->inetd.forking) {
|
||||
svc_busy(svc);
|
||||
service_step(svc);
|
||||
}
|
||||
|
||||
/* Copy inherited attributes from inetd service's svc */
|
||||
task->runlevels = svc->runlevels;
|
||||
|
||||
/*
|
||||
* Only copy the most relevant parts of inetd, in particular we
|
||||
* must *not* copy the watcher data to the clone!
|
||||
*/
|
||||
task->inetd.svc = svc;
|
||||
task->inetd.cmd = svc->inetd.cmd;
|
||||
task->inetd.type = svc->inetd.type;
|
||||
|
||||
memcpy(task->rlimit, svc->rlimit, sizeof(task->rlimit));
|
||||
memcpy(task->cond, svc->cond, sizeof(task->cond));
|
||||
memcpy(task->username, svc->username, sizeof(task->username));
|
||||
memcpy(task->group, svc->group, sizeof(task->group));
|
||||
memcpy(task->args, svc->args, sizeof(task->args));
|
||||
strlcpy(task->desc, svc->desc, sizeof(task->desc) - strlen(conn));
|
||||
strlcat(task->desc, conn, sizeof(task->desc));
|
||||
strlcpy(task->iifname, iifname, sizeof(task->iifname));
|
||||
strlcpy(task->name, svc->name, sizeof(task->name));
|
||||
|
||||
task->stdin_fd = stdin;
|
||||
service_step(task);
|
||||
}
|
||||
|
||||
/*
|
||||
* Refuse service if the request specifies a reply port corresponding to any internal service.
|
||||
* This is done as a defense against looping attacks; the remote IP address is logged.
|
||||
* http://www.freebsd.org/cgi/man.cgi?inetd(8)
|
||||
* https://svnweb.freebsd.org/base/head/usr.sbin/inetd/inetd.c?revision=298909&view=markup#l2094
|
||||
*/
|
||||
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
char pname[NI_MAXHOST];
|
||||
|
||||
for (svc = svc_inetd_iterator(&iter, 1); svc; svc = svc_inetd_iterator(&iter, 0)) {
|
||||
inetd_t *i = &svc->inetd;
|
||||
|
||||
if (!i->builtin || i->type != SOCK_DGRAM)
|
||||
continue;
|
||||
|
||||
if (((const struct sockaddr_in *)sa)->sin_port == i->port) {
|
||||
getnameinfo(sa, len, pname, sizeof(pname), NULL, 0, NI_NUMERICHOST);
|
||||
logit(LOG_WARNING, "%s/%s:%s/%s loop request REFUSED from %s", i->name, "UDP", name, "UDP", pname);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Launch Inet socket for service.
|
||||
* TODO: Add filtering ALLOW/DENY per interface.
|
||||
*/
|
||||
static int spawn_socket(inetd_t *inetd)
|
||||
{
|
||||
int sd;
|
||||
socklen_t len = sizeof(struct sockaddr);
|
||||
struct sockaddr_in s;
|
||||
|
||||
if (!inetd->type) {
|
||||
logit(LOG_CRIT, "Invalid inetd service %s, skipping ...", inetd->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
_d("Spawning server socket for inetd %s, type %s ...", inetd->name, inetd->type == SOCK_STREAM ? "stream" : "dgram");
|
||||
sd = socket(AF_INET, inetd->type | SOCK_NONBLOCK | SOCK_CLOEXEC, inetd->proto);
|
||||
if (-1 == sd) {
|
||||
logit(LOG_CRIT, "Failed opening inetd socket type %d proto %d", inetd->type, inetd->proto);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEADDR);
|
||||
#ifdef SO_REUSEPORT
|
||||
ENABLE_SOCKOPT(sd, SOL_SOCKET, SO_REUSEPORT);
|
||||
#endif
|
||||
|
||||
memset(&s, 0, sizeof(s));
|
||||
s.sin_family = AF_INET;
|
||||
s.sin_addr.s_addr = INADDR_ANY;
|
||||
s.sin_port = htons(inetd->port);
|
||||
if (bind(sd, (struct sockaddr *)&s, len) < 0) {
|
||||
logit(LOG_CRIT, "Failed binding to port %d, maybe another %s server is already running?",
|
||||
inetd->port, inetd->name);
|
||||
close(sd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
if (inetd->port) {
|
||||
if (inetd->type == SOCK_STREAM) {
|
||||
if (-1 == listen(sd, 10)) {
|
||||
logit(LOG_CRIT, "Failed listening to inetd service %s", inetd->name);
|
||||
close(sd);
|
||||
return -errno;
|
||||
}
|
||||
} else { /* SOCK_DGRAM */
|
||||
/* Set extra sockopt to get ifindex from inbound packets */
|
||||
ENABLE_SOCKOPT(sd, SOL_IP, IP_PKTINFO);
|
||||
}
|
||||
}
|
||||
|
||||
if (uev_io_init(ctx, &inetd->watcher, socket_cb, inetd->svc, sd, UEV_READ)) {
|
||||
logit(LOG_CRIT, "Failed setting up inetd watcher for %s", inetd->name);
|
||||
close(sd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_start(inetd_t *inetd)
|
||||
{
|
||||
int sd;
|
||||
char buf[BUFSIZ];
|
||||
ssize_t len;
|
||||
|
||||
sd = inetd->watcher.fd;
|
||||
if (sd == -1)
|
||||
return spawn_socket(inetd);
|
||||
|
||||
/* Read anything lingering, or clean up socket after failure */
|
||||
len = recv(sd, buf, sizeof(buf), MSG_DONTWAIT);
|
||||
if (len > 0)
|
||||
_d("Read %zd lingering bytes from socket before (re)starting %s ...", len, inetd->svc->cmd);
|
||||
|
||||
/* Restore O_NONBLOCK for socket */
|
||||
if (fcntl(sd, F_SETFL, fcntl(sd, F_GETFL, 0) | O_NONBLOCK)) {
|
||||
logit(LOG_CRIT, "Cannot safely (re)start %s inetd service", inetd->svc->cmd);
|
||||
return -errno;
|
||||
}
|
||||
|
||||
_d("Re-starting %s socket watcher ...", inetd->svc->cmd);
|
||||
uev_io_start(&inetd->watcher);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void inetd_stop_children(inetd_t *inetd, int check_allowed)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
svc = svc_job_iterator(&iter, 1, inetd->svc->job);
|
||||
while (svc) {
|
||||
if (!svc_is_inetd(svc)) {
|
||||
if (!check_allowed || !inetd_is_allowed(inetd, svc->iifname)) {
|
||||
svc_stop(svc);
|
||||
service_step(svc);
|
||||
}
|
||||
}
|
||||
svc = svc_job_iterator(&iter, 0, inetd->svc->job);
|
||||
}
|
||||
}
|
||||
|
||||
void inetd_stop(inetd_t *inetd)
|
||||
{
|
||||
if (!inetd || !inetd->svc) {
|
||||
_e("Invalid inetd, cannot stop it...");
|
||||
return;
|
||||
}
|
||||
|
||||
if (inetd->watcher.fd != -1) {
|
||||
_d("Stopping %s socket watcher ...", inetd->svc->cmd);
|
||||
uev_io_stop(&inetd->watcher);
|
||||
|
||||
/*
|
||||
* For dgram inetd services we block the parent SVC
|
||||
* and halt the watcher, so don't close the socket!
|
||||
*/
|
||||
if (!svc_is_busy(inetd->svc)) {
|
||||
_d("Shutting down inet socket %d ...", inetd->watcher.fd);
|
||||
close(inetd->watcher.fd);
|
||||
inetd->watcher.fd = -1;
|
||||
|
||||
inetd_stop_children(inetd, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct servent *fallback_service(char *service, char *proto)
|
||||
{
|
||||
int service_num;
|
||||
static struct servent lfs;
|
||||
|
||||
service_num = fgetint("/etc/services", " \n\t", service);
|
||||
if (service_num > 0) {
|
||||
lfs.s_name = service;
|
||||
lfs.s_port = htons(service_num);
|
||||
lfs.s_proto = NULL;
|
||||
if (!strcmp("tcp", proto) || !strcmp("udp", proto))
|
||||
lfs.s_proto = proto;
|
||||
|
||||
return &lfs;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct servent *getent_service(char *service, char *proto)
|
||||
{
|
||||
struct servent *ent;
|
||||
|
||||
#ifdef ENABLE_STATIC
|
||||
ent = fallback_service(service, proto);
|
||||
#else
|
||||
ent = getservbyname(service, proto);
|
||||
if (!ent)
|
||||
ent = fallback_service(service, proto);
|
||||
#endif
|
||||
return ent;
|
||||
}
|
||||
|
||||
static struct protoent *fallback_proto(char *proto)
|
||||
{
|
||||
int proto_num;
|
||||
static struct protoent lfp;
|
||||
|
||||
proto_num = fgetint("/etc/protocols", " \n\t", proto);
|
||||
if (proto_num > 0) {
|
||||
lfp.p_name = proto;
|
||||
lfp.p_proto = proto_num;
|
||||
|
||||
return &lfp;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct protoent *getent_proto(char *proto)
|
||||
{
|
||||
struct protoent *ent;
|
||||
|
||||
#ifdef ENABLE_STATIC
|
||||
ent = fallback_proto(proto);
|
||||
#else
|
||||
ent = getprotobyname(proto);
|
||||
if (!ent)
|
||||
ent = fallback_proto(proto);
|
||||
#endif
|
||||
return ent;
|
||||
}
|
||||
|
||||
static int getent(char *service, char *proto, struct servent **sv, struct protoent **pv)
|
||||
{
|
||||
if (!fexist("/etc/services") || !fexist("/etc/protocols")) {
|
||||
_w("Cannot register inetd %s/%s, system missing /etc/services or /etc/protocols", service, proto);
|
||||
return errno = ECANCELED;
|
||||
}
|
||||
|
||||
*sv = getent_service(service, proto);
|
||||
if (!*sv) {
|
||||
const char *errstr;
|
||||
static struct servent s;
|
||||
|
||||
s.s_name = service;
|
||||
s.s_port = strtonum(service, 1, UINT16_MAX, &errstr);
|
||||
s.s_proto = NULL;
|
||||
if (!strcmp("tcp", proto) || !strcmp("udp", proto))
|
||||
s.s_proto = proto;
|
||||
|
||||
if (errstr || !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 && (*sv)->s_proto) {
|
||||
*pv = getent_proto((*sv)->s_proto);
|
||||
if (!*pv) {
|
||||
_e("Cannot find proto %s, skipping ...", (*sv)->s_proto);
|
||||
return errno = EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find exact match.
|
||||
*/
|
||||
static inetd_filter_t *find_filter(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter;
|
||||
|
||||
if (!ifname)
|
||||
ifname = "*";
|
||||
|
||||
TAILQ_FOREACH(filter, &inetd->filters, link) {
|
||||
_d("Checking filters for %s: '%s' vs '%s' (exact match) ...",
|
||||
inetd->name, filter->ifname, ifname);
|
||||
|
||||
if (!strcmp(filter->ifname, ifname))
|
||||
return filter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* First try exact match, then fall back to any match.
|
||||
*/
|
||||
inetd_filter_t *inetd_filter_match(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter = find_filter(inetd, ifname);
|
||||
|
||||
if (filter)
|
||||
return filter;
|
||||
|
||||
TAILQ_FOREACH(filter, &inetd->filters, link) {
|
||||
_d("Checking filters for %s: '%s' vs '%s' (any match) ...",
|
||||
inetd->name, filter->ifname, ifname);
|
||||
|
||||
if (!strcmp(filter->ifname, "*"))
|
||||
return filter;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int inetd_flush(inetd_t *inetd)
|
||||
{
|
||||
inetd_filter_t *filter, *next;
|
||||
|
||||
TAILQ_FOREACH_SAFE(filter, &inetd->filters, link, next) {
|
||||
TAILQ_REMOVE(&inetd->filters, filter, link);
|
||||
free(filter);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Poor man's tcpwrappers filtering */
|
||||
int inetd_allow(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter;
|
||||
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
filter->deny = 0;
|
||||
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
|
||||
TAILQ_INSERT_TAIL(&inetd->filters, filter, link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_deny(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter;
|
||||
|
||||
if (!inetd)
|
||||
return errno = EINVAL;
|
||||
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
filter->deny = 1;
|
||||
strlcpy(filter->ifname, ifname, sizeof(filter->ifname));
|
||||
TAILQ_INSERT_TAIL(&inetd->filters, filter, link);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_is_allowed(inetd_t *inetd, char *ifname)
|
||||
{
|
||||
inetd_filter_t *filter;
|
||||
|
||||
if (!inetd) {
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
filter = inetd_filter_match(inetd, ifname);
|
||||
if (filter) {
|
||||
_d("Found matching filter for %s, deny: %d ... ", inetd->name, filter->deny);
|
||||
return !filter->deny;
|
||||
}
|
||||
|
||||
_d("No matching filter for %s ... ", inetd->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_match(inetd_t *inetd, char *service, char *proto)
|
||||
{
|
||||
struct servent *sv = NULL;
|
||||
struct protoent *pv = NULL;
|
||||
|
||||
if (!inetd || !service || !proto)
|
||||
return errno = EINVAL;
|
||||
|
||||
if (strncmp(inetd->name, service, sizeof(inetd->name)))
|
||||
return 0;
|
||||
|
||||
if (getent(service, proto, &sv, &pv))
|
||||
return 0;
|
||||
|
||||
if (inetd->proto == pv->p_proto &&
|
||||
inetd->port == ntohs(sv->s_port))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compose presentable string of inetd filters: !eth0,eth1,eth2,!eth3 */
|
||||
int inetd_filter_str(inetd_t *inetd, char *str, size_t len)
|
||||
{
|
||||
int prev = 0;
|
||||
char buf[42];
|
||||
inetd_filter_t *filter;
|
||||
|
||||
if (!inetd || !str || len <= 0) {
|
||||
_e("Dafuq?");
|
||||
return 1;
|
||||
}
|
||||
|
||||
snprintf(str, len, "%s allow %s ", inetd->name,
|
||||
inetd->type == SOCK_DGRAM ? "UDP" : "TCP");
|
||||
TAILQ_FOREACH(filter, &inetd->filters, link) {
|
||||
char ifname[IFNAMSIZ];
|
||||
|
||||
if (filter->deny)
|
||||
continue;
|
||||
|
||||
if (!strlen(filter->ifname))
|
||||
snprintf(ifname, sizeof(ifname), "*");
|
||||
else
|
||||
strlcpy(ifname, filter->ifname, sizeof(ifname));
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%s:%d", prev ? "," : "",
|
||||
ifname, inetd->port);
|
||||
prev = 1;
|
||||
strlcat(str, buf, len);
|
||||
}
|
||||
|
||||
prev = 0;
|
||||
TAILQ_FOREACH(filter, &inetd->filters, link) {
|
||||
char ifname[IFNAMSIZ];
|
||||
|
||||
if (!filter->deny)
|
||||
continue;
|
||||
if (!prev) {
|
||||
snprintf(buf, sizeof(buf), " deny ");
|
||||
strlcat(str, buf, len);
|
||||
}
|
||||
|
||||
if (!strlen(filter->ifname))
|
||||
snprintf(ifname, sizeof(ifname), "*");
|
||||
else
|
||||
strlcpy(ifname, filter->ifname, sizeof(ifname));
|
||||
|
||||
snprintf(buf, sizeof(buf), "%s%s", prev ? "," : "", ifname);
|
||||
prev = 1;
|
||||
strlcat(str, buf, len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
svc_t *inetd_find_svc(char *path, char *service, char *proto)
|
||||
{
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_inetd_iterator(&iter, 1); svc; svc = svc_inetd_iterator(&iter, 0)) {
|
||||
if (strncmp(path, svc->cmd, strlen(svc->cmd)))
|
||||
continue;
|
||||
|
||||
if (inetd_match(&svc->inetd, service, proto)) {
|
||||
_d("Found a matching inetd svc for %s %s %s", path, service, proto);
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is called to add a new, unique, inetd service. When an
|
||||
* ifname is given as argument this means *only* run service on this
|
||||
* interface. If a similar service runs on another port, this function
|
||||
* must add this ifname as "deny" to that other service.
|
||||
*
|
||||
* Example:
|
||||
* inetd ssh@eth0:222/tcp nowait [2345] /usr/sbin/sshd -i
|
||||
* inetd ssh/tcp nowait [2345] /usr/sbin/sshd -i
|
||||
*
|
||||
* In this example eth0:222 is very specific, so when ssh/tcp (default)
|
||||
* is added we must find the previous 'ssh' service and add its eth0 as
|
||||
* deny, so we don't accept port 22 session on eth0.
|
||||
*
|
||||
* In the reverse case, where the default (ssh/tcp) entry is listed
|
||||
* before the specific (eth0:222), the new inetd service must find the
|
||||
* (any!) previous rule and add its ifname to their deny list.
|
||||
*
|
||||
* If equivalent service exists already service_register() will instead call
|
||||
* inetd_allow().
|
||||
*/
|
||||
int inetd_new(inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc)
|
||||
{
|
||||
int result;
|
||||
struct servent *sv = NULL;
|
||||
struct protoent *pv = NULL;
|
||||
|
||||
if (!inetd || !service || !proto)
|
||||
return errno = EINVAL;
|
||||
|
||||
result = getent(service, proto, &sv, &pv);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
/* Setup defaults */
|
||||
inetd->std = 1;
|
||||
inetd->port = ntohs(sv->s_port);
|
||||
inetd->proto = pv->p_proto;
|
||||
inetd->forking = !!forking;
|
||||
inetd->next_id = 2;
|
||||
if (!name)
|
||||
name = service;
|
||||
strlcpy(inetd->name, name, sizeof(inetd->name));
|
||||
TAILQ_INIT(&inetd->filters);
|
||||
|
||||
/* Naïve mapping tcp->stream, udp->dgram, other->dgram */
|
||||
if (!strcasecmp(sv->s_proto, "tcp"))
|
||||
inetd->type = SOCK_STREAM;
|
||||
else
|
||||
inetd->type = SOCK_DGRAM;
|
||||
|
||||
if (inetd->type == SOCK_DGRAM && inetd->forking) {
|
||||
logit(LOG_WARNING, "%s: 'nowait' is not applicable on UDP services, ignoring", svc->cmd);
|
||||
inetd->forking = 0;
|
||||
}
|
||||
|
||||
/* Reset descriptor, used internally */
|
||||
inetd->watcher.fd = -1;
|
||||
|
||||
/* Setup socket callback argument */
|
||||
inetd->svc = svc;
|
||||
|
||||
_d("New service %s (default port %d proto %s:%d)", name, inetd->port, sv->s_proto, pv->p_proto);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int inetd_del(inetd_t *inetd)
|
||||
{
|
||||
svc_unblock(inetd->svc);
|
||||
inetd_stop(inetd);
|
||||
|
||||
return inetd_flush(inetd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
-83
@@ -1,83 +0,0 @@
|
||||
/* Classic inetd services launcher for Finit
|
||||
*
|
||||
* Copyright (c) 2015-2021 Joachim Wiberg <troglobit@gmail.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef FINIT_INETD_H_
|
||||
#define FINIT_INETD_H_
|
||||
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <uev/uev.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
|
||||
typedef struct svc svc_t;
|
||||
|
||||
typedef struct inetd_filter {
|
||||
TAILQ_ENTRY(inetd_filter) link;
|
||||
int deny; /* 0:allow, 1:deny */
|
||||
char ifname[IFNAMSIZ]; /* E.g., eth0 */
|
||||
} inetd_filter_t;
|
||||
|
||||
typedef struct {
|
||||
uev_t watcher;
|
||||
svc_t *svc; /* svc_t pointer for the socket callback */
|
||||
|
||||
int type; /* Socket type: SOCK_STREAM/SOCK_DGRAM */
|
||||
int std; /* Standard proto/port from /etc/services */
|
||||
int proto;
|
||||
int port;
|
||||
int forking;
|
||||
int builtin; /* Set by built-in inetd services only */
|
||||
int next_id; /* Next child job's id */
|
||||
char name[10];
|
||||
int (*cmd)(int type); /* internal inetd service, like 'time' */
|
||||
|
||||
TAILQ_HEAD(, inetd_filter) filters;
|
||||
} inetd_t;
|
||||
|
||||
int inetd_check_loop(struct sockaddr *sa, socklen_t len, char *name);
|
||||
|
||||
int inetd_start (inetd_t *inetd);
|
||||
void inetd_stop (inetd_t *inetd);
|
||||
void inetd_stop_children (inetd_t *inetd, int check_allowed);
|
||||
|
||||
int inetd_new (inetd_t *inetd, char *name, char *service, char *proto, int forking, svc_t *svc);
|
||||
int inetd_del (inetd_t *inetd);
|
||||
|
||||
svc_t *inetd_find_svc (char *path, char *service, char *proto);
|
||||
|
||||
int inetd_match (inetd_t *inetd, char *service, char *proto);
|
||||
int inetd_filter_str(inetd_t *inetd, char *str, size_t len);
|
||||
|
||||
int inetd_flush (inetd_t *inetd);
|
||||
int inetd_allow (inetd_t *inetd, char *ifname);
|
||||
int inetd_deny (inetd_t *inetd, char *ifname);
|
||||
int inetd_is_allowed(inetd_t *inetd, char *ifname);
|
||||
|
||||
#endif /* FINIT_INETD_H_ */
|
||||
|
||||
/**
|
||||
* Local Variables:
|
||||
* indent-tabs-mode: t
|
||||
* c-file-style: "linux"
|
||||
* End:
|
||||
*/
|
||||
+6
-44
@@ -421,17 +421,14 @@ static int show_status(char *arg)
|
||||
|
||||
for (svc = client_svc_iterator(1); svc; svc = client_svc_iterator(0)) {
|
||||
char jobid[20], args[512] = "", *lvls;
|
||||
int i;
|
||||
|
||||
if (!svc->id[0])
|
||||
snprintf(jobid, sizeof(jobid), "%d", svc->job);
|
||||
else
|
||||
snprintf(jobid, sizeof(jobid), "%d:%s", svc->job, svc->id);
|
||||
|
||||
printf("%-9s %8s ", jobid, svc_status(svc));
|
||||
if (svc_is_inetd(svc))
|
||||
printf("inetd ");
|
||||
else
|
||||
printf("%-6d ", svc->pid);
|
||||
printf("%-9s %8s %-6d ", jobid, svc_status(svc), svc->pid);
|
||||
|
||||
lvls = runlevel_string(runlevel, svc->runlevels);
|
||||
if (strchr(lvls, '\e'))
|
||||
@@ -445,47 +442,12 @@ static int show_status(char *arg)
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef INETD_ENABLED
|
||||
if (svc_is_inetd(svc)) {
|
||||
char *info;
|
||||
struct init_request rq = {
|
||||
.magic = INIT_MAGIC,
|
||||
.cmd = INIT_CMD_QUERY_INETD,
|
||||
};
|
||||
|
||||
snprintf(rq.data, sizeof(rq.data), "%s", jobid);
|
||||
if (client_send(&rq, sizeof(rq))) {
|
||||
snprintf(args, sizeof(args), "Unknown inetd");
|
||||
info = args;
|
||||
} else {
|
||||
size_t len = sizeof(rq.data);
|
||||
|
||||
info = rq.data;
|
||||
info[len - 1] = 0;
|
||||
|
||||
if (!string_match("internal", svc->cmd)) {
|
||||
char *ptr;
|
||||
|
||||
ptr = strchr(info, ' ');
|
||||
if (ptr)
|
||||
info = ptr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
printf("%s %s\n", svc->cmd, info);
|
||||
for (i = 1; i < MAX_NUM_SVC_ARGS; i++) {
|
||||
strlcat(args, svc->args[i], sizeof(args));
|
||||
strlcat(args, " ", sizeof(args));
|
||||
}
|
||||
else
|
||||
#endif /* INETD_ENABLED */
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < MAX_NUM_SVC_ARGS; i++) {
|
||||
strlcat(args, svc->args[i], sizeof(args));
|
||||
strlcat(args, " ", sizeof(args));
|
||||
}
|
||||
|
||||
printf("%s %s\n", svc->cmd, args);
|
||||
}
|
||||
printf("%s %s\n", svc->cmd, args);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+39
-239
@@ -37,7 +37,6 @@
|
||||
#include "cond.h"
|
||||
#include "finit.h"
|
||||
#include "helpers.h"
|
||||
#include "inetd.h"
|
||||
#include "pid.h"
|
||||
#include "private.h"
|
||||
#include "sig.h"
|
||||
@@ -248,17 +247,6 @@ static int lredirect(svc_t *svc)
|
||||
*/
|
||||
static int redirect(svc_t *svc)
|
||||
{
|
||||
/* Redirect inetd socket to stdin for connection */
|
||||
#ifdef INETD_ENABLED
|
||||
if (svc_is_inetd_conn(svc)) {
|
||||
dup2(svc->stdin_fd, STDIN_FILENO);
|
||||
close(svc->stdin_fd);
|
||||
dup2(STDIN_FILENO, STDOUT_FILENO);
|
||||
dup2(STDIN_FILENO, STDERR_FILENO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
stdin_redirect();
|
||||
|
||||
if (svc->log.enabled) {
|
||||
@@ -306,19 +294,14 @@ static int service_start(svc_t *svc)
|
||||
return 1;
|
||||
|
||||
/* Don't try and start service if it doesn't exist. */
|
||||
if (!whichp(svc->cmd) && !svc->inetd.cmd) {
|
||||
if (!whichp(svc->cmd)) {
|
||||
print(1, "Service %s does not exist", svc->cmd);
|
||||
svc_missing(svc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef INETD_ENABLED
|
||||
if (svc_is_inetd(svc))
|
||||
return inetd_start(&svc->inetd);
|
||||
#endif
|
||||
if (svc_is_sysv(svc)) {
|
||||
if (svc_is_sysv(svc))
|
||||
logit(LOG_CONSOLE | LOG_NOTICE, "Calling '%s start' ...", svc->cmd);
|
||||
}
|
||||
|
||||
if (!svc->desc[0])
|
||||
do_progress = 0;
|
||||
@@ -404,22 +387,11 @@ static int service_start(svc_t *svc)
|
||||
redirect(svc);
|
||||
sig_unblock();
|
||||
|
||||
if (svc->inetd.cmd)
|
||||
status = svc->inetd.cmd(svc->inetd.type);
|
||||
else if (svc_is_runtask(svc))
|
||||
if (svc_is_runtask(svc))
|
||||
status = exec_runtask(svc->cmd, args);
|
||||
else
|
||||
status = execvp(svc->cmd, args);
|
||||
|
||||
#ifdef INETD_ENABLED
|
||||
if (svc_is_inetd_conn(svc)) {
|
||||
if (svc->inetd.type == SOCK_STREAM) {
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
_exit(status);
|
||||
} else if (log_is_debug()) {
|
||||
char buf[CMD_SIZE] = "";
|
||||
@@ -455,13 +427,6 @@ static int service_start(svc_t *svc)
|
||||
pid_file_create(svc);
|
||||
break;
|
||||
|
||||
#ifdef INETD_ENABLED
|
||||
case SVC_TYPE_INETD_CONN:
|
||||
if (svc->inetd.type == SOCK_STREAM)
|
||||
close(svc->stdin_fd);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -519,22 +484,6 @@ static int service_stop(svc_t *svc)
|
||||
if (svc->state <= SVC_STOPPING_STATE)
|
||||
return 0;
|
||||
|
||||
#ifdef INETD_ENABLED
|
||||
if (svc_is_inetd(svc)) {
|
||||
int do_progress = runlevel != 1 && !svc_is_busy(svc);
|
||||
|
||||
if (do_progress)
|
||||
print_desc("Stopping ", svc->desc);
|
||||
|
||||
inetd_stop(&svc->inetd);
|
||||
|
||||
if (do_progress)
|
||||
print_result(0);
|
||||
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
return 0;
|
||||
} else
|
||||
#endif
|
||||
service_timeout_cancel(svc);
|
||||
|
||||
if (!svc_is_sysv(svc)) {
|
||||
@@ -792,7 +741,7 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
|
||||
* service_register - Register service, task or run commands
|
||||
* @type: %SVC_TYPE_SERVICE(0), %SVC_TYPE_TASK(1), %SVC_TYPE_RUN(2)
|
||||
* @cfg: Configuration, complete command, with -- for description text
|
||||
* @rlimit: Limits for this service/task/run/inetd, may be global limits
|
||||
* @rlimit: Limits for this service/task/run, may be global limits
|
||||
* @file: The file name service was loaded from
|
||||
*
|
||||
* This function is used to register commands to be run on different
|
||||
@@ -807,7 +756,6 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
|
||||
* service @username [!0-6,S] <!COND> /path/to/daemon arg -- Description
|
||||
* task @username [!0-6,S] /path/to/task arg -- Description
|
||||
* run @username [!0-6,S] /path/to/cmd arg -- Description
|
||||
* inetd tcp/ssh nowait [2345] @root:root /sbin/sshd -i -- Description
|
||||
*
|
||||
* If the username is left out the command is started as root. The []
|
||||
* brackets denote the allowed runlevels, if left out the default for a
|
||||
@@ -817,46 +765,43 @@ static void parse_cmdline_args(svc_t *svc, char *cmd)
|
||||
* command is listed in more than the [S] runlevel they will be called
|
||||
* when changing runlevel.
|
||||
*
|
||||
* Services (daemons, not inetd services) also support an optional <!EV>
|
||||
* argument. This is for services that, e.g., require a system gateway
|
||||
* or interface to be up before they are started. Or restarted, or even
|
||||
* SIGHUP'ed, when the gateway changes or interfaces come and go. The
|
||||
* special case when a service is declared with <!> means it does not
|
||||
* support SIGHUP but must be STOP/START'ed at system reconfiguration.
|
||||
* Services (daemons) also support an optional <!condition> argument.
|
||||
* This is for services that depend on another service, e.g. Quagga ripd
|
||||
* depends on zebra, or require a system gateway or interface to be up
|
||||
* before they are started. Or restarted, or even SIGHUP'ed, when the
|
||||
* gateway changes or interfaces come and go. The special case when a
|
||||
* service is declared with <!> means it does not support SIGHUP but
|
||||
* must be STOP/START'ed at system reconfiguration.
|
||||
*
|
||||
* Service conditions can be: pid/<PATH> for PID files, net/<IFNAME>/up
|
||||
* and net/<IFNAME>/exists. The condition handling is further described
|
||||
* in doc/conditions.md, but worth mentioning here is that the condition
|
||||
* name itself can be modified using the :ID and name:foo syntax.
|
||||
* Conditions can for example be: pid/NAME:ID for process dependencies,
|
||||
* net/<IFNAME>/up or net/<IFNAME>/exists. The condition handling is
|
||||
* further described in doc/conditions.md, but worth mentioning here is
|
||||
* that the condition a services *provides* can be modified using the
|
||||
* :ID and name:foo syntax.
|
||||
*
|
||||
* For multiple instances of the same command, e.g. multiple DHCP
|
||||
* clients, the user must enter an ID, using the :ID syntax.
|
||||
*
|
||||
* service :1 /sbin/udhcpc -i eth1
|
||||
* service :2 /sbin/udhcpc -i eth2
|
||||
* service :eth1 /sbin/udhcpc -i eth1
|
||||
* service :eth2 /sbin/udhcpc -i eth2
|
||||
*
|
||||
* Without the :ID syntax Finit will overwrite the first service line
|
||||
* with the contents of the second. The :ID must be [1,MAXINT].
|
||||
* Without the :ID syntax, Finit replaces the first service line with
|
||||
* the contents of the second. The :ID can be any string value and
|
||||
* defaults to "" (emtpy string).
|
||||
*
|
||||
* Returns:
|
||||
* POSIX OK(0) on success, or non-zero errno exit status on failure.
|
||||
*/
|
||||
int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
{
|
||||
#ifdef INETD_ENABLED
|
||||
char id_str[MAX_ID_LEN];
|
||||
int forking = 0;
|
||||
#endif
|
||||
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
|
||||
char *username = NULL, *log = NULL, *pid = NULL;
|
||||
char *name = NULL, *halt = NULL, *delay = NULL;
|
||||
char *id = NULL;
|
||||
int levels = 0;
|
||||
int manual = 0;
|
||||
char *line;
|
||||
char *id = NULL;
|
||||
char *username = NULL, *log = NULL, *pid = NULL;
|
||||
char *service = NULL, *proto = NULL, *ifaces = NULL;
|
||||
char *cmd, *desc, *runlevels = NULL, *cond = NULL;
|
||||
char *name = NULL, *halt = NULL, *delay = NULL;
|
||||
svc_t *svc;
|
||||
plugin_t *plugin = NULL;
|
||||
|
||||
if (!cfg) {
|
||||
_e("Invalid input argument");
|
||||
@@ -902,12 +847,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
cond = &cmd[1];
|
||||
else if (cmd[0] == ':') /* :ID */
|
||||
id = &cmd[1];
|
||||
#ifdef INETD_ENABLED
|
||||
else if (!strncasecmp(cmd, "nowait", 6))
|
||||
forking = 1;
|
||||
else if (!strncasecmp(cmd, "wait", 4))
|
||||
forking = 0;
|
||||
#endif
|
||||
else if (!strncasecmp(cmd, "log", 3))
|
||||
log = cmd;
|
||||
else if (!strncasecmp(cmd, "pid", 3))
|
||||
@@ -920,8 +859,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
halt = &cmd[5];
|
||||
else if (!strncasecmp(cmd, "kill:", 5))
|
||||
delay = &cmd[5];
|
||||
else if (cmd[0] != '/' && strchr(cmd, '/'))
|
||||
service = cmd; /* inetd service/proto */
|
||||
else
|
||||
break;
|
||||
|
||||
@@ -938,55 +875,6 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Example: inetd ssh/tcp@eth0,eth1 or 222/tcp@eth2 */
|
||||
if (service) {
|
||||
ifaces = strchr(service, '@');
|
||||
if (ifaces)
|
||||
*ifaces++ = 0;
|
||||
|
||||
proto = strchr(service, '/');
|
||||
if (!proto)
|
||||
goto incomplete;
|
||||
*proto++ = 0;
|
||||
}
|
||||
|
||||
#ifdef INETD_ENABLED
|
||||
/* Find plugin that provides a callback for this inetd service */
|
||||
if (type == SVC_TYPE_INETD) {
|
||||
if (!strncasecmp(cmd, "internal", 8)) {
|
||||
char *ptr, *ps = service;
|
||||
|
||||
/* internal.service */
|
||||
ptr = strchr(cmd, '.');
|
||||
if (ptr) {
|
||||
*ptr++ = 0;
|
||||
ps = ptr;
|
||||
}
|
||||
|
||||
plugin = plugin_find(ps);
|
||||
if (!plugin || !plugin->inetd.cmd) {
|
||||
_w("Inetd service %s has no internal plugin, skipping ...", service);
|
||||
free(line);
|
||||
return errno = ENOENT;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if known inetd, update command line, then add ifnames for filtering only. */
|
||||
svc = inetd_find_svc(cmd, service, proto);
|
||||
if (svc) {
|
||||
parse_cmdline_args(svc, cmd);
|
||||
goto inetd_setup;
|
||||
}
|
||||
|
||||
/* inetd services need a unique ID, so we must always set one. */
|
||||
if (!id) {
|
||||
snprintf(id_str, sizeof(id_str), "%d", svc_next_id_int(cmd));
|
||||
id = id_str;
|
||||
}
|
||||
}
|
||||
recreate:
|
||||
#endif
|
||||
|
||||
if (!id)
|
||||
id = "";
|
||||
|
||||
@@ -1004,16 +892,6 @@ recreate:
|
||||
svc_stop(svc);
|
||||
}
|
||||
}
|
||||
#ifdef INETD_ENABLED
|
||||
else {
|
||||
if (svc_is_inetd(svc) && type != SVC_TYPE_INETD) {
|
||||
_d("Service was previously inetd, deregistering ...");
|
||||
inetd_del(&svc->inetd);
|
||||
svc_del(svc);
|
||||
goto recreate;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Always clear svc PID file, for now. See TODO */
|
||||
svc->pidfile[0] = 0;
|
||||
@@ -1031,12 +909,7 @@ recreate:
|
||||
strlcpy(svc->username, username, sizeof(svc->username));
|
||||
}
|
||||
|
||||
if (plugin) {
|
||||
/* Internal plugin provides this service */
|
||||
svc->inetd.cmd = plugin->inetd.cmd;
|
||||
svc->inetd.builtin = 1;
|
||||
} else
|
||||
parse_cmdline_args(svc, cmd);
|
||||
parse_cmdline_args(svc, cmd);
|
||||
|
||||
svc->runlevels = levels;
|
||||
_d("Service %s runlevel 0x%2x", svc->cmd, svc->runlevels);
|
||||
@@ -1053,35 +926,6 @@ recreate:
|
||||
if (desc)
|
||||
strlcpy(svc->desc, desc, sizeof(svc->desc));
|
||||
|
||||
#ifdef INETD_ENABLED
|
||||
if (svc_is_inetd(svc)) {
|
||||
char *iface, *name = service;
|
||||
|
||||
if (svc->inetd.cmd && plugin)
|
||||
name = plugin->name;
|
||||
|
||||
if (inetd_new(&svc->inetd, name, service, proto, forking, svc)) {
|
||||
_e("Failed registering new inetd service %s/%s", service, proto);
|
||||
free(line);
|
||||
return svc_del(svc);
|
||||
}
|
||||
|
||||
inetd_setup:
|
||||
inetd_flush(&svc->inetd);
|
||||
|
||||
if (!ifaces) {
|
||||
_d("No specific iface listed for %s, allowing ANY", service);
|
||||
inetd_allow(&svc->inetd, NULL);
|
||||
} else {
|
||||
for (iface = strtok(ifaces, ","); iface; iface = strtok(NULL, ",")) {
|
||||
if (iface[0] == '!')
|
||||
inetd_deny(&svc->inetd, &iface[1]);
|
||||
else
|
||||
inetd_allow(&svc->inetd, iface);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Set configured limits */
|
||||
memcpy(svc->rlimit, rlimit, sizeof(svc->rlimit));
|
||||
|
||||
@@ -1101,44 +945,18 @@ recreate:
|
||||
|
||||
/*
|
||||
* This function is called when cleaning up lingering (stopped) services
|
||||
* after a .conf reload, as well as when an inetd connection terminates.
|
||||
* after a .conf reload.
|
||||
*
|
||||
* We need to ensure we properly stop the service before removing it,
|
||||
* including stopping any pending restart or SIGKILL timers before we
|
||||
* proceed to free() the svc itself.
|
||||
*
|
||||
* Remember to not try to stop inetd connections, they only get here
|
||||
* when already stopped, if we do we end up in a recursive loop.
|
||||
*/
|
||||
void service_unregister(svc_t *svc)
|
||||
{
|
||||
if (!svc)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Only try stopping @svc if it's *not* an inetd connection.
|
||||
* Prevents infinite recursion when called from service_step()
|
||||
*/
|
||||
switch (svc->type) {
|
||||
#ifdef INETD_ENABLED
|
||||
case SVC_TYPE_INETD:
|
||||
inetd_del(&svc->inetd);
|
||||
break;
|
||||
|
||||
case SVC_TYPE_INETD_CONN:
|
||||
/* inetd connection, if UDP unblock parent */
|
||||
if (svc_is_busy(svc->inetd.svc)) {
|
||||
svc_unblock(svc->inetd.svc);
|
||||
service_step(svc->inetd.svc);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
service_stop(svc);
|
||||
break;
|
||||
}
|
||||
|
||||
service_stop(svc);
|
||||
svc_del(svc);
|
||||
}
|
||||
|
||||
@@ -1238,7 +1056,7 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
|
||||
*state = new;
|
||||
|
||||
/* if PID isn't collected within SVC_TERM_TIMEOUT msec, kill it! */
|
||||
if ((*state == SVC_STOPPING_STATE) && !svc_is_inetd(svc)) {
|
||||
if ((*state == SVC_STOPPING_STATE)) {
|
||||
_d("%s is stopping, wait %d sec before sending SIGKILL ...",
|
||||
svc->cmd, svc->killdelay / 1000);
|
||||
service_timeout_cancel(svc);
|
||||
@@ -1247,7 +1065,7 @@ static void svc_set_state(svc_t *svc, svc_state_t new)
|
||||
}
|
||||
|
||||
/*
|
||||
* Transition inetd/task/run/service
|
||||
* Transition task/run/service
|
||||
*
|
||||
* Returns: non-zero if the @svc is no longer valid (removed)
|
||||
*/
|
||||
@@ -1275,12 +1093,6 @@ restart:
|
||||
break;
|
||||
|
||||
case SVC_DONE_STATE:
|
||||
#ifdef INETD_ENABLED
|
||||
if (svc_is_inetd_conn(svc)) {
|
||||
service_unregister(svc);
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
if (svc_is_changed(svc))
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
break;
|
||||
@@ -1293,11 +1105,8 @@ restart:
|
||||
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_SERVICE:
|
||||
case SVC_TYPE_INETD:
|
||||
svc_set_state(svc, SVC_HALTED_STATE);
|
||||
break;
|
||||
|
||||
case SVC_TYPE_INETD_CONN:
|
||||
case SVC_TYPE_TASK:
|
||||
case SVC_TYPE_RUN:
|
||||
case SVC_TYPE_SYSV:
|
||||
@@ -1322,8 +1131,7 @@ restart:
|
||||
err = service_start(svc);
|
||||
if (err) {
|
||||
(*restart_cnt)++;
|
||||
if (!svc_is_inetd_conn(svc))
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Everything went fine, clean and set state */
|
||||
@@ -1352,12 +1160,6 @@ restart:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Collected inetd connection, drive it to stopping */
|
||||
if (svc_is_inetd_conn(svc)) {
|
||||
svc_set_state(svc, SVC_STOPPING_STATE);
|
||||
break;
|
||||
}
|
||||
|
||||
if (svc_is_runtask(svc)) {
|
||||
if (svc_is_sysv(svc)) {
|
||||
if (!svc->started)
|
||||
@@ -1384,18 +1186,16 @@ restart:
|
||||
case COND_ON:
|
||||
if (svc_is_changed(svc)) {
|
||||
if (svc->sighup) {
|
||||
/* wait until all processes has been stopped before continuing... */
|
||||
/*
|
||||
* wait until all processes have been
|
||||
* stopped before continuing...
|
||||
*/
|
||||
if (sm_is_in_teardown(&sm))
|
||||
break;
|
||||
service_restart(svc);
|
||||
} else {
|
||||
#ifdef INETD_ENABLED
|
||||
if (svc_is_inetd(svc))
|
||||
inetd_stop_children(&svc->inetd, 1);
|
||||
else
|
||||
#endif
|
||||
service_stop(svc);
|
||||
}
|
||||
} else
|
||||
service_stop(svc);
|
||||
|
||||
svc_mark_clean(svc);
|
||||
}
|
||||
break;
|
||||
@@ -1465,7 +1265,7 @@ void service_step_all(int types)
|
||||
|
||||
void service_worker(void *unused)
|
||||
{
|
||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK | SVC_TYPE_INETD);
|
||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_RUNTASK);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -222,7 +222,7 @@ restart:
|
||||
_d("Stopping services not allowed after reconf ...");
|
||||
sm->in_teardown = 1;
|
||||
cond_reload();
|
||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||
service_step_all(SVC_TYPE_SERVICE);
|
||||
tty_reload(NULL);
|
||||
|
||||
sm->state = SM_RELOAD_WAIT_STATE;
|
||||
@@ -244,12 +244,12 @@ restart:
|
||||
svc_clean_dynamic(service_unregister);
|
||||
|
||||
_d("Starting services after reconf ...");
|
||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||
service_step_all(SVC_TYPE_SERVICE);
|
||||
|
||||
_d("Calling reconf hooks ...");
|
||||
plugin_run_hooks(HOOK_SVC_RECONF);
|
||||
|
||||
service_step_all(SVC_TYPE_SERVICE | SVC_TYPE_INETD);
|
||||
service_step_all(SVC_TYPE_SERVICE);
|
||||
_d("Reconfiguration done");
|
||||
|
||||
sm->state = SM_RUNNING_STATE;
|
||||
|
||||
@@ -72,9 +72,9 @@ static void svc_gc(void *arg)
|
||||
|
||||
/**
|
||||
* svc_new - Create a new service
|
||||
* @cmd: External program to call, or 'internal' for internal inetd services
|
||||
* @cmd: External program to call
|
||||
* @id: Instance id
|
||||
* @type: Service type, one of service, task, run or inetd
|
||||
* @type: Service type, one of service, task, run
|
||||
*
|
||||
* Returns:
|
||||
* A pointer to a new &svc_t object, or %NULL if out of empty slots.
|
||||
@@ -169,28 +169,6 @@ svc_t *svc_iterator(svc_t **iter, int first)
|
||||
return svc;
|
||||
}
|
||||
|
||||
/**
|
||||
* svc_inetd_iterator - Naive iterator over all registered inetd services.
|
||||
* @iter: Iterator, must be a valid pointer
|
||||
* @first: If set, get first &svc_t, otherwise get next
|
||||
*
|
||||
* Returns:
|
||||
* The first inetd &svc_t when %NULL is given as argument, otherwise the
|
||||
* next inetd &svc_t until the end when %NULL is returned.
|
||||
*/
|
||||
svc_t *svc_inetd_iterator(svc_t **iter, int first)
|
||||
{
|
||||
svc_t *svc;
|
||||
|
||||
for (svc = svc_iterator(iter, first); svc; svc = svc_iterator(iter, 0)) {
|
||||
if (svc_is_inetd(svc))
|
||||
return svc;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* svc_named_iterator - Iterates over all instances of a service.
|
||||
* @iter: Iterator, must be a valid pointer
|
||||
@@ -455,8 +433,6 @@ void svc_mark_dynamic(void)
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
if (svc->protect)
|
||||
continue;
|
||||
if (svc_is_inetd_conn(svc))
|
||||
continue;
|
||||
|
||||
*((int *)&svc->dirty) = -1;
|
||||
}
|
||||
@@ -547,29 +523,6 @@ int svc_enabled(svc_t *svc)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Same base service, return unique ID as an integer
|
||||
* Note: intended for use with INETD services.
|
||||
*/
|
||||
int svc_next_id_int(char *cmd)
|
||||
{
|
||||
int n = 1;
|
||||
svc_t *svc, *iter = NULL;
|
||||
|
||||
for (svc = svc_iterator(&iter, 1); svc; svc = svc_iterator(&iter, 0)) {
|
||||
char id[MAX_ID_LEN];
|
||||
|
||||
snprintf(id, sizeof(id), "%d", n);
|
||||
|
||||
if (!strcmp(svc->cmd, cmd) && strcmp(svc->id, id))
|
||||
return n;
|
||||
|
||||
n++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int svc_is_unique(svc_t *svc)
|
||||
{
|
||||
svc_t *s, *iter = NULL;
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
#include <sys/types.h> /* pid_t */
|
||||
#include <lite/lite.h>
|
||||
#include <lite/queue.h> /* BSD sys/queue.h API */
|
||||
#include <uev/uev.h>
|
||||
|
||||
#include "inetd.h"
|
||||
#include "helpers.h"
|
||||
|
||||
typedef int svc_cmd_t;
|
||||
@@ -41,8 +41,6 @@ typedef enum {
|
||||
SVC_TYPE_SERVICE = 1, /* Monitored, will be respawned */
|
||||
SVC_TYPE_TASK = 2, /* One-shot, runs in parallell */
|
||||
SVC_TYPE_RUN = 4, /* Like task, but wait for completion */
|
||||
SVC_TYPE_INETD = 8, /* Classic inetd service */
|
||||
SVC_TYPE_INETD_CONN = 16, /* Single inetd connection */
|
||||
SVC_TYPE_SYSV = 32, /* SysV style init.d script w/ start/stop */
|
||||
} svc_type_t;
|
||||
|
||||
@@ -103,7 +101,7 @@ typedef struct svc {
|
||||
int started; /* Set for run/task/sysv to track if started */
|
||||
int status; /* From waitpid() when process is collected */
|
||||
const svc_state_t state; /* Paused, Reloading, Restart, Running, ... */
|
||||
svc_type_t type; /* Service, run, task, inetd, ... */
|
||||
svc_type_t type; /* Service, run, task, ... */
|
||||
int protect; /* Services like dbus-daemon & udev by Finit */
|
||||
const int dirty; /* -1: removal, 0: unmodified, 1: modified */
|
||||
int starting; /* ... waiting for pidfile to be re-asserted */
|
||||
@@ -117,11 +115,6 @@ typedef struct svc {
|
||||
char once; /* run/task, (at least) once per runlevel */
|
||||
const char restart_cnt; /* Incremented for each restart by service monitor. */
|
||||
|
||||
/* For inetd services */
|
||||
inetd_t inetd;
|
||||
int stdin_fd;
|
||||
char iifname[IF_NAMESIZE + 1]; /* Ingress interface for connection */
|
||||
|
||||
/* Set for services we need to redirect stdout/stderr to syslog */
|
||||
struct {
|
||||
char enabled;
|
||||
@@ -162,7 +155,6 @@ svc_t *svc_find_by_nameid (char *name, char *id);
|
||||
svc_t *svc_find_by_pidfile (char *fn);
|
||||
|
||||
svc_t *svc_iterator (svc_t **iter, int first);
|
||||
svc_t *svc_inetd_iterator (svc_t **iter, int first);
|
||||
svc_t *svc_named_iterator (svc_t **iter, int first, char *cmd);
|
||||
svc_t *svc_job_iterator (svc_t **iter, int first, int job);
|
||||
|
||||
@@ -179,13 +171,10 @@ int svc_clean_bootstrap (svc_t *svc);
|
||||
void svc_prune_bootstrap (void);
|
||||
|
||||
int svc_enabled (svc_t *svc);
|
||||
int svc_next_id_int (char *cmd);
|
||||
int svc_is_unique (svc_t *svc);
|
||||
|
||||
int svc_parse_jobstr (char *str, size_t len, int (*found)(svc_t *), int (not_found)(char *, char *));
|
||||
|
||||
static inline int svc_is_inetd (svc_t *svc) { return svc && SVC_TYPE_INETD == svc->type; }
|
||||
static inline int svc_is_inetd_conn(svc_t *svc) { return svc && SVC_TYPE_INETD_CONN == svc->type; }
|
||||
static inline int svc_is_daemon (svc_t *svc) { return svc && SVC_TYPE_SERVICE == svc->type; }
|
||||
static inline int svc_is_sysv (svc_t *svc) { return svc && SVC_TYPE_SYSV == svc->type; }
|
||||
static inline int svc_is_runtask (svc_t *svc) { return svc && (SVC_TYPE_RUNTASK & svc->type); }
|
||||
@@ -246,7 +235,6 @@ static inline char *svc_status(svc_t *svc)
|
||||
|
||||
case SVC_STOPPING_STATE:
|
||||
switch (svc->type) {
|
||||
case SVC_TYPE_INETD_CONN:
|
||||
case SVC_TYPE_RUN:
|
||||
case SVC_TYPE_TASK:
|
||||
return "active";
|
||||
|
||||
Reference in New Issue
Block a user