aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am1
-rw-r--r--src/inetd-bi.c305
-rw-r--r--src/inetd.c29
-rw-r--r--src/pies.c6
-rw-r--r--src/pies.h16
-rw-r--r--src/progman.c22
6 files changed, 371 insertions, 8 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 8735607..bbe5db7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,6 +22,7 @@ pies_SOURCES = \
depmap.c\
diag.c\
inetd.c\
+ inetd-bi.c\
limits.c\
meta.c\
meta1gram.y\
diff --git a/src/inetd-bi.c b/src/inetd-bi.c
new file mode 100644
index 0000000..f86f373
--- /dev/null
+++ b/src/inetd-bi.c
@@ -0,0 +1,305 @@
+/* This file is part of GNU Pies.
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ GNU Pies is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GNU Pies is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "pies.h"
+#include <netdb.h>
+
+#define INTBUFSIZE 8192
+
+/* Echo protocol, RFC 862 */
+void
+echo_stream (int fd)
+{
+ int rc;
+ char buffer[INTBUFSIZE];
+
+ while ((rc = read (fd, buffer, sizeof buffer)) > 0
+ && write (fd, buffer, rc) > 0)
+ ;
+}
+
+void
+echo_dg (int fd)
+{
+ int rc;
+ char buffer[INTBUFSIZE];
+ struct sockaddr sa;
+ socklen_t size = sizeof sa;
+
+ rc = recvfrom (fd, buffer, sizeof buffer, 0, &sa, &size);
+ if (rc < 0)
+ return;
+ sendto (fd, buffer, rc, 0, &sa, sizeof sa);
+}
+
+/* Discard protocol, RFC 863 */
+void
+discard_stream (int fd)
+{
+ int rc;
+ char buffer[INTBUFSIZE];
+
+ while (1)
+ {
+ while ((rc = read (fd, buffer, sizeof buffer)) > 0)
+ ;
+ if (rc == 0 || errno != EINTR)
+ break;
+ }
+}
+
+void
+discard_dg (int fd)
+{
+ char buffer[INTBUFSIZE];
+ read (fd, buffer, sizeof buffer);
+}
+
+
+/* Time Protocol, RFC 868 */
+
+/* Return a machine readable date and time as seconds since
+ midnight, Jan 1, 1900. */
+
+#define SEVENTY_YEARS ((unsigned long)25567 * 24 * 60 * 60)
+
+unsigned long
+time_since_1900 (void)
+{
+ struct timeval tv;
+
+ if (gettimeofday (&tv, NULL) < 0)
+ {
+ logmsg (LOG_ERR, "gettimeofday: %s", strerror (errno));
+ return 0;
+ }
+ return htonl ((long) (tv.tv_sec + SEVENTY_YEARS));
+}
+
+void
+time_stream (int fd)
+{
+ unsigned long result = time_since_1900 ();
+ write (fd, (char *) &result, sizeof result);
+}
+
+void
+time_dg (int fd)
+{
+ unsigned long result;
+ struct sockaddr sa;
+ socklen_t size = sizeof sa;
+
+ if (recvfrom (fd, (char *) &result, sizeof result, 0, &sa, &size) < 0)
+ return;
+ result = time_since_1900 ();
+ sendto (fd, (char *) &result, sizeof result, 0, &sa, sizeof sa);
+}
+
+/* Daytime Protocol, RFC 867 */
+void
+daytime_stream (int fd)
+{
+ char buffer[27];
+ time_t now;
+
+ time (&now);
+ sprintf (buffer, "%.24s\r\n", ctime (&now));
+ write (fd, buffer, strlen (buffer));
+}
+
+void
+daytime_dg (int fd)
+{
+ char buffer[27];
+ time_t now;
+ struct sockaddr sa;
+ socklen_t size = sizeof sa;
+
+ time (&now);
+
+ if (recvfrom (fd, buffer, sizeof buffer, 0, &sa, &size) < 0)
+ return;
+ sprintf (buffer, "%.24s\r\n", ctime (&now));
+ sendto (fd, buffer, strlen (buffer), 0, &sa, sizeof sa);
+}
+
+/* Character Generator Protocol, RFC 864 */
+
+#define LINESIZ 72
+
+static void
+chargen_next_line (char *text)
+{
+ static int ch = 0;
+ int i, c;
+
+ do
+ ch = (ch + 1) % 128;
+ while (!c_isprint (ch));
+
+ for (i = 0, c = ch; i < LINESIZ; )
+ {
+ if (c_isprint (c))
+ text[i++] = c;
+ c = (c + 1) % 128;
+ }
+}
+
+void
+chargen_stream (int fd)
+{
+ char text[LINESIZ + 2];
+
+ text[LINESIZ] = '\r';
+ text[LINESIZ + 1] = '\n';
+
+ while (1)
+ {
+ chargen_next_line (text);
+ if (write (fd, text, sizeof text) != sizeof text)
+ break;
+ }
+}
+
+void
+chargen_dg (int fd)
+{
+ struct sockaddr sa;
+ socklen_t size = sizeof sa;
+ char text[LINESIZ + 2];
+
+ if (recvfrom (fd, text, sizeof text, 0, &sa, &size) < 0)
+ return;
+ text[LINESIZ] = '\r';
+ text[LINESIZ + 1] = '\n';
+ chargen_next_line (text);
+ sendto (fd, text, sizeof text, 0, &sa, sizeof sa);
+}
+
+
+/* Quote of the Day Protocol, RFC 865 */
+
+#define QOTD_MAX 512
+#define QOTD_DEF "Quote of the Day\r\n"
+
+static size_t
+trnl (char *text, size_t size)
+{
+ size_t off = size;
+
+ for (; off > 0; off--)
+ if (text[off] == '\n')
+ {
+ if (text[off-1] == '\r')
+ off--;
+ else
+ {
+ if (size == QOTD_MAX)
+ size--;
+ memmove (text + off + 1, text + off, size - off);
+ text[off] = '\r';
+ size++;
+ }
+ }
+ return size;
+}
+
+size_t
+qotd_read (char *text)
+{
+ ssize_t rc;
+ int fd = open (qotdfile, O_RDONLY);
+ if (fd == -1)
+ {
+ logmsg (LOG_ERR, _("cannot open %s: %s"), qotdfile, strerror (errno));
+ strncpy (text, QOTD_DEF, QOTD_MAX);
+ rc = QOTD_MAX;
+ }
+ else
+ {
+ rc = read (fd, text, QOTD_MAX);
+ if (rc >= 0)
+ rc = trnl (text, rc);
+ else
+ {
+ logmsg (LOG_ERR, _("error reading %s: %s"),
+ qotdfile, strerror (errno));
+ strncpy (text, QOTD_DEF, QOTD_MAX);
+ rc = QOTD_MAX;
+ }
+ }
+ close (fd);
+ return rc;
+}
+
+void
+qotd_stream (int fd)
+{
+ char text[QOTD_MAX];
+ size_t len = qotd_read (text);
+ write (fd, text, len);
+}
+
+void
+qotd_dg (int fd)
+{
+ char text[QOTD_MAX];
+ struct sockaddr sa;
+ socklen_t size = sizeof sa;
+ size_t len;
+ if (recvfrom (fd, text, sizeof text, 0, &sa, &size) < 0)
+ return;
+ len = qotd_read (text);
+ sendto (fd, text, len, 0, &sa, sizeof sa);
+}
+
+
+struct inetd_builtin inetd_builtin_tab[] = {
+ /* Echo received data */
+ {"echo", SOCK_STREAM, 0, 0, echo_stream},
+ {"echo", SOCK_DGRAM, 1, 0, echo_dg},
+ /* Internet /dev/null */
+ {"discard", SOCK_STREAM, 0, 0, discard_stream},
+ {"discard", SOCK_DGRAM, 1, 0, discard_dg},
+ /* Return 32 bit time since 1900 */
+ {"time", SOCK_STREAM, 1, 0, time_stream},
+ {"time", SOCK_DGRAM, 1, 0, time_dg},
+ /* Return human-readable time */
+ {"daytime", SOCK_STREAM, 1, 0, daytime_stream},
+ {"daytime", SOCK_DGRAM, 1, 0, daytime_dg},
+ /* Character generator */
+ {"chargen", SOCK_STREAM, 0, 0, chargen_stream},
+ {"chargen", SOCK_DGRAM, 1, 0, chargen_dg},
+ /* Quote of the Day */
+ {"qotd", SOCK_STREAM, 0, 0, qotd_stream},
+ {"qotd", SOCK_DGRAM, 1, 0, qotd_dg},
+#if 0
+ {"tcpmux", SOCK_STREAM, 0, 0, tcpmux},
+#endif
+ {NULL, 0, 0, 0, NULL}
+};
+
+struct inetd_builtin *
+inetd_builtin_lookup (const char *service, int socktype)
+{
+ struct inetd_builtin *bp;
+
+ for (bp = inetd_builtin_tab; bp->service; bp++)
+ if (bp->socktype == socktype && strcmp (bp->service, service) == 0)
+ return bp;
+ return NULL;
+}
diff --git a/src/inetd.c b/src/inetd.c
index 270425d..f6c8276 100644
--- a/src/inetd.c
+++ b/src/inetd.c
@@ -68,7 +68,8 @@ inetd_conf_file (const char *file)
char *address;
char *service;
size_t len;
-
+ struct inetd_builtin *builtin;
+
if (line_no)
wordsplit_free (&ws);
@@ -182,7 +183,21 @@ inetd_conf_file (const char *file)
group = ws.ws_wordv[IFLD_USER] + len + 1;
}
user = ws.ws_wordv[IFLD_USER];
-
+
+ /* Is it a built-in? */
+ if (strcmp (ws.ws_wordv[IFLD_SERVER_PATH], "internal") == 0)
+ {
+ builtin = inetd_builtin_lookup (service, socket_type);
+ if (!builtin)
+ {
+ logmsg (LOG_ERR, "%s:%lu: %s",
+ file, line_no, _("unknown built-in"));
+ continue;
+ }
+ }
+ else
+ builtin = NULL;
+
/* Create the component */
if (address)
{
@@ -195,12 +210,18 @@ inetd_conf_file (const char *file)
}
else
comp = component_create (service);
-
+
comp->mode = pies_comp_inetd;
comp->socket_type = socket_type;
comp->socket_url = url;
comp->max_rate = max_rate;
- comp->flags = flags;
+ if (builtin)
+ {
+ comp->builtin = builtin;
+ comp->flags = builtin->flags;
+ }
+ else
+ comp->flags = flags;
comp->privs.user = xstrdup (user); /* FIXME: memory leak */
if (group)
{
diff --git a/src/pies.c b/src/pies.c
index 74e71f7..49c4060 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -32,6 +32,7 @@ int inetd_mode;
char *pidfile = LOCALSTATEDIR "/pies.pid";
char *ctlfile = LOCALSTATEDIR "/pies.ctl";
char *statfile = LOCALSTATEDIR "/pies.stat";
+char *qotdfile = LOCALSTATEDIR "/pies.qotd";
mode_t pies_umask = 0;
unsigned long shutdown_timeout = 5;
size_t default_max_rate;
@@ -1273,6 +1274,11 @@ struct grecs_keyword pies_keywords[] = {
grecs_type_string, &statfile, 0,
NULL,
},
+ {"qotd-file",
+ NULL,
+ N_("Set location of the QOTD file."),
+ grecs_type_string, &qotdfile, 0,
+ NULL },
{"user",
NULL,
N_("Run with this user privileges."),
diff --git a/src/pies.h b/src/pies.h
index 5ba6ca7..d9c1a3c 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -158,6 +158,7 @@ struct component
size_t max_rate; /* Maximum number of invocations per minute
(inetd) */
int socket_type; /* Socket type */
+ struct inetd_builtin *builtin; /* Builtin function (inetd) */
char *rmfile; /* Try to remove this file before starting */
struct pies_privs privs; /* UID/GIDS+groups to run under */
mode_t umask; /* Umask to install before starting */
@@ -188,6 +189,7 @@ extern char *mailer_command_line;
extern int mailer_argc;
extern char **mailer_argv;
extern size_t default_max_rate;
+extern char *qotdfile;
void register_prog (struct component *comp);
size_t progman_running_count (void);
@@ -333,3 +335,17 @@ void pies_epriv_setup (struct pies_privs *);
/* inetd.c */
int inetd_parse_conf (const char *file);
+
+/* inetd-bi.c */
+struct inetd_builtin
+{
+ const char *service;
+ int socktype;
+ int single_process;
+ int flags;
+ void (*fun) (int);
+};
+
+struct inetd_builtin *inetd_builtin_lookup (const char *service, int socktype);
+
+
diff --git a/src/progman.c b/src/progman.c
index f0cc4c9..35fc876 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -754,7 +754,13 @@ prog_start (struct prog *prog)
logmsg (LOG_ERR, _("%s: cannot remove file `%s': %s"),
prog->tag, prog->v.p.comp->rmfile, strerror (errno));
}
-
+
+ if (prog->v.p.comp->builtin && prog->v.p.comp->builtin->single_process)
+ {
+ prog->v.p.comp->builtin->fun (prog->v.p.socket);
+ return;
+ }
+
redir[RETR_OUT] = open_redirector (prog, RETR_OUT);
redir[RETR_ERR] = open_redirector (prog, RETR_ERR);
@@ -789,6 +795,14 @@ prog_start (struct prog *prog)
prog->v.p.comp->limits ?
prog->v.p.comp->limits : pies_limits);
+ if (prog->v.p.comp->builtin)
+ {
+ mf_proctitle_format ("inetd %s",
+ prog->v.p.comp->builtin->service);
+ prog->v.p.comp->builtin->fun (prog->v.p.socket);
+ _exit (0);
+ }
+
if (debug_level >= 1)
{
int i;
@@ -843,13 +857,13 @@ prog_start (struct prog *prog)
if (prog->v.p.comp->mode == pies_comp_pass_fd)
FD_SET (prog->v.p.socket, &fdset);
close_fds (&fdset);
-
+
execvp (prog->v.p.comp->program ?
prog->v.p.comp->program : prog->v.p.comp->argv[0],
prog->v.p.comp->argv);
openlog (log_tag, LOG_PID, prog->v.p.comp->facility);
syslog (LOG_CRIT, _("cannot start `%s': %s"), prog->tag,
- strerror (errno));
+ strerror (errno));
_exit (EX_SOFTWARE);
case -1:
@@ -1339,7 +1353,7 @@ prog_start_prerequisites (struct prog *prog)
if (!prog->prereq)
return 0; /* Ok to startup */
- debug (1, ("Starting prerequisites of %s", prog->tag));
+ debug (1, ("starting prerequisites of %s", prog->tag));
ret = 0;
for (i = 0; prog->prereq[i]; i++)
{

Return to:

Send suggestions and report system problems to the System administrator.