diff options
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/inetd-bi.c | 305 | ||||
-rw-r--r-- | src/inetd.c | 29 | ||||
-rw-r--r-- | src/pies.c | 6 | ||||
-rw-r--r-- | src/pies.h | 16 | ||||
-rw-r--r-- | src/progman.c | 22 |
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) { @@ -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."), @@ -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++) { |