diff --git a/README.md b/README.md index ad333a81..44e25f39 100644 --- a/README.md +++ b/README.md @@ -73,8 +73,11 @@ interface, reducing the need for a full blown firewall. Built-in optional inetd services: -- time (rdate) RFC862 -- echo RFC868 +- echo RFC862 +- chargen RFC864 +- daytime RFC867 +- discard RFC863 +- time (rdate) RFC868 **Runlevels** @@ -437,7 +440,8 @@ Inetd A built-in *Internet Super Server* support was added in Finit v1.12 and v1.13, along with an internal `time` inetd service, RFC 868 (rdate). The latter is supplied as a plugin to illustrate how simple it is to -extend finit with more internal inetd services. +extend finit with more internal inetd services. Today more built-in +services are available. > Please note, not all UNIX daemons are prepared to run as inetd services. > In the example below `sshd` also need the command line argument `-i`. @@ -473,29 +477,41 @@ default port. To run ssh on port 222, and all others on port 22: ``` Compared to Finit v1.12 you must *explicitly deny* access from `eth0`! - + +To protect against looping attacks, the inetd server will refuse UDP +service if the reply port corresponds to any internal service. Similar +to how the FreeBSD inetd operates. + **Internal Services** -The original `inetd` had a few standard services built-in: +Like the original `inetd`, Finit has a few standard services built-in. +They are realized as plugins to provide a simple means of testing the +inetd functionality stand-alone. But this also provides both a useful +network testing/availability, as well as a rudimentary time server for +`rdate` clients. -- time - echo - chargen +- daytime - discard +- time -Finit currently supports the `time` and `echo` services. Both of which -are realized as plugins to provide a simple means of testing the inetd -functionality stand-alone. But this also provides both a useful network -testing/availability and a rudimentary time server for rdate clients. - -Internal inetd services are set up as follows: +For security reasons they are all disabled by default and have to be +enabled with both the `configure` script and a special `inetd` stanza in +the `finit.conf` or `finit.d/*.conf` like this: ```shell - inetd time/udp wait [2345] internal - inetd time/tcp nowait [2345] internal inetd echo/udp wait [2345] internal inetd echo/tcp nowait [2345] internal + inetd chargen/udp wait [2345] internal + inetd chargen/tcp nowait [2345] internal + inetd daytime/udp wait [2345] internal + inetd daytime/tcp nowait [2345] internal + inetd discard/udp wait [2345] internal + inetd discard/tcp nowait [2345] internal + inetd time/udp wait [2345] internal + inetd time/tcp nowait [2345] internal ``` Then call `rdate` from a remote machine (or use localhost): @@ -512,6 +528,20 @@ Or `echoping` to reach the echo service: echoping -uv ``` +Or `echoping -d` to reach the discard service: + +```shell + echoping -dv + echoping -duv +``` + +Or `echoping -c` to reach the chargen service: + +```shell + echoping -cv + echoping -cuv +``` + If you use `time/udp` you must use the standard rdate implementation and then call it with `rdate -up` to connect using UDP. Without the `-p` argument rdate will try to set the system clock. Please note that rdate @@ -554,6 +584,12 @@ For your convenience a set of *optional* plugins are available: * *echo.so*: RFC 862 plugin. Start as inetd service, like time below. +* *chargen.so*: RFC 864 plugin. Start as inetd service, like time below. + +* *daytime.so*: RFC 867 plugin. Start as inetd service, like time below. + +* *discard.so*: RFC 863 plugin. Start as inetd service, like time below. + * *hwclock.so*: Restore and save system clock from/to RTC on startup/shutdown. diff --git a/configure.ac b/configure.ac index f265edb8..772af2f3 100644 --- a/configure.ac +++ b/configure.ac @@ -53,14 +53,17 @@ AC_ARG_ENABLE(quiet, # Check for extra plugins to enable 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([inetd-echo], [no], [Inetd plugin: echo server, RFC862]) -AC_PLUGIN([inetd-time], [no], [Inetd plugin: time (rdate) server, RFC868]) -AC_PLUGIN([lost], [no], [Example HOOK_SVC_LOST plugin, very noisy as-is!]) -AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf]) -AC_PLUGIN([x11-common], [no], [Console setup (for X)]) -AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.]) +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([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([lost], [no], [Example HOOK_SVC_LOST plugin, very noisy as-is!]) +AC_PLUGIN([resolvconf], [no], [Setup necessary files for resolvconf]) +AC_PLUGIN([x11-common], [no], [Console setup (for X)]) +AC_PLUGIN([netlink], [yes], [Basic netlink plugin for IFUP/IFDN and GW events. Can be replaced with externally built plugin that links with libnl or similar.]) # Check for extra arguments or packages AC_ARG_WITH(heading, diff --git a/finit.c b/finit.c index 535f1227..4e148bf4 100644 --- a/finit.c +++ b/finit.c @@ -38,7 +38,6 @@ #include "service.h" #include "sig.h" #include "tty.h" -#include "inetd.h" #include "sm.h" int debug = 0; diff --git a/inetd.c b/inetd.c index 516217e8..d76d6f2e 100755 --- a/inetd.c +++ b/inetd.c @@ -107,8 +107,8 @@ static int inetd_stream_peek(int sd, char *ifname) static int get_stdin(svc_t *svc) { - char ifname[IF_NAMESIZE] = "UNKNOWN"; int stdin = svc->inetd.watcher.fd; + char ifname[IF_NAMESIZE] = "UNKNOWN"; if (svc->inetd.type == SOCK_STREAM) { /* Open new client socket from server socket */ @@ -189,6 +189,33 @@ static void socket_cb(uev_t *UNUSED(w), void *arg, int UNUSED(events)) 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; + char pname[NI_MAXHOST]; + + for (svc = svc_inetd_iterator(1); svc; svc = svc_inetd_iterator(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); + FLOG_WARN("%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. */ diff --git a/inetd.h b/inetd.h index 32db966e..d0f326d0 100644 --- a/inetd.h +++ b/inetd.h @@ -46,6 +46,7 @@ typedef struct { 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' */ @@ -53,6 +54,8 @@ typedef struct { 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); diff --git a/plugins/Makefile.am b/plugins/Makefile.am index e25cf87d..61cd73dd 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -15,13 +15,27 @@ if BUILD_DBUS_PLUGIN libplug_la_SOURCES += dbus.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_LOST_PLUGIN libplug_la_SOURCES += lost.c @@ -46,13 +60,27 @@ if BUILD_DBUS_PLUGIN pkglib_LTLIBRARIES += dbus.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_LOST_PLUGIN pkglib_LTLIBRARIES += lost.la diff --git a/plugins/chargen.c b/plugins/chargen.c new file mode 100644 index 00000000..b3e1febc --- /dev/null +++ b/plugins/chargen.c @@ -0,0 +1,114 @@ +/* Optional inetd plugin for the Character Generator Protocol, RFC 864 + * + * Copyright (c) 2016 Joachim Nilsson + * + * 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 +#include /* STDIN_FILENO */ +#include + +#include "../plugin.h" + +#define NAME "chargen" +#define PATTERN "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ " + +static char *generator(char *buf, size_t len) +{ + size_t num; + static size_t pos = 0; + const char pattern[] = PATTERN; + + len = 72; + if (pos + len > sizeof(pattern)) { + num = sizeof(pattern) - pos; + len -= num; + } else { + num = 72; + len = 0; + } + + strncpy(&buf[0], &pattern[pos], num--); + if (len++) + strncpy(&buf[num], pattern, len); + strcat(buf, "\r\n"); + + 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; + ssize_t len; + 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: + */ diff --git a/plugins/daytime.c b/plugins/daytime.c new file mode 100644 index 00000000..4ea9ce11 --- /dev/null +++ b/plugins/daytime.c @@ -0,0 +1,102 @@ +/* Optional inetd plugin for Daytime Protocol, RFC 867 + * + * Copyright (c) 2016 Joachim Nilsson + * + * 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 +#include +#include /* STDIN_FILENO */ +#include + +#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: + */ diff --git a/plugins/discard.c b/plugins/discard.c new file mode 100644 index 00000000..94bc56c7 --- /dev/null +++ b/plugins/discard.c @@ -0,0 +1,67 @@ +/* Optional inetd plugin for the Discard Protocol, RFC 863 + * + * Copyright (c) 2016 Joachim Nilsson + * + * 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 +#include /* STDIN_FILENO */ +#include + +#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: + */ diff --git a/plugins/echo.c b/plugins/echo.c index 6cad05a5..311a2255 100644 --- a/plugins/echo.c +++ b/plugins/echo.c @@ -1,4 +1,4 @@ -/* Optional inetd plugin for the echo protocol RFC 862 +/* Optional inetd plugin for the Echo Protocol, RFC 862 * * Copyright (c) 2016 Joachim Nilsson * @@ -27,7 +27,21 @@ #include "../plugin.h" -static int echo_cb(int type) +#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]; @@ -35,7 +49,7 @@ static int echo_cb(int type) struct sockaddr_storage sa; socklen_t sa_len = sizeof(sa); - len = recvfrom(sd, buf, sizeof(buf), MSG_DONTWAIT, (struct sockaddr *)&sa, &sa_len); + len = recv_peer(sd, buf, sizeof(buf), (struct sockaddr *)&sa, &sa_len); if (-1 == len) return -1; /* On error, close connection. */ @@ -43,9 +57,9 @@ static int echo_cb(int type) } static plugin_t plugin = { - .name = "echo", /* Must match the inetd /etc/services entry */ + .name = NAME, /* Must match the inetd /etc/services entry */ .inetd = { - .cmd = echo_cb + .cmd = cb }, }; diff --git a/plugins/time.c b/plugins/time.c index 6a014342..de81938a 100644 --- a/plugins/time.c +++ b/plugins/time.c @@ -1,4 +1,4 @@ -/* Optional inetd plugin for time (rdate) protocol RFC 868 +/* Optional inetd plugin for Time Protocol (rdate), RFC 868 * * Copyright (c) 2015 Joachim Nilsson * @@ -28,43 +28,73 @@ #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 int rfc868(int type) +static char *rfctime(char *buf, size_t *len) { - int sd = STDIN_FILENO; time_t now; - struct sockaddr_storage sa; - socklen_t sa_len = sizeof(sa); - - if (SOCK_DGRAM == type) { - int dummy; - - /* Read empty datagram in UDP mode before sending reply. */ - if (-1 == recvfrom(sd, &dummy, sizeof(dummy), MSG_DONTWAIT, (struct sockaddr *)&sa, &sa_len)) - return -1; /* On error, close connection. */ - } now = time(NULL); if ((time_t)-1 == now) - return -1; /* On error, close connection. */ + return NULL; - /* Account for UNIX epoch offset */ + /* + * Account for UNIX epoch offset, and + * convert to network byte order + */ now += EPOCH_OFFSET; + now = htonl(now); - /* Convert to network byte order, not explicitly stated in RFC */ - now = htonl(now); + *len = sizeof(now); + memcpy(buf, &now, *len); - /* Send reply, ignore error, simply close connection. */ - return sendto(sd, &now, sizeof(now), MSG_DONTWAIT, (struct sockaddr *)&sa, sa_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, &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 = "time", /* Must match the inetd /etc/services entry */ + .name = NAME, /* Must match the inetd /etc/services entry */ .inetd = { - .cmd = rfc868 + .cmd = cb } }; diff --git a/service.c b/service.c index 5f911f24..e6ba6f3d 100755 --- a/service.c +++ b/service.c @@ -589,6 +589,7 @@ recreate: if (plugin) { /* Internal plugin provides this service */ svc->inetd.cmd = plugin->inetd.cmd; + svc->inetd.builtin = 1; } else { strlcpy(svc->args[i++], cmd, sizeof(svc->args[0])); while ((cmd = strtok(NULL, " ")))