aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-11-24 13:38:52 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2009-11-24 14:04:31 +0200
commite6772c4d68849cfdb4547a59bc51cb6dd0acd2c6 (patch)
tree72c0baa79455c9008df3f137a11117772b321a52
parent68796f86fe6abae13debf253c0e16b4bac9c1bca (diff)
downloadpies-e6772c4d68849cfdb4547a59bc51cb6dd0acd2c6.tar.gz
pies-e6772c4d68849cfdb4547a59bc51cb6dd0acd2c6.tar.bz2
Implement parsing of inetd.conf files.
* src/Makefile.am (pies_SOURCES): Add inetd.c. * src/inetd.c: New file. * src/pies.c (inetd_mode): New global. (str_to_socket_type): New function. (_cb_socket_type): Use str_to_socket_type. (_cm_include_meta1): Rename to _cb_include_meta1. (_cb_include_inetd): New function. (pies_keywords): New keyword "include-inetd". (options): New option --inetd. (main): Handle inetd mode. * src/pies.h (str_to_socket_type): New proto. (disable_socket, enable_socket): Fix return type. * src/progman.c (redirect_to_file): Avoid coredump on privs.user == NULL. (open_redirector,env_setup) (progman_start,run_command): Remove unneeded variable. (progman_start): Fix diagnostic message. * src/socket.c (disable_socket, enable_socket): Fix return type. Do nothing if fd < 0. * src/userprivs.c (switch_to_privs): Allow to pass uid==0.
-rw-r--r--src/Makefile.am1
-rw-r--r--src/inetd.c320
-rw-r--r--src/pies.c108
-rw-r--r--src/pies.h12
-rw-r--r--src/progman.c11
-rw-r--r--src/socket.c8
-rw-r--r--src/userprivs.c6
7 files changed, 417 insertions, 49 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 63043f0..8735607 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -21,6 +21,7 @@ pies_SOURCES = \
addrfmt.c\
depmap.c\
diag.c\
+ inetd.c\
limits.c\
meta.c\
meta1gram.y\
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);
+}
diff --git a/src/pies.c b/src/pies.c
index 2bf127c..fd83e04 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -28,6 +28,7 @@ char *log_tag;
struct pies_privs pies_privs;
int foreground;
int command;
+int inetd_mode;
char *pidfile = LOCALSTATEDIR "/pies.pid";
char *ctlfile = LOCALSTATEDIR "/pies.ctl";
char *statfile = LOCALSTATEDIR "/pies.stat";
@@ -712,33 +713,35 @@ _cb_url (enum grecs_callback_command cmd,
return 0;
}
+int
+str_to_socket_type (const char *str, int *pret)
+{
+ if (strcmp (str, "stream") == 0)
+ *pret = SOCK_STREAM;
+ else if (strcmp (str, "dgram") == 0)
+ *pret = SOCK_DGRAM;
+ else if (strcmp (str, "rdm") == 0)
+ *pret = SOCK_RDM;
+ else if (strcmp (str, "seqpacket") == 0)
+ *pret = SOCK_SEQPACKET;
+ else if (strcmp (str, "raw") == 0)
+ *pret = SOCK_RAW;
+ else
+ return 1;
+ return 0;
+}
+
static int
_cb_socket_type (enum grecs_callback_command cmd,
grecs_locus_t *locus,
void *varptr, grecs_value_t *value, void *cb_data)
{
- int t;
-
if (assert_scalar_stmt (locus, cmd)
|| assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
return 1;
- if (strcmp (value->v.string, "stream") == 0)
- t = SOCK_STREAM;
- else if (strcmp (value->v.string, "dgram") == 0)
- t = SOCK_DGRAM;
- else if (strcmp (value->v.string, "rdm") == 0)
- t = SOCK_RDM;
- else if (strcmp (value->v.string, "seqpacket") == 0)
- t = SOCK_SEQPACKET;
- else if (strcmp (value->v.string, "raw") == 0)
- t = SOCK_RAW;
- else
- {
- grecs_error (locus, 0, _("bad socket type"));
- return 0;
- }
- *(int*)varptr = t;
+ if (str_to_socket_type (value->v.string, varptr))
+ grecs_error (locus, 0, _("bad socket type"));
return 0;
}
@@ -1207,7 +1210,7 @@ static struct grecs_keyword syslog_kw[] = {
struct component default_component;
static int
-_cm_include_meta1 (enum grecs_callback_command cmd,
+_cb_include_meta1 (enum grecs_callback_command cmd,
grecs_locus_t *locus,
void *varptr, grecs_value_t *value, void *cb_data)
{
@@ -1217,6 +1220,16 @@ _cm_include_meta1 (enum grecs_callback_command cmd,
return 0;
}
+static int
+_cb_include_inetd (enum grecs_callback_command cmd,
+ grecs_locus_t *locus,
+ void *varptr, grecs_value_t *value, void *cb_data)
+{
+ if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
+ return 1;
+ return inetd_parse_conf (value->v.string);
+}
+
struct grecs_keyword pies_keywords[] = {
{"component",
N_("<tag: string>"),
@@ -1303,11 +1316,16 @@ struct grecs_keyword pies_keywords[] = {
N_("Define an ACL."),
grecs_type_section, NULL, 0,
defacl_section_parser, NULL, acl_keywords},
+ {"include-inetd",
+ N_("file-or-dir: string"),
+ N_("Include inetd configuration file or directory"),
+ grecs_type_string, NULL, 0,
+ _cb_include_inetd },
{"include-meta1",
N_("file: string"),
N_("Include components from the specified MeTA1 configuration file."),
grecs_type_string, NULL, 0,
- _cm_include_meta1,
+ _cb_include_meta1,
},
{"meta1-queue-dir",
NULL,
@@ -1391,6 +1409,8 @@ static struct argp_option options[] = {
N_("parse configuration file and exit"), GRP + 1},
{NULL, 'E', NULL, 0,
N_("preprocess config and exit"), GRP + 1},
+ {"inetd", 'i', NULL, 0,
+ N_("run in inetd mode"), GRP + 1},
{"config-file", 'c', N_("FILE"), 0,
N_("use FILE instead of the default configuration"), GRP + 1},
{"config-help", OPT_CONFIG_HELP, NULL, 0,
@@ -1453,6 +1473,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
preprocess_only = 1;
break;
+ case 'i':
+ inetd_mode = 1;
+ break;
+
case 't':
log_to_stderr_only = 1;
lint_mode = 1;
@@ -1938,20 +1962,44 @@ main (int argc, char **argv)
if (argp_parse (&argp, argc, argv, 0, &index, NULL))
exit (EX_USAGE);
- if (!DEFAULT_PREPROCESSOR)
- grecs_preprocessor = NULL;
- else
+ if (inetd_mode)
{
- grecs_preprocessor = obstack_finish (&pp_stk);
- free (pp_qopt);
+ if (index == argc)
+ {
+ if (inetd_parse_conf (SYSCONFDIR "/inetd.conf"))
+ exit (EX_CONFIG);
+ }
+ else
+ {
+ int i;
+
+ for (i = index; i < argc; i++)
+ {
+ if (inetd_parse_conf (argv[i]))
+ exit (EX_CONFIG);
+ }
+ }
+
+ index = argc;
}
+ else
+ {
+ if (!DEFAULT_PREPROCESSOR)
+ grecs_preprocessor = NULL;
+ else
+ {
+ grecs_preprocessor = obstack_finish (&pp_stk);
+ free (pp_qopt);
+ }
- if (preprocess_only)
- exit (grecs_preproc_run (conffile, grecs_preprocessor) ? EX_CONFIG : 0);
-
- if (grecs_parse (conffile))
- exit (EX_CONFIG);
+ if (preprocess_only)
+ exit (grecs_preproc_run (conffile, grecs_preprocessor)
+ ? EX_CONFIG : 0);
+ if (grecs_parse (conffile))
+ exit (EX_CONFIG);
+ }
+
set_mailer_argcv ();
if (lint_mode)
diff --git a/src/pies.h b/src/pies.h
index 68a2ff5..e387a56 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -162,7 +162,7 @@ struct component
struct pies_url *socket_url; /* Socket to listen on
(if mode != pies_comp_exec) */
char *pass_fd_socket; /* Socket to pass fd on
- (if mode == pies_comp_pass_fd) */
+ (if mode == pies_comp_pass_fd) */
unsigned pass_fd_timeout; /* Maximum time to wait for pass_fd socket to
become available. */
pies_acl_t acl;
@@ -223,6 +223,8 @@ size_t depmap_next (pies_depmap_t dmap, pies_depmap_pos_t pos);
int assert_grecs_value_type (grecs_locus_t *locus,
const grecs_value_t *value, int type);
+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);
@@ -254,8 +256,8 @@ int register_socket (int socktype, int fd);
int pass_fd (const char *socket, int fd, unsigned time_out);
int create_socket (struct pies_url *url, int socket_type,
const char *user, mode_t umask);
-int disable_socket (int fd);
-int enable_socket (int fd);
+void disable_socket (int fd);
+void enable_socket (int fd);
int parse_limits (limits_record_t *plrec, char *str, char **endp);
@@ -324,4 +326,6 @@ int switch_to_privs (uid_t uid, gid_t gid, gl_list_t retain_groups);
void pies_priv_setup (struct pies_privs *);
void pies_epriv_setup (struct pies_privs *);
-
+
+/* inetd.c */
+int inetd_parse_conf (const char *file);
diff --git a/src/progman.c b/src/progman.c
index 85a5068..227b438 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -382,8 +382,8 @@ redirect_to_file (struct prog *master, int stream)
return -1;
}
/* Fix file ownership */
- pw = getpwnam (master->v.p.comp->privs.user);
- if (pw)
+ if (master->v.p.comp->privs.user
+ && (pw = getpwnam (master->v.p.comp->privs.user)) != NULL)
chown (master->v.p.comp->redir[stream].v.file, pw->pw_uid, pw->pw_gid);
return fd;
}
@@ -409,7 +409,7 @@ open_redirector (struct prog *master, int stream)
char *buf = NULL;
size_t size = 0;
pid_t pid;
- int i, prio;
+ int prio;
char *tag;
fd_set fdset;
@@ -613,7 +613,6 @@ env_setup (char **env)
static void
prog_start (struct prog *prog)
{
- int i;
pid_t pid;
time_t now;
int redir[2];
@@ -1191,7 +1190,7 @@ progman_start ()
struct prog *prog;
recompute_alarm = 0;
- debug (1, ("Starting components"));
+ debug (1, ("starting components"));
for (prog = proghead; prog; prog = prog->next)
if (IS_COMPONENT (prog)
&& ((prog->v.p.status == status_enabled && prog->pid == 0)
@@ -1706,8 +1705,6 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
if (pid == 0)
{
- int i;
-
debug (1, (_("executing %s"), act->command));
/* Child */
setenv ("PIES_VERSION", PACKAGE_VERSION, 1);
diff --git a/src/socket.c b/src/socket.c
index 8b25073..6c56817 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -423,16 +423,20 @@ register_socket (int socktype, int fd)
return 0;
}
-int
+void
disable_socket (int fd)
{
+ if (fd < 0)
+ return;
debug (2, (_("disabling fd %d"), fd));
FD_CLR (fd, &listenset);
}
-int
+void
enable_socket (int fd)
{
+ if (fd < 0)
+ return;
debug (2, (_("enabling fd %d"), fd));
FD_SET (fd, &listenset);
}
diff --git a/src/userprivs.c b/src/userprivs.c
index 399e229..ba7494f 100644
--- a/src/userprivs.c
+++ b/src/userprivs.c
@@ -89,12 +89,6 @@ switch_to_privs (uid_t uid, gid_t gid, gl_list_t retain_groups)
gid_t *emptygidset;
size_t size = 1, j = 1;
- if (uid == 0)
- {
- logmsg (LOG_ERR, _("refusing to run as root"));
- return 1;
- }
-
/* Create a list of supplementary groups */
size = 1 + (retain_groups ? gl_list_size (retain_groups) : 0);
emptygidset = xcalloc (size, sizeof emptygidset[0]);

Return to:

Send suggestions and report system problems to the System administrator.