aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2009-11-28 12:09:15 +0200
committerSergey Poznyakoff <gray@gnu.org.ua>2009-11-28 13:15:51 +0200
commit36a53f1875a097fa16bceaf674dc627d916651df (patch)
treeee33a5cf08231f11a3b31e0f16652229d5add561
parent69bc6e88c7babf356efbacbdc2230de407c27590 (diff)
downloadpies-36a53f1875a097fa16bceaf674dc627d916651df.tar.gz
pies-36a53f1875a097fa16bceaf674dc627d916651df.tar.bz2
Handle per-tcpmux ACL's. Optionally pass socket data via environment variables.
* src/inetd-bi.c (tcpmux): Consult the component's ACL before deciding whether to handle the connection. * src/pies.c (str_to_socket_type): Rewrite using strtotok. (socket_type_to_str): New function (str_to_cf): New flags: sockenv and resolve. Use strtotok. (main): Log_tag defaults to program instance name. * src/pies.h: Include socket-related headers. (CF_SOCKENV, CF_RESOLVE): New flags. (pies_sockaddr_storage): New union. (check_acl): New proto. (progman_run_comp): Change signature. (socket_type_to_str): New proto. * src/progman.c (struct prog): New members sa_storage, sa_len. (prog_sockenv): New function. (progman_run_comp): Call prog_sockenv. Initialize sa_storage and sa_len of the created struct prog. (prog_start): Call prog_sockenv. Do not close 2 if logging to stderr. (check_acl): Remove static. (_prog_accept): Use union pies_sockaddr_storage. Pass socket address in pinst->v.p.sa_storage and pinst->v.p.sa_len. (sockenv_hint, envsize): New variables. (add_env): New function. (env_setup): Remove. (environ_setup): New function. * src/socket.c: Remove unnecessary includes.
-rw-r--r--src/inetd-bi.c27
-rw-r--r--src/pies.c63
-rw-r--r--src/pies.h30
-rw-r--r--src/progman.c264
-rw-r--r--src/socket.c14
5 files changed, 300 insertions, 98 deletions
diff --git a/src/inetd-bi.c b/src/inetd-bi.c
index 30423de..d002e4c 100644
--- a/src/inetd-bi.c
+++ b/src/inetd-bi.c
@@ -320,6 +320,9 @@ tcpmux (int fd, struct component const *comp)
char service[MAX_SERV_LEN + 1];
size_t len;
struct component *srv_comp;
+ union pies_sockaddr_storage sa;
+ socklen_t salen = sizeof (sa);
+ int rc;
/* Read service name */
if ((len = fd_getline (fd, service, MAX_SERV_LEN)) < 0)
@@ -344,10 +347,30 @@ tcpmux (int fd, struct component const *comp)
return;
}
+ rc = getpeername (fd, (struct sockaddr *) &sa, &salen);
+ if (rc)
+ logmsg (LOG_ERR, _("%s: cannot get peer name: %s"),
+ comp->tag, strerror (errno));
+
+ if (comp->acl)
+ {
+ if (rc)
+ {
+ fd_write (fd, "-Service not available\r\n");
+ return;
+ }
+
+ if (check_acl (comp->acl, (struct sockaddr *) &sa, salen))
+ {
+ fd_write (fd, "-Service not available\r\n");
+ return;
+ }
+ }
+
if (srv_comp->flags & CF_TCPMUXPLUS)
fd_write (fd, "+Go\r\n");
-
- progman_run_comp (srv_comp, fd);
+
+ progman_run_comp (srv_comp, fd, &sa, salen);
}
diff --git a/src/pies.c b/src/pies.c
index c583d7b..20ad9e2 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -772,22 +772,26 @@ _cb_url (enum grecs_callback_command cmd,
return 0;
}
+static struct tokendef socktype_xtab[] = {
+ { "stream", SOCK_STREAM },
+ { "dgram", SOCK_DGRAM },
+ { "seqpacket", SOCK_SEQPACKET },
+ { "raw", SOCK_RAW },
+ { "rdm", SOCK_RDM },
+ { "packet", SOCK_PACKET },
+ { NULL }
+};
+
int
-str_to_socket_type (const char *str, int *pret)
+str_to_socket_type (const char *str, int *pres)
{
- 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;
+ return strtotok (socktype_xtab, str, pres);
+}
+
+int
+socket_type_to_str (int socket_type, const char **pres)
+{
+ return toktostr (socktype_xtab, socket_type, pres);
}
static int
@@ -854,6 +858,18 @@ str_to_cf (const char *string, int *flags)
size_t len = strlen (string);
int neg = 0;
int mask;
+
+ static struct tokendef cf_tab[] = {
+ { "disable", CF_DISABLED },
+ { "precious", CF_PRECIOUS },
+ { "wait", CF_WAIT },
+ { "tcpmux", CF_TCPMUX },
+ { "tcpmuxplus", CF_TCPMUXPLUS },
+ { "internal", CF_INTERNAL },
+ { "sockenv", CF_SOCKENV },
+ { "resolve", CF_RESOLVE },
+ { NULL }
+ };
if (len > 2 && memcmp (string, "no", 2) == 0)
{
@@ -861,19 +877,7 @@ str_to_cf (const char *string, int *flags)
string += 2;
}
- if (strcmp (string, "disable") == 0)
- mask = CF_DISABLED;
- else if (strcmp (string, "precious") == 0)
- mask = CF_PRECIOUS;
- else if (strcmp (string, "wait") == 0)
- mask = CF_WAIT;
- else if (strcmp (string, "tcpmux") == 0)
- mask = CF_TCPMUX;
- else if (strcmp (string, "tcpmuxplus") == 0)
- mask = CF_TCPMUXPLUS;
- else if (strcmp (string, "internal") == 0)
- mask = CF_INTERNAL;
- else
+ if (strtotok (cf_tab, string, &mask))
return 1;
if (neg)
@@ -2215,6 +2219,9 @@ main (int argc, char **argv)
else
instance++;
}
+ else
+ log_tag = instance;
+
set_file_names (instance);
if (!DEFAULT_PREPROCESSOR)
@@ -2224,7 +2231,7 @@ main (int argc, char **argv)
grecs_preprocessor = obstack_finish (&pp_stk);
free (pp_qopt);
}
-
+
if (preprocess_only)
{
for (file = conf_head; file; file = file->next)
diff --git a/src/pies.h b/src/pies.h
index 4d2f774..d6347ce 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -23,6 +23,10 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <arpa/inet.h>
+#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
@@ -139,10 +143,16 @@ enum pies_comp_mode
#define CF_DISABLED 0x01 /* The componenet is disabled */
#define CF_PRECIOUS 0x02 /* The component is precious (should not
be disabled) */
-#define CF_WAIT 0x04
-#define CF_TCPMUX 0x08
-#define CF_TCPMUXPLUS 0x10
-#define CF_INTERNAL 0x20
+#define CF_WAIT 0x04 /* Wait for the component instance to
+ terminate. */
+#define CF_TCPMUX 0x08 /* A plain TCPMUX service */
+#define CF_TCPMUXPLUS 0x10 /* A TCPMUX-plus service, i.e. pies
+ must emit a '+' response before starting
+ it */
+#define CF_INTERNAL 0x20 /* An internal inetd service */
+#define CF_SOCKENV 0x40 /* Component wants socket information in
+ the environment */
+#define CF_RESOLVE 0x80 /* Resolve IP addresses */
#define ISCF_TCPMUX(f) ((f) & (CF_TCPMUX | CF_TCPMUXPLUS))
@@ -187,6 +197,13 @@ struct component
struct action act_temp; /* Auxiliary object used during configuration */
};
+union pies_sockaddr_storage
+{
+ struct sockaddr s;
+ struct sockaddr_in s_in;
+ struct sockaddr_un s_un;
+};
+
extern char *log_tag;
extern int log_facility;
extern unsigned long shutdown_timeout;
@@ -217,11 +234,13 @@ struct component *progman_lookup_component (const char *tag);
struct component *progman_lookup_tcpmux (const char *service,
const char *master);
-void progman_run_comp (struct component *comp, int fd);
+void progman_run_comp (struct component *comp, int fd,
+ union pies_sockaddr_storage *sa, socklen_t salen);
void progman_iterate_comp (int (*fun) (struct component *, void *),
void *data);
+int check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen);
void log_setup (int want_stderr);
void signal_setup (RETSIGTYPE (*sf)(int));
@@ -247,6 +266,7 @@ 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);
+int socket_type_to_str (int socket_type, const char **pres);
struct component *component_create (const char *name);
diff --git a/src/progman.c b/src/progman.c
index 4743507..fa4e377 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -57,6 +57,8 @@ struct prog
size_t num_instances; /* Number of running instances */
/* If comp->type == pies_comp_inetd && status == status_enabled */
struct prog *listener;
+ union pies_sockaddr_storage sa_storage;
+ size_t sa_len;
} p;
struct
@@ -507,19 +509,101 @@ open_redirector (struct prog *master, int stream)
}
}
-extern char **environ;
+
+extern char **environ; /* Environment */
+static size_t envsize; /* Size of environ. If it is not 0, then we
+ have allocated space for the environ. */
+
+#define ENV_PROTO "PROTO"
+#define ENV_SOCKTYPE "SOCKTYPE"
+#define ENV_LOCALIP "LOCALIP"
+#define ENV_LOCALPORT "LOCALPORT"
+#define ENV_LOCALHOST "LOCALHOST"
+#define ENV_REMOTEIP "REMOTEIP"
+#define ENV_REMOTEPORT "REMOTEPORT"
+#define ENV_REMOTEHOST "REMOTEHOST"
+
+static char *sockenv_hint[] = {
+ "-" ENV_PROTO,
+ "-" ENV_SOCKTYPE,
+ "-" ENV_LOCALIP,
+ "-" ENV_LOCALPORT,
+ "-" ENV_LOCALHOST,
+ "-" ENV_REMOTEIP,
+ "-" ENV_REMOTEPORT,
+ "-" ENV_REMOTEHOST,
+ NULL
+};
-static char *
-find_env (const char *name, int val)
+#define DEBUG_ENVIRON(l) \
+ do \
+ if (debug_level >= (l)) \
+ { \
+ 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"); \
+ } \
+ while (0)
+
+static void
+add_env (const char *name, const char *value)
{
- int nlen = strcspn (name, "+=");
- int i;
+ size_t i;
+ size_t namelen = strlen (name);
+ char *p;
for (i = 0; environ[i]; i++)
{
- size_t elen = strcspn (environ[i], "=");
- if (elen == nlen && memcmp (name, environ[i], nlen) == 0)
- return val ? environ[i] + elen + 1 : environ[i];
+ if (!strncmp (environ[i], name, namelen) && environ[i][namelen] == '=')
+ break;
+ }
+
+ if (environ[i] == NULL)
+ {
+ if (envsize == 0)
+ {
+ char **new_env;
+
+ envsize = i + 4;
+ new_env = xcalloc (envsize, sizeof new_env[0]);
+ for (i = 0; new_env[i] = environ[i]; i++)
+ ;
+ environ = new_env;
+ }
+ else if (i == envsize)
+ {
+ envsize += 4;
+ environ = xrealloc (environ,
+ envsize * sizeof environ[0]);
+ }
+ environ[i+1] = NULL;
+ }
+
+ if (!value)
+ value = "";
+ p = xmalloc (namelen + 1 + strlen (value) + 1);
+ strcpy (p, name);
+ p[namelen] = '=';
+ strcpy (p + namelen + 1, value);
+ environ[i] = p;
+}
+
+static char *
+find_env (const char *name, int val)
+{
+ if (environ)
+ {
+ int nlen = strcspn (name, "+=");
+ int i;
+
+ for (i = 0; environ[i]; i++)
+ {
+ size_t elen = strcspn (environ[i], "=");
+ if (elen == nlen && memcmp (name, environ[i], nlen) == 0)
+ return val ? environ[i] + elen + 1 : environ[i];
+ }
}
return NULL;
}
@@ -580,20 +664,20 @@ env_concat (const char *name, size_t namelen, const char *a, const char *b)
return res;
}
-static char **
-env_setup (char **env)
+static void
+environ_setup (char **hint)
{
char **old_env = environ;
char **new_env;
- int count, i, n;
+ size_t count, i, n;
- if (!env)
- return old_env;
+ if (!hint)
+ return;
- if (strcmp (env[0], "-") == 0)
+ if (strcmp (hint[0], "-") == 0)
{
old_env = NULL;
- env++;
+ hint++;
}
/* Count new environment size */
@@ -602,10 +686,10 @@ env_setup (char **env)
for (i = 0; old_env[i]; i++)
count++;
- for (i = 0; env[i]; i++)
+ for (i = 0; hint[i]; i++)
count++;
- /* Allocate the new environment. */
+ /* Allocate new environment. */
new_env = xcalloc (count + 1, sizeof new_env[0]);
/* Populate the environment. */
@@ -614,41 +698,122 @@ env_setup (char **env)
if (old_env)
for (i = 0; old_env[i]; i++)
{
- if (!locate_unset (env, old_env[i]))
+ if (!locate_unset (hint, old_env[i]))
new_env[n++] = old_env[i];
}
- for (i = 0; env[i]; i++)
+ for (i = 0; hint[i]; i++)
{
char *p;
- if (env[i][0] == '-')
+ if (hint[i][0] == '-')
{
/* Skip unset directives. */
continue;
}
- if ((p = strchr (env[i], '=')))
+ if ((p = strchr (hint[i], '=')))
{
- if (p == env[i])
+ if (p == hint[i])
continue; /* Ignore erroneous entry */
if (p[-1] == '+')
- new_env[n++] = env_concat (env[i], p - env[i] - 1,
- find_env(env[i], 1), p + 1);
+ new_env[n++] = env_concat (hint[i], p - hint[i] - 1,
+ find_env(hint[i], 1), p + 1);
else if (p[1] == '+')
- new_env[n++] = env_concat (env[i], p - env[i],
- p + 2, find_env(env[i], 1));
+ new_env[n++] = env_concat (hint[i], p - hint[i],
+ p + 2, find_env(hint[i], 1));
else
- new_env[n++] = env[i];
+ new_env[n++] = hint[i];
}
else
{
- p = find_env (env[i], 0);
+ p = find_env (hint[i], 0);
if (p)
new_env[n++] = p;
}
}
new_env[n] = NULL;
- return new_env;
+
+ if (envsize)
+ free (environ);
+
+ environ = new_env;
+ envsize = count + 1;
+}
+
+/* Pass socket information in environment variables. */
+void
+prog_sockenv (struct prog *prog)
+{
+ char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+ char *p;
+ struct hostent *host;
+ union pies_sockaddr_storage sa_server;
+ socklen_t len = sizeof (sa_server);
+ union pies_sockaddr_storage *sa_client = &prog->v.p.sa_storage;
+ socklen_t cltlen = prog->v.p.sa_len;
+ const char *proto = NULL;
+
+ if (!(prog->v.p.comp->flags & CF_SOCKENV))
+ return;
+
+ if (socket_type_to_str (prog->v.p.comp->socket_type, &proto))
+ proto = umaxtostr (prog->v.p.comp->socket_type, buf);
+ add_env (ENV_SOCKTYPE, proto);
+
+ if (prog->v.p.comp->socket_url)
+ proto = prog->v.p.comp->socket_url->proto_s;
+ else if (prog->v.p.listener)
+ proto = prog->v.p.listener->v.p.comp->socket_url->proto_s;
+ else if (ISCF_TCPMUX (prog->v.p.comp->flags))
+ proto = "TCP";
+
+ add_env (ENV_PROTO, proto);
+
+ if (getsockname (prog->v.p.socket,
+ (struct sockaddr *) &sa_server, &len) < 0)
+ logmsg (LOG_WARNING, "getsockname(): %s", strerror (errno));
+ else if (sa_server.s.sa_family == AF_INET)
+ {
+ p = inet_ntoa (sa_server.s_in.sin_addr);
+ if (p)
+ add_env (ENV_LOCALIP, p);
+
+ p = umaxtostr (ntohs (sa_server.s_in.sin_port), buf);
+ add_env (ENV_LOCALPORT, p);
+
+ if (prog->v.p.comp->flags & CF_RESOLVE)
+ {
+ if ((host = gethostbyaddr ((char *) &sa_server.s_in.sin_addr,
+ sizeof (sa_server.s_in.sin_addr),
+ AF_INET)) == NULL)
+ logmsg (LOG_WARNING, "gethostbyaddr: %s", strerror (errno));
+ else
+ add_env (ENV_LOCALHOST, host->h_name);
+ }
+ }
+
+ if (cltlen > 0 && sa_client->s.sa_family == AF_INET)
+ {
+ p = inet_ntoa (sa_client->s_in.sin_addr);
+ if (p)
+ add_env (ENV_REMOTEIP, p);
+
+ p = umaxtostr (ntohs (sa_client->s_in.sin_port), buf);
+ add_env (ENV_REMOTEPORT, p);
+
+ if (prog->v.p.comp->flags & CF_RESOLVE)
+ {
+ if ((host = gethostbyaddr ((char *) &sa_client->s_in.sin_addr,
+ sizeof (sa_client->s_in.sin_addr),
+ AF_INET)) == NULL)
+ logmsg (LOG_WARNING, "gethostbyaddr: %s",
+ strerror (errno));
+ else
+ add_env (ENV_REMOTEHOST, host->h_name);
+ }
+ }
+ /* FIXME: $REMOTEINFO ? */
+ DEBUG_ENVIRON (4);
}
static int
@@ -744,15 +909,10 @@ prog_start_prologue (struct prog *prog)
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");
- }
+ environ_setup (prog->v.p.comp->env ?
+ prog->v.p.comp->env :
+ ((prog->v.p.comp->flags & CF_SOCKENV) ? sockenv_hint : NULL));
+ DEBUG_ENVIRON (4);
pies_priv_setup (&prog->v.p.comp->privs);
if (prog->v.p.comp->umask)
@@ -796,11 +956,15 @@ prog_execute (struct prog *prog)
}
void
-progman_run_comp (struct component *comp, int fd)
+progman_run_comp (struct component *comp, int fd,
+ union pies_sockaddr_storage *sa, socklen_t salen)
{
struct prog *prog = register_prog0 (comp, -1);
prog->v.p.socket = fd;
+ prog->v.p.sa_storage = *sa;
+ prog->v.p.sa_len = salen;
prog_start_prologue (prog);
+ prog_sockenv (prog);
prog_execute (prog);
}
@@ -899,6 +1063,8 @@ prog_start (struct prog *prog)
case pies_comp_accept:
case pies_comp_inetd:
+ prog_sockenv (prog);
+
dup2 (prog->v.p.socket, 0);
dup2 (prog->v.p.socket, 1);
close (prog->v.p.socket);
@@ -908,8 +1074,11 @@ prog_start (struct prog *prog)
if (redir[RETR_ERR] == -1)
{
- close (2);
- open ("/dev/null", O_WRONLY);
+ if (!DIAG_OUTPUT (DIAG_TO_STDERR))
+ {
+ close (2);
+ open ("/dev/null", O_WRONLY);
+ }
}
else if (redir[RETR_ERR] != 1)
{
@@ -954,8 +1123,8 @@ prog_start (struct prog *prog)
}
}
-static int
-check_acl (pies_acl_t acl, struct sockaddr *s, int salen)
+int
+check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen)
{
struct acl_input input;
int rc;
@@ -985,11 +1154,7 @@ _prog_accept (struct prog *p)
{
int fd;
struct prog *pinst;
- union
- {
- struct sockaddr s_in;
- struct sockaddr s_un;
- } addr;
+ union pies_sockaddr_storage addr;
socklen_t addrlen = sizeof addr;
fd = accept (p->v.p.socket, (struct sockaddr*) &addr, &addrlen);
@@ -1035,6 +1200,8 @@ _prog_accept (struct prog *p)
pinst = register_prog0 (p->v.p.comp, -1);
pinst->v.p.socket = fd;
pinst->v.p.listener = p;
+ pinst->v.p.sa_storage = addr;
+ pinst->v.p.sa_len = addrlen;
prog_start (pinst);
close (fd);
pinst->v.p.socket = -1;
@@ -1869,7 +2036,6 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
else
setenv ("PIES_STATUS", umaxtostr (STATUS_CODE (retcode), buf), 1);
- /* FIXME: see above */
close_fds (NULL);
argv[0] = "/bin/sh";
diff --git a/src/socket.c b/src/socket.c
index 6c56817..ca4d699 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -16,20 +16,6 @@
#include "pies.h"
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <netinet/in.h>
-#include <sys/un.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <unistd.h>
-#include <pwd.h>
-#include <grp.h>
-
static void
switch_eids (uid_t *puid, gid_t *pgid, mode_t *pumask)
{

Return to:

Send suggestions and report system problems to the System administrator.