diff options
-rw-r--r-- | src/inetd-bi.c | 116 | ||||
-rw-r--r-- | src/inetd.c | 66 | ||||
-rw-r--r-- | src/pies.h | 10 | ||||
-rw-r--r-- | src/progman.c | 166 |
4 files changed, 270 insertions, 88 deletions
diff --git a/src/inetd-bi.c b/src/inetd-bi.c index f86f373..60e6fb5 100644 --- a/src/inetd-bi.c +++ b/src/inetd-bi.c @@ -20,7 +20,7 @@ #define INTBUFSIZE 8192 /* Echo protocol, RFC 862 */ -void +static void echo_stream (int fd) { int rc; @@ -31,7 +31,7 @@ echo_stream (int fd) ; } -void +static void echo_dg (int fd) { int rc; @@ -46,7 +46,7 @@ echo_dg (int fd) } /* Discard protocol, RFC 863 */ -void +static void discard_stream (int fd) { int rc; @@ -61,7 +61,7 @@ discard_stream (int fd) } } -void +static void discard_dg (int fd) { char buffer[INTBUFSIZE]; @@ -76,7 +76,7 @@ discard_dg (int fd) #define SEVENTY_YEARS ((unsigned long)25567 * 24 * 60 * 60) -unsigned long +static unsigned long time_since_1900 (void) { struct timeval tv; @@ -89,14 +89,14 @@ time_since_1900 (void) return htonl ((long) (tv.tv_sec + SEVENTY_YEARS)); } -void +static void time_stream (int fd) { unsigned long result = time_since_1900 (); write (fd, (char *) &result, sizeof result); } -void +static void time_dg (int fd) { unsigned long result; @@ -110,7 +110,7 @@ time_dg (int fd) } /* Daytime Protocol, RFC 867 */ -void +static void daytime_stream (int fd) { char buffer[27]; @@ -121,7 +121,7 @@ daytime_stream (int fd) write (fd, buffer, strlen (buffer)); } -void +static void daytime_dg (int fd) { char buffer[27]; @@ -159,7 +159,7 @@ chargen_next_line (char *text) } } -void +static void chargen_stream (int fd) { char text[LINESIZ + 2]; @@ -175,7 +175,7 @@ chargen_stream (int fd) } } -void +static void chargen_dg (int fd) { struct sockaddr sa; @@ -218,7 +218,7 @@ trnl (char *text, size_t size) return size; } -size_t +static size_t qotd_read (char *text) { ssize_t rc; @@ -246,7 +246,7 @@ qotd_read (char *text) return rc; } -void +static void qotd_stream (int fd) { char text[QOTD_MAX]; @@ -254,7 +254,7 @@ qotd_stream (int fd) write (fd, text, len); } -void +static void qotd_dg (int fd) { char text[QOTD_MAX]; @@ -267,7 +267,90 @@ qotd_dg (int fd) sendto (fd, text, len, 0, &sa, sizeof sa); } + +/* TCPMUX service, RFC 1078 */ +#define MAX_SERV_LEN (256+2) + +static int +fd_getline (int fd, char *buf, int len) +{ + int count = 0, n; + + do + { + n = read (fd, buf, len - count); + if (n == 0) + return count; + if (n < 0) + return -1; + while (--n >= 0) + { + if (*buf == '\r' || *buf == '\n' || *buf == '\0') + return count; + count++; + buf++; + } + } + while (count < len); + return count; +} + +static int +fd_write (int fd, const char *text) +{ + return write (fd, text, strlen (text)); +} + +static int +tcpmux_help (struct component *comp, void *data) +{ + int *pfd = data; + + if (comp->flags & (CF_TCPMUXPLUS | CF_TCPMUX)) + { + fd_write (*pfd, comp->service); + fd_write (*pfd, "\r\n"); + } + return 0; +} +static void +tcpmux (int fd) +{ + char service[MAX_SERV_LEN + 1]; + size_t len; + struct component *comp; + + /* Read service name */ + if ((len = fd_getline (fd, service, MAX_SERV_LEN)) < 0) + { + fd_write (fd, "-Error reading service name\r\n"); + return; + } + service[len] = 0; + + debug (2, ("tcpmux: someone wants %s", service)); + + if (!strcasecmp (service, "help")) + { + progman_iterate_comp (tcpmux_help, &fd); + return; + } + + comp = progman_lookup_service (service); + if (!comp) + { + fd_write (fd, "-Service not available\r\n"); + return; + } + + if (comp->flags & CF_TCPMUXPLUS) + fd_write (fd, "+Go\r\n"); + + progman_run_comp (comp, fd); +} + + struct inetd_builtin inetd_builtin_tab[] = { /* Echo received data */ {"echo", SOCK_STREAM, 0, 0, echo_stream}, @@ -287,9 +370,8 @@ struct inetd_builtin inetd_builtin_tab[] = { /* 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 + /* TCPMUX */ + {"tcpmux", SOCK_STREAM, 0, 0, tcpmux}, {NULL, 0, 0, 0, NULL} }; diff --git a/src/inetd.c b/src/inetd.c index f6c8276..f356512 100644 --- a/src/inetd.c +++ b/src/inetd.c @@ -35,6 +35,9 @@ listel_dispose(const void *el) free((void*)el); } +#define TCPMUX_PREFIX_STR "tcpmux/" +#define TCPMUX_PREFIX_LEN (sizeof(TCPMUX_PREFIX_STR)-1) + static int inetd_conf_file (const char *file) { @@ -69,6 +72,7 @@ inetd_conf_file (const char *file) char *service; size_t len; struct inetd_builtin *builtin; + char *tag; if (line_no) wordsplit_free (&ws); @@ -135,21 +139,50 @@ inetd_conf_file (const char *file) continue; } - /* Create URL from protocol and service fields. */ - str = xasprintf ("inet+%s://%s:%s", - ws.ws_wordv[IFLD_PROTOCOL], - address ? address : "0.0.0.0", - service); - if (pies_url_create (&url, str)) + tag = service; + /* Handle eventual "tcpmux/" */ + if (strncmp (service, TCPMUX_PREFIX_STR, TCPMUX_PREFIX_LEN) == 0) { - /* FIXME: Better error message */ - logmsg (LOG_ERR, "%s:%lu: %s", - file, line_no, _("invalid socket address")); - continue; - } - - free (str); + service += TCPMUX_PREFIX_LEN; + if (*service == '+') + { + flags |= CF_TCPMUXPLUS; + service++; + } + else + flags |= CF_TCPMUX; + if (strncmp (ws.ws_wordv[IFLD_PROTOCOL], "tcp", 3)) + { + logmsg (LOG_ERR, "%s:%lu: %s", + file, line_no, _("bad protocol for tcpmux service")); + continue; + } + if (socket_type != SOCK_STREAM) + { + logmsg (LOG_ERR, "%s:%lu: %s", + file, line_no, _("bad socket type for tcpmux service")); + continue; + } + url = NULL; + } + else + { + /* Create URL from protocol and service fields. */ + str = xasprintf ("inet+%s://%s:%s", + ws.ws_wordv[IFLD_PROTOCOL], + address ? address : "0.0.0.0", + service); + if (pies_url_create (&url, str)) + { + /* FIXME: Better error message */ + logmsg (LOG_ERR, "%s:%lu: %s", + file, line_no, _("invalid socket address")); + continue; + } + free (str); + } + /* Parse wait/nowait field */ str = strchr (ws.ws_wordv[IFLD_WAIT], '.'); if (str) @@ -201,15 +234,15 @@ inetd_conf_file (const char *file) /* Create the component */ if (address) { - str = xmalloc (strlen (address) + 1 + strlen (service) + 1); + str = xmalloc (strlen (address) + 1 + strlen (tag) + 1); strcpy (str, address); strcat (str, ":"); - strcat (str, service); + strcat (str, tag); comp = component_create (str); free (str); } else - comp = component_create (service); + comp = component_create (tag); comp->mode = pies_comp_inetd; comp->socket_type = socket_type; @@ -222,6 +255,7 @@ inetd_conf_file (const char *file) } else comp->flags = flags; + comp->service = xstrdup (service); comp->privs.user = xstrdup (user); /* FIXME: memory leak */ if (group) { @@ -140,6 +140,8 @@ enum pies_comp_mode #define CF_PRECIOUS 0x02 /* The component is precious (should not be disabled) */ #define CF_WAIT 0x04 +#define CF_TCPMUX 0x08 +#define CF_TCPMUXPLUS 0x10 struct component { @@ -159,6 +161,7 @@ struct component (inetd) */ int socket_type; /* Socket type */ struct inetd_builtin *builtin; /* Builtin function (inetd) */ + char *service; 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 */ @@ -205,6 +208,12 @@ int progman_accept (int socket); int progman_build_depmap (void); void progman_create_sockets (void); struct component *progman_lookup_component (const char *tag); +struct component *progman_lookup_service (const char *service); +void progman_run_comp (struct component *comp, int fd); + +void progman_iterate_comp (int (*fun) (struct component *, void *), + void *data); + void log_setup (int want_stderr); void signal_setup (RETSIGTYPE (*sf)(int)); @@ -232,6 +241,7 @@ int assert_grecs_value_type (grecs_locus_t *locus, int str_to_socket_type (const char *str, int *pret); struct component *component_create (const char *name); + void component_finish (struct component *comp, grecs_locus_t *locus); struct grecs_keyword *find_component_keyword (const char *ident); diff --git a/src/progman.c b/src/progman.c index 35fc876..1235d81 100644 --- a/src/progman.c +++ b/src/progman.c @@ -78,6 +78,19 @@ static struct prog *proghead, *progtail; static pies_depmap_t depmap; static int recompute_alarm; +void +progman_iterate_comp (int (*fun) (struct component *, void *), void *data) +{ + struct prog *prog; + + for (prog = proghead; prog; prog = prog->next) + if (IS_COMPONENT (prog) + && !(prog->v.p.comp->mode == pies_comp_inetd + && prog->v.p.listener) + && fun (prog->v.p.comp, data)) + break; +} + static struct prog * prog_lookup_by_pid (pid_t pid) { @@ -110,6 +123,18 @@ prog_lookup_by_tag (const char *tag) return prog; } +struct prog * +prog_lookup_by_service (const char *service) +{ + struct prog *prog; + for (prog = proghead; prog; prog = prog->next) + if (IS_COMPONENT (prog) + && prog->v.p.comp->service + && strcmp (prog->v.p.comp->service, service) == 0) + break; + return prog; +} + struct component * progman_lookup_component (const char *tag) { @@ -120,6 +145,15 @@ progman_lookup_component (const char *tag) return NULL; } +struct component * +progman_lookup_service (const char *service) +{ + struct prog *prog = prog_lookup_by_service (service); + if (!prog) + return NULL; + return prog->v.p.comp; +} + struct prog * prog_lookup_by_idx (unsigned idx) { @@ -693,6 +727,77 @@ prog_open_socket (struct prog *prog) } static void +prog_start_prologue (struct prog *prog) +{ + if (prog->v.p.comp->dir) + { + debug (1, (_("chdir %s"), prog->v.p.comp->dir)); + if (chdir (prog->v.p.comp->dir)) + logmsg (LOG_ERR, _("%s: cannot change to directory %s: %s"), + prog->tag, prog->v.p.comp->dir, strerror (errno)); + } + + environ = env_setup (prog->v.p.comp->env); + if (debug_level >= 4) + { + int i; + logmsg_printf (LOG_DEBUG, "environment: "); + for (i = 0; environ[i]; i++) + logmsg_printf (LOG_DEBUG, "%s ", environ[i]); + logmsg_printf (LOG_DEBUG, "\n"); + } + + pies_priv_setup (&prog->v.p.comp->privs); + if (prog->v.p.comp->umask) + umask (prog->v.p.comp->umask); + + set_limits (prog->tag, + prog->v.p.comp->limits ? + prog->v.p.comp->limits : pies_limits); + + if (debug_level >= 1) + { + int i; + struct component *comp = prog->v.p.comp; + + logmsg_printf (LOG_DEBUG, "executing"); + for (i = 0; i < comp->argc; i++) + logmsg_printf (LOG_DEBUG, " %s", + quotearg (comp->argv[i])); + logmsg_printf (LOG_DEBUG, "\n"); + } +} + +static void +prog_execute (struct prog *prog) +{ + if (prog->v.p.comp->builtin) + { + mf_proctitle_format ("inetd %s", + prog->v.p.comp->builtin->service); + prog->v.p.comp->builtin->fun (0); + _exit (0); + } + + 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)); + _exit (EX_SOFTWARE); +} + +void +progman_run_comp (struct component *comp, int fd) +{ + struct prog *prog = register_prog0 (comp, -1); + prog->v.p.socket = fd; + prog_start_prologue (prog); + prog_execute (prog); +} + +static void prog_start (struct prog *prog) { pid_t pid; @@ -769,52 +874,7 @@ prog_start (struct prog *prog) /* The child branch. */ case 0: signal_setup (SIG_DFL); - if (prog->v.p.comp->dir) - { - debug (1, (_("chdir %s"), prog->v.p.comp->dir)); - if (chdir (prog->v.p.comp->dir)) - logmsg (LOG_ERR, _("%s: cannot change to directory %s: %s"), - prog->tag, prog->v.p.comp->dir, strerror (errno)); - } - - environ = env_setup (prog->v.p.comp->env); - if (debug_level >= 4) - { - int i; - logmsg_printf (LOG_DEBUG, "environment: "); - for (i = 0; environ[i]; i++) - logmsg_printf (LOG_DEBUG, "%s ", environ[i]); - logmsg_printf (LOG_DEBUG, "\n"); - } - - pies_priv_setup (&prog->v.p.comp->privs); - if (prog->v.p.comp->umask) - umask (prog->v.p.comp->umask); - - set_limits (prog->tag, - 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; - struct component *comp = prog->v.p.comp; - - logmsg_printf (LOG_DEBUG, "executing"); - for (i = 0; i < comp->argc; i++) - logmsg_printf (LOG_DEBUG, " %s", - quotearg (comp->argv[i])); - logmsg_printf (LOG_DEBUG, "\n"); - } - + prog_start_prologue (prog); switch (prog->v.p.comp->mode) { case pies_comp_pass_fd: @@ -858,14 +918,9 @@ prog_start (struct prog *prog) 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)); - _exit (EX_SOFTWARE); - + prog_execute (prog); + + case -1: logmsg (LOG_CRIT, _("cannot run `%s': fork failed: %s"), @@ -1199,7 +1254,8 @@ progman_create_sockets () if (IS_COMPONENT (prog)) { struct component *comp = prog->v.p.comp; - if (comp->mode == pies_comp_inetd) + if (comp->mode == pies_comp_inetd + && !(comp->flags & (CF_TCPMUXPLUS | CF_TCPMUX))) { int fd = create_socket (comp->socket_url, comp->socket_type, |