diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-28 12:09:15 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2009-11-28 13:15:51 +0200 |
commit | 36a53f1875a097fa16bceaf674dc627d916651df (patch) | |
tree | ee33a5cf08231f11a3b31e0f16652229d5add561 | |
parent | 69bc6e88c7babf356efbacbdc2230de407c27590 (diff) | |
download | pies-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.c | 27 | ||||
-rw-r--r-- | src/pies.c | 63 | ||||
-rw-r--r-- | src/pies.h | 30 | ||||
-rw-r--r-- | src/progman.c | 264 | ||||
-rw-r--r-- | src/socket.c | 14 |
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); } @@ -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) @@ -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) { |