aboutsummaryrefslogtreecommitdiff
path: root/src/inetd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/inetd.c')
-rw-r--r--src/inetd.c320
1 files changed, 320 insertions, 0 deletions
diff --git a/src/inetd.c b/src/inetd.c
new file mode 100644
index 0000000..ac40a5a
--- /dev/null
+++ b/src/inetd.c
@@ -0,0 +1,320 @@
+/* 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 <sys/types.h>
+#include <dirent.h>
+
+#define IFLD_SERVICE 0 /* service name */
+#define IFLD_SOCKET 1 /* socket type */
+#define IFLD_PROTOCOL 2 /* protocol */
+#define IFLD_WAIT 3 /* wait/nowait */
+#define IFLD_USER 4 /* user */
+#define IFLD_SERVER_PATH 5 /* server program path */
+#define IFLD_SERVER_ARGS 6 /* server program arguments */
+
+#define IFLD_MIN_COUNT 6 /* Minimum number of fields in entry */
+
+/* FIXME: Duplicated in grex-lex.l */
+static void
+listel_dispose(const void *el)
+{
+ free((void*)el);
+}
+
+static int
+inetd_conf_file (const char *file)
+{
+ FILE *fp;
+ size_t size = 0;
+ char *buf = NULL;
+ size_t line_no = 0;
+ struct wordsplit ws;
+ char *dfl_address = NULL;
+
+ fp = fopen (file, "r");
+ if (!fp)
+ {
+ logmsg (LOG_ERR,
+ _("cannot open configuration file %s: %s"),
+ file, strerror (errno));
+ return 1;
+ }
+
+ while (getline (&buf, &size, fp) >= 0)
+ {
+ char *p;
+ struct component *comp;
+ int socket_type;
+ struct pies_url *url;
+ size_t max_instances = 0;
+ int flags = 0;
+ char *str;
+ char *user = NULL;
+ char *group = NULL;
+ char *address;
+ char *service;
+ size_t len;
+
+ if (line_no)
+ wordsplit_free (&ws);
+
+ line_no++;
+ for (p = buf; *p && c_isblank (*p); p++)
+ ;
+
+ if (!p || *p == '\n' || *p == '#')
+ continue;
+
+ if (wordsplit (p, &ws,
+ WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_WS |
+ WRDSF_SQUEEZE_DELIMS))
+ {
+ logmsg (LOG_ERR, "wordsplit: %s", strerror (errno));
+ continue;
+ }
+
+ if (ws.ws_wordc == 1)
+ {
+ size_t len = strlen (ws.ws_wordv[IFLD_SERVICE]);
+ if (len > 0 && ws.ws_wordv[IFLD_SERVICE][len-1] == ':')
+ {
+ free (dfl_address);
+
+ if (len == 2 && ws.ws_wordv[IFLD_SERVICE][0] == '*')
+ dfl_address = NULL;
+ else
+ {
+ dfl_address = xmalloc (len);
+ memcpy (dfl_address, ws.ws_wordv[IFLD_SERVICE], len-1);
+ dfl_address[len-1] = 0;
+ }
+ continue;
+ }
+ }
+
+ if (ws.ws_wordc < IFLD_MIN_COUNT)
+ {
+ logmsg (LOG_ERR, "%s:%lu: too few fields", file, line_no);
+ continue;
+ }
+
+ /* Parse service */
+ str = strchr (ws.ws_wordv[IFLD_SERVICE], ':');
+ if (str)
+ {
+ *str++ = 0;
+ address = ws.ws_wordv[IFLD_SERVICE];
+ service = str;
+ }
+ else
+ {
+ address = dfl_address;
+ service = ws.ws_wordv[IFLD_SERVICE];
+ }
+
+ /* Parse socket type */
+ if (str_to_socket_type (ws.ws_wordv[IFLD_SOCKET], &socket_type))
+ {
+ logmsg (LOG_ERR, "%s:%lu: %s",
+ file, line_no, _("bad socket type"));
+ 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))
+ {
+ /* 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)
+ {
+ size_t n;
+
+ *str++ = 0;
+ n = strtoul(str, &p, 10);
+ if (*p)
+ logmsg (LOG_WARNING, "%s:%lu: invalid number (near %s)",
+ file, line_no, p);
+ else
+ max_instances = n;
+ }
+
+ if (strcmp (ws.ws_wordv[IFLD_WAIT], "wait") == 0)
+ flags |= CF_WAIT;
+ else if (strcmp (ws.ws_wordv[IFLD_WAIT], "nowait"))
+ {
+ logmsg (LOG_ERR, "%s:%lu: %s",
+ file, line_no, _("invalid wait field"));
+ pies_url_destroy(&url);
+ continue;
+ }
+
+ /* Parse user/group */
+ len = strcspn (ws.ws_wordv[IFLD_USER], ":.");
+ if (ws.ws_wordv[IFLD_USER][len])
+ {
+ ws.ws_wordv[IFLD_USER][len] = 0;
+ group = ws.ws_wordv[IFLD_USER] + len + 1;
+ }
+ user = ws.ws_wordv[IFLD_USER];
+
+ /* Create the component */
+ if (address)
+ {
+ str = xmalloc (strlen (address) + 1 + strlen (service) + 1);
+ strcpy (str, address);
+ strcat (str, ":");
+ strcat (str, service);
+ comp = component_create (str);
+ free (str);
+ }
+ else
+ comp = component_create (service);
+
+ comp->mode = pies_comp_inetd;
+ comp->socket_type = socket_type;
+ comp->socket_url = url;
+ comp->max_instances = max_instances;
+ comp->flags = flags;
+ comp->privs.user = xstrdup (user); /* FIXME: memory leak */
+ if (group)
+ {
+ comp->privs.groups =
+ gl_list_create_empty (&gl_linked_list_implementation,
+ NULL,
+ NULL,
+ listel_dispose,
+ true);
+ gl_list_add_last (comp->privs.groups, xstrdup (group));
+ }
+
+ comp->program = xstrdup (ws.ws_wordv[IFLD_SERVER_PATH]);
+
+ if (ws.ws_wordc > IFLD_MIN_COUNT)
+ {
+ size_t i, j;
+
+ comp->argc = ws.ws_wordc - IFLD_MIN_COUNT;
+ comp->argv = xcalloc (comp->argc + 1, sizeof (comp->argv[0]));
+ for (i = IFLD_SERVER_ARGS, j = 0; i < ws.ws_wordc; i++, j++)
+ comp->argv[j] = xstrdup (ws.ws_wordv[i]);
+ }
+ else
+ {
+ comp->argc = 1;
+ comp->argv = xcalloc (comp->argc + 1, sizeof (comp->argv[0]));
+ comp->argv[0] = xstrdup (comp->program);
+ }
+
+ if (progman_lookup_component (comp->tag) == NULL)
+ register_prog (comp);
+ }
+
+ if (line_no)
+ wordsplit_free (&ws);
+ free (dfl_address);
+ free (buf);
+ fclose (fp);
+ return 0;
+}
+
+#ifndef S_ISLNK
+# define S_ISLNK(m) 0
+#endif
+#define NAME_INIT_ALLOC 16
+
+static int
+inetd_conf_dir (const char *name)
+{
+ DIR *dir;
+ struct dirent *ent;
+ int errs = 0;
+ char *namebuf;
+ size_t namebufsize;
+ size_t namelen;
+
+ dir = opendir (name);
+ if (!dir)
+ {
+ logmsg (LOG_ERR, _("cannot open directory %s: %s"),
+ name, strerror (errno));
+ return 1;
+ }
+
+ namelen = strlen (name);
+ namebufsize = namelen;
+ if (name[namelen-1] != '/')
+ namebufsize++;
+ namebufsize += NAME_INIT_ALLOC;
+ namebuf = xmalloc (namebufsize);
+ memcpy (namebuf, name, namelen);
+ if (name[namelen-1] != '/')
+ namebuf[namelen++] = 0;
+
+ while ((ent = readdir (dir)))
+ {
+ struct stat st;
+
+ if (stat (ent->d_name, &st))
+ {
+ logmsg (LOG_ERR, _("cannot stat %s/%s: %s"),
+ name, ent->d_name, strerror (errno));
+ errs |= 1;
+ }
+ else if (S_ISREG (st.st_mode) || S_ISLNK (st.st_mode))
+ {
+ size_t len = strlen (ent->d_name);
+ if (namelen + len >= namebufsize)
+ {
+ namebufsize = namelen + len + 1;
+ namebuf = xrealloc (namebuf, namebufsize);
+ }
+ strcpy (namebuf + namelen, ent->d_name);
+ errs |= inetd_conf_file (namebuf);
+ }
+ }
+ free (namebuf);
+ closedir (dir);
+ return errs;
+}
+
+int
+inetd_parse_conf (const char *file)
+{
+ struct stat st;
+
+ if (stat (file, &st))
+ {
+ logmsg (LOG_ERR, _("cannot stat %s: %s"), file, strerror (errno));
+ return 1;
+ }
+ if (S_ISDIR (st.st_mode))
+ return inetd_conf_dir (file);
+
+ return inetd_conf_file (file);
+}

Return to:

Send suggestions and report system problems to the System administrator.