aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am8
-rw-r--r--src/acl.c627
-rw-r--r--src/acl.h43
-rw-r--r--src/addrfmt.c133
-rw-r--r--src/diag.c131
-rw-r--r--src/meta.c127
-rw-r--r--src/pies.c68
-rw-r--r--src/pp-setup116
-rw-r--r--src/progman.c4
-rw-r--r--src/url.c212
-rw-r--r--src/userprivs.c279
11 files changed, 1722 insertions, 26 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c0c3b8a..970a8b3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -37,20 +37,16 @@ noinst_HEADERS = \
meta1lex.h\
pies.h
-EXTRA_DIST = pies.rcin
-noinst_DATA = pies.rc
-DISTCLEANFILES = pies.rc
-.rcin.rc:
- $(AM_V_GEN)sed 's|SBINDIR|$(sbindir)|g' $< > $@
-
meta1lex.c: meta1gram.h
incdir=$(pkgdatadir)/$(VERSION)/include
inc_DATA = pp-setup
+EXTRA_DIST = pp-setup
INCLUDES = \
-I$(top_srcdir)/lib\
-I$(top_srcdir)/gnu\
+ -I$(top_builddir)/gnu\
-I$(top_srcdir)/grecs/src
LDADD = \
diff --git a/src/acl.c b/src/acl.c
new file mode 100644
index 0000000..8561967
--- /dev/null
+++ b/src/acl.c
@@ -0,0 +1,627 @@
+/* This file is part of Pies
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ 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.
+
+ 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 Pies. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "pies.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <hash.h>
+
+struct pies_sockaddr
+{
+ unsigned netmask;
+ int salen;
+ struct sockaddr sa;
+};
+
+struct acl_entry
+{
+ grecs_locus_t locus;
+ int allow;
+ int authenticated;
+ pies_acl_t acl;
+ gl_list_t groups;
+ gl_list_t sockaddrs;
+};
+
+struct pies_acl
+{
+ char *name;
+ grecs_locus_t locus;
+ gl_list_t list;
+};
+
+
+
+/* ACL creation */
+
+pies_acl_t
+pies_acl_create (const char *name, grecs_locus_t *locus)
+{
+ pies_acl_t acl = xmalloc (sizeof (acl[0]));
+ acl->name = xstrdup (name);
+ acl->locus = *locus;
+ acl->list = gl_list_create_empty(&gl_linked_list_implementation,
+ NULL,
+ NULL,
+ NULL,
+ false);
+ return acl;
+}
+
+static struct pies_sockaddr *
+create_acl_sockaddr (int family, int len)
+{
+ struct pies_sockaddr *p = xzalloc (sizeof (*p));
+ p->salen = len;
+ p->sa.sa_family = family;
+ return p;
+}
+
+/* allow|deny [all|authenticated|group <grp: list>]
+ [acl <name: string>] [from <addr: list>] */
+
+static int
+_parse_token (struct acl_entry *entry, const grecs_value_t *value)
+{
+ if (strcmp (value->v.string, "all") == 0
+ || strcmp (value->v.string, "any") == 0)
+ /* FIXME: Nothing? */ ;
+ else if (strcmp (value->v.string, "auth") == 0
+ || strcmp (value->v.string, "authenticated") == 0)
+ entry->authenticated = 1;
+ else
+ return 1;
+ return 0;
+}
+
+static int
+_parse_sockaddr (struct acl_entry *entry, const grecs_value_t *value)
+{
+ struct pies_sockaddr *sptr;
+ const char *string;
+
+ if (assert_grecs_value_type (&entry->locus, value, GRECS_TYPE_STRING))
+ return 1;
+
+ string = value->v.string;
+
+ if (string[0] == '/')
+ {
+ size_t len;
+ struct sockaddr_un *s_un;
+
+ len = strlen (string);
+ if (len >= sizeof (s_un->sun_path))
+ {
+ grecs_error (&entry->locus, 0,
+ _("socket name too long: `%s'"), string);
+ return 1;
+ }
+ sptr = create_acl_sockaddr (AF_UNIX, sizeof (s_un));
+ s_un = (struct sockaddr_un *) &sptr->sa;
+ memcpy (s_un->sun_path, string, len);
+ s_un->sun_path[len] = 0;
+ }
+ else
+ {
+ struct in_addr addr;
+ struct sockaddr_in *s_in;
+ char *p = strchr (string, '/');
+
+ if (p)
+ *p = 0;
+
+ if (inet_aton (string, &addr) == 0)
+ {
+ struct hostent *hp = gethostbyname (string);
+ if (!hp)
+ {
+ grecs_error (&entry->locus, 0,
+ _("cannot resolve host name: `%s'"), string);
+ if (p)
+ *p = '/';
+ return 1;
+ }
+ memcpy (&addr.s_addr, hp->h_addr, sizeof (addr.s_addr));
+ }
+ addr.s_addr = ntohl (addr.s_addr);
+
+ sptr = create_acl_sockaddr (AF_INET, sizeof (s_in));
+ s_in = (struct sockaddr_in *) &sptr->sa;
+ s_in->sin_addr = addr;
+
+ if (p)
+ {
+ *p++ = '/';
+ char *q;
+ unsigned netlen;
+
+ netlen = strtoul (p, &q, 10);
+ if (*q == 0)
+ {
+ if (netlen == 0)
+ sptr->netmask = 0;
+ else
+ {
+ sptr->netmask = 0xfffffffful >> (32 - netlen);
+ sptr->netmask <<= (32 - netlen);
+ sptr->netmask = htonl (sptr->netmask);
+ }
+ }
+ else if (*q == '.')
+ {
+ struct in_addr addr;
+
+ if (inet_aton (p, &addr) == 0)
+ {
+ grecs_error (&entry->locus, 0,
+ _("invalid netmask: `%s'"), p);
+ return 1;
+ }
+ sptr->netmask = addr.s_addr;
+ }
+ else
+ {
+ grecs_error (&entry->locus, 0, _("invalid netmask: `%s'"), p);
+ return 1;
+ }
+ }
+ else
+ sptr->netmask = 0xfffffffful;
+ }
+ gl_list_add_last (entry->sockaddrs, sptr);
+ return 0;
+}
+
+static int
+_parse_from (struct acl_entry *entry, size_t argc, const grecs_value_t *argv)
+{
+ if (argc == 0)
+ return 0;
+ else if (argv->type == GRECS_TYPE_LIST)
+ {
+ grecs_error (&entry->locus, 0, _("expected `from', but found list"));
+ return 1;
+ }
+ else if (strcmp (argv->v.string, "from"))
+ {
+ grecs_error (&entry->locus, 0, _("expected `from', but found `%s'"),
+ argv->v.string);
+ return 1;
+ }
+ argc--;
+ argv++;
+
+ if (argc == 0)
+ {
+ grecs_error (&entry->locus, 0,
+ _("unexpected end of statement after `from'"));
+ return 1;
+ }
+
+ entry->sockaddrs = gl_list_create_empty(&gl_linked_list_implementation,
+ NULL,
+ NULL,
+ NULL,
+ false);
+ if (argv->type == GRECS_TYPE_STRING)
+ {
+ if (_parse_sockaddr (entry, argv))
+ return 1;
+ }
+ else
+ {
+ gl_list_iterator_t itr = gl_list_iterator (argv->v.list);
+ const void *p;
+ int rc = 0;
+ while (gl_list_iterator_next (&itr, &p, NULL))
+ rc += _parse_sockaddr (entry, (const grecs_value_t*) p);
+ gl_list_iterator_free (&itr);
+ if (rc)
+ return rc;
+ }
+
+ if (argc - 1)
+ {
+ grecs_warning (&entry->locus, 0, _("junk after `from' list"));
+ return 1;
+ }
+ return 0;
+}
+
+static int
+_parse_sub_acl (struct acl_entry *entry, size_t argc, grecs_value_t *argv)
+{
+ if (argc == 0)
+ return 0;
+ if (strcmp (argv->v.string, "acl") == 0)
+ {
+ argc--;
+ argv++;
+ if (argc == 0)
+ {
+ grecs_error (&entry->locus, 0,
+ _("expected ACL name, but found end of statement"));
+ return 1;
+ }
+
+ if (argv->type != GRECS_TYPE_STRING)
+ {
+ grecs_error (&entry->locus, 0,
+ _("expected string, but found list"));
+ return 1;
+ }
+
+ entry->acl = pies_acl_lookup (argv->v.string);
+
+ if (!entry->acl)
+ {
+ grecs_error (&entry->locus, 0, _("ACL not defined: `%s'"),
+ argv->v.string);
+ return 1;
+ }
+ argc--;
+ argv++;
+ }
+ return _parse_from (entry, argc, argv);
+}
+
+static int
+_parse_group (struct acl_entry *entry, size_t argc, grecs_value_t * argv)
+{
+ if (strcmp (argv->v.string, "group") == 0)
+ {
+ argc--;
+ argv++;
+ if (argc == 0)
+ {
+ grecs_error (&entry->locus, 0,
+ _("expected group list, but found end of statement"));
+ return 1;
+ }
+ if (argv->type == GRECS_TYPE_STRING)
+ {
+ entry->groups = gl_list_create_empty(&gl_linked_list_implementation,
+ NULL,
+ NULL,
+ NULL,
+ false);
+ gl_list_add_last (entry->groups, (void *) argv->v.string);
+ }
+ else
+ entry->groups = argv->v.list;
+ argc--;
+ argv++;
+ }
+ return _parse_sub_acl (entry, argc, argv);
+}
+
+static int
+_parse_acl (struct acl_entry *entry, size_t argc, grecs_value_t *argv)
+{
+ if (assert_grecs_value_type (&entry->locus, argv, GRECS_TYPE_STRING))
+ return 1;
+ else if (_parse_token (entry, argv) == 0)
+ return _parse_sub_acl (entry, argc - 1, argv + 1);
+ else
+ return _parse_group (entry, argc, argv);
+}
+
+int
+parse_acl_line (grecs_locus_t *locus, int allow, pies_acl_t acl,
+ grecs_value_t *value)
+{
+ struct acl_entry *entry = xzalloc (sizeof (*entry));
+
+ entry->locus = *locus;
+ entry->allow = allow;
+
+ switch (value->type)
+ {
+ case GRECS_TYPE_STRING:
+ if (_parse_token (entry, value))
+ {
+ grecs_error (&entry->locus, 0, _("unknown word `%s'"),
+ value->v.string);
+ return 1;
+ }
+ break;
+
+ case GRECS_TYPE_ARRAY:
+ if (_parse_acl (entry, value->v.arg.c, value->v.arg.v))
+ return 1;
+ break;
+
+ case GRECS_TYPE_LIST:
+ grecs_error (locus, 0, _("unexpected list"));
+ return 1;
+ }
+ gl_list_add_last (acl->list, entry);
+ return 0;
+}
+
+int
+acl_section_parser (enum grecs_callback_command cmd,
+ grecs_locus_t *locus,
+ void *varptr,
+ grecs_value_t *value,
+ void *cb_data)
+{
+ void **pdata = cb_data;
+ pies_acl_t acl;
+
+ switch (cmd)
+ {
+ case grecs_callback_section_begin:
+ if (value->type != GRECS_TYPE_STRING)
+ grecs_error (locus, 0, _("ACL name must be a string"));
+ else if (!value->v.string)
+ grecs_error (locus, 0, _("missing ACL name"));
+ else
+ {
+ grecs_locus_t defn_loc;
+ acl = pies_acl_create (value->v.string, locus);
+ if (pies_acl_install (acl, &defn_loc))
+ {
+ grecs_error (locus, 0,
+ _("redefinition of ACL %s"),
+ value->v.string);
+ grecs_error (&defn_loc, 0,
+ _("location of the previous definition"));
+ return 1;
+ }
+ *pdata = acl;
+ }
+ break;
+
+ case grecs_callback_section_end:
+ case grecs_callback_set_value:
+ break;
+ }
+ return 0;
+}
+
+static int
+allow_cb (enum grecs_callback_command cmd,
+ grecs_locus_t *locus,
+ void *varptr,
+ grecs_value_t *value,
+ void *cb_data)
+{
+ pies_acl_t acl = varptr;
+
+ if (cmd != grecs_callback_set_value)
+ {
+ grecs_error (locus, 0, _("unexpected block statement"));
+ return 1;
+ }
+ parse_acl_line (locus, 1, acl, value);
+ return 0;
+}
+
+static int
+deny_cb (enum grecs_callback_command cmd,
+ grecs_locus_t *locus,
+ void *varptr,
+ grecs_value_t *value,
+ void *cb_data)
+{
+ pies_acl_t acl = varptr;
+ if (cmd != grecs_callback_set_value)
+ {
+ grecs_error (locus, 0, _("unexpected block statement"));
+ return 1;
+ }
+ parse_acl_line (locus, 0, acl, value);
+ return 0;
+}
+
+struct grecs_keyword acl_keywords[] = {
+ { "allow", N_("[all|authenticated|group <grp: list>] [from <addr: list>]"),
+ N_("Allow access"),
+ grecs_type_string, NULL, 0,
+ allow_cb },
+ { "deny", N_("[all|authenticated|group <grp: list>] [from <addr: list>]"),
+ N_("Deny access"),
+ grecs_type_string, NULL, 0,
+ deny_cb },
+ { NULL }
+};
+
+
+
+
+/* ACL verification */
+
+#define S_UN_NAME(sa, salen) \
+ ((salen < offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path)
+
+static int
+_check_sockaddr (struct pies_sockaddr *sptr, struct acl_input *input)
+{
+ if (sptr->sa.sa_family != input->addr->sa_family)
+ return 0;
+
+ switch (sptr->sa.sa_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *sin_clt = (struct sockaddr_in *) input->addr;
+ struct sockaddr_in *sin_item = (struct sockaddr_in *) &sptr->sa;
+
+ if (ntohl (sin_clt->sin_addr.s_addr) ==
+ (sin_item->sin_addr.s_addr & sptr->netmask))
+ return 1;
+ break;
+ }
+
+ case AF_UNIX:
+ {
+ struct sockaddr_un *sun_clt = (struct sockaddr_un *) input->addr;
+ struct sockaddr_un *sun_item = (struct sockaddr_un *) &sptr->sa;
+
+ if (S_UN_NAME (sun_clt, input->addrlen)[0]
+ && S_UN_NAME (sun_item, sptr->salen)[0]
+ && strcmp (sun_clt->sun_path, sun_item->sun_path) == 0)
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int
+match_group (const char **groups, const char *arg)
+{
+ for (; *groups; groups++)
+ if (strcmp (*groups, arg) == 0)
+ return 1;
+ return 0;
+}
+
+static int
+_acl_check (struct acl_entry *ent, struct acl_input *input)
+{
+ int result = 1;
+
+ if (ent->authenticated)
+ {
+ result = input->user != NULL;
+ if (!result)
+ return result;
+ }
+
+ if (ent->groups)
+ {
+ const void *p;
+ gl_list_iterator_t itr = gl_list_iterator (ent->groups);
+ while (result && gl_list_iterator_next (&itr, &p, NULL))
+ result = match_group (input->groups, p);
+ gl_list_iterator_free (&itr);
+ if (!result)
+ return result;
+ }
+
+ result = pies_acl_check (ent->acl, input, 1);
+ if (!result)
+ return result;
+
+ if (ent->sockaddrs)
+ {
+ const void *p;
+ gl_list_iterator_t itr = gl_list_iterator (ent->sockaddrs);
+ result = 0;
+ while (gl_list_iterator_next (&itr, &p, NULL))
+ {
+ if (_check_sockaddr ((struct pies_sockaddr *)p, input))
+ break;
+ }
+ gl_list_iterator_free (&itr);
+ }
+
+ return result;
+}
+
+static int
+_acl_check_cb (struct acl_entry *ent, struct acl_input *input, int *pres)
+{
+ int result = _acl_check (ent, input);
+ debug (10, ("%s:%d: %s", ent->locus.file, ent->locus.line,
+ /* TRANSLATIONS: `MATCHES' is the verb `match' in 2nd person.
+ E.g., in French: CONCORD AVEC */
+ result ? _("MATCHES") : _("does not match")));
+
+ if (result)
+ {
+ *pres = ent->allow;
+ return 1;
+ }
+ return 0;
+}
+
+int
+pies_acl_check (pies_acl_t acl, struct acl_input *input, int result)
+{
+ if (acl)
+ {
+ const void *p;
+ gl_list_iterator_t itr = gl_list_iterator (acl->list);
+ while (gl_list_iterator_next (&itr, &p, NULL)
+ && _acl_check_cb ((struct acl_entry *)p, input, &result))
+ ;
+ gl_list_iterator_free (&itr);
+ }
+ return result;
+}
+
+
+/* Hash table */
+
+static Hash_table *acl_table;
+
+/* Calculate the hash of a string. */
+static size_t
+acl_hasher (void const *data, unsigned n_buckets)
+{
+ const struct pies_acl *p = data;
+ return hash_string (p->name, n_buckets);
+}
+
+/* Compare two strings for equality. */
+static bool
+acl_compare (void const *data1, void const *data2)
+{
+ const struct pies_acl *p1 = data1;
+ const struct pies_acl *p2 = data2;
+ return strcasecmp (p1->name, p2->name) == 0;
+}
+
+int
+pies_acl_install (pies_acl_t acl, grecs_locus_t * locus)
+{
+ pies_acl_t ret;
+ if (!((acl_table
+ || (acl_table = hash_initialize (0, 0,
+ acl_hasher,
+ acl_compare, 0)))
+ && (ret = hash_insert (acl_table, acl))))
+ xalloc_die ();
+
+ if (ret != acl)
+ {
+ if (locus)
+ *locus = ret->locus;
+ return 1;
+ }
+ return 0;
+}
+
+pies_acl_t
+pies_acl_lookup (const char *name)
+{
+ struct pies_acl samp;
+ if (!acl_table)
+ return NULL;
+ samp.name = (char *) name;
+ return hash_lookup (acl_table, &samp);
+}
diff --git a/src/acl.h b/src/acl.h
new file mode 100644
index 0000000..8d7725e
--- /dev/null
+++ b/src/acl.h
@@ -0,0 +1,43 @@
+/* This file is part of Pies
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ 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.
+
+ 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 Pies. If not, see <http://www.gnu.org/licenses/>. */
+
+/* acl.c */
+typedef struct pies_acl *pies_acl_t;
+
+struct acl_input
+{
+ struct sockaddr *addr;
+ socklen_t addrlen;
+ const char *user;
+ const char **groups;
+};
+
+pies_acl_t pies_acl_create (const char *name, grecs_locus_t *locus);
+int pies_acl_check (pies_acl_t acl, struct acl_input *input, int result);
+int parse_acl_line (grecs_locus_t *locus, int allow, pies_acl_t acl,
+ grecs_value_t *value);
+pies_acl_t pies_acl_lookup (const char *name);
+int pies_acl_install (pies_acl_t acl, grecs_locus_t * locus);
+
+int assert_grecs_value_type (grecs_locus_t *locus,
+ const grecs_value_t *value, int type);
+
+extern struct grecs_keyword acl_keywords[];
+extern int acl_section_parser (enum grecs_callback_command cmd,
+ grecs_locus_t *locus,
+ void *varptr,
+ grecs_value_t *value,
+ void *cb_data);
diff --git a/src/addrfmt.c b/src/addrfmt.c
new file mode 100644
index 0000000..0687445
--- /dev/null
+++ b/src/addrfmt.c
@@ -0,0 +1,133 @@
+/* This file is part of Pies
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ 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.
+
+ 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 Pies. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "pies.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+int
+str2port (char *str)
+{
+ struct servent *serv;
+ char *p;
+ int port;
+
+ /* First try to read it from /etc/services */
+ serv = getservbyname (str, "tcp");
+
+ if (serv != NULL)
+ port = ntohs(serv->s_port);
+ else
+ {
+ unsigned long l;
+ /* Not in services, maybe a number? */
+ l = strtoul (str, &p, 0);
+
+ if (*p || l < 0 || l > USHRT_MAX)
+ return -1;
+
+ port = l;
+ }
+
+ return port;
+}
+
+static size_t
+_my_stpcpy (char **pbuf, size_t *psize, const char *src)
+{
+ size_t slen = strlen (src);
+ if (pbuf == NULL || *pbuf == NULL)
+ return slen;
+ else
+ {
+ char *buf = *pbuf;
+ size_t size = *psize;
+ if (size > slen)
+ size = slen;
+ memcpy (buf, src, size);
+ *psize -= size;
+ *pbuf += size;
+ if (*psize)
+ **pbuf = 0;
+ else
+ (*pbuf)[-1] = 0;
+ return size;
+ }
+}
+
+#define S_UN_NAME(sa, salen) \
+ ((salen < offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path)
+
+void
+sockaddr_to_str (const struct sockaddr *sa, int salen,
+ char *bufptr, size_t buflen,
+ size_t *plen)
+{
+ char buf[INT_BUFSIZE_BOUND (uintmax_t)]; /* FIXME: too much */
+ size_t len = 0;
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
+ len += _my_stpcpy (&bufptr, &buflen, inet_ntoa(s_in.sin_addr));
+ len += _my_stpcpy (&bufptr, &buflen, ":");
+ len += _my_stpcpy (&bufptr, &buflen,
+ umaxtostr(ntohs (s_in.sin_port), buf));
+ break;
+ }
+
+ case AF_UNIX:
+ {
+ struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
+ if (S_UN_NAME(s_un, salen)[0] == 0)
+ len += _my_stpcpy (&bufptr, &buflen, "anonymous socket");
+ else
+ {
+ len += _my_stpcpy (&bufptr, &buflen, "socket ");
+ len += _my_stpcpy (&bufptr, &buflen, s_un->sun_path);
+ }
+ break;
+ }
+
+ default:
+ len += _my_stpcpy (&bufptr, &buflen, "{Unsupported family: ");
+ len += _my_stpcpy (&bufptr, &buflen, umaxtostr (sa->sa_family, buf));
+ len += _my_stpcpy (&bufptr, &buflen, "}");
+ }
+ if (plen)
+ *plen = len + 1;
+}
+
+char *
+sockaddr_to_astr (const struct sockaddr *sa, int salen)
+{
+ size_t size;
+ char *p;
+
+ sockaddr_to_str(sa, salen, NULL, 0, &size);
+ p = xmalloc (size);
+ sockaddr_to_str(sa, salen, p, size, NULL);
+ return p;
+}
diff --git a/src/diag.c b/src/diag.c
new file mode 100644
index 0000000..8ae3911
--- /dev/null
+++ b/src/diag.c
@@ -0,0 +1,131 @@
+/* This file is part of Pies.
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ 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.
+
+ 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 Pies. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "pies.h"
+#include "xvasprintf.h"
+
+unsigned debug_level;
+int source_info_option;
+
+void
+syslog_printer (int prio, const char *fmt, va_list ap)
+{
+#if HAVE_VSYSLOG
+ vsyslog (prio, fmt, ap);
+#else
+ char buf[128];
+ vsnprintf (buf, sizeof buf, fmt, ap);
+#endif
+}
+
+void
+vlogmsg (int prio, const char *fmt, va_list ap)
+{
+ if (log_to_stderr)
+ {
+ vfprintf (stderr, fmt, ap);
+ fprintf (stderr, "\n");
+ }
+ else
+ syslog_printer (prio, fmt, ap);
+}
+
+void
+logmsg (int prio, const char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ vlogmsg (prio, fmt, ap);
+ va_end (ap);
+}
+
+void
+debug_msg (const char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ vlogmsg (LOG_DEBUG, fmt, ap);
+ va_end (ap);
+}
+
+
+static struct obstack log_stk;
+static int log_stk_init;
+
+void
+logmsg_vprintf (int prio, const char *fmt, va_list ap)
+{
+ char *str, *p;
+
+ str = xvasprintf (fmt, ap);
+
+ if (!log_stk_init)
+ {
+ obstack_init (&log_stk);
+ log_stk_init = 1;
+ }
+ for (p = str; *p; )
+ {
+ size_t len = strcspn (p, "\n");
+ if (len)
+ obstack_grow (&log_stk, p, len);
+ p += len;
+ if (*p)
+ {
+ char *msg;
+
+ obstack_1grow (&log_stk, 0);
+ msg = obstack_finish (&log_stk);
+ logmsg (prio, "%s", msg);
+ obstack_free (&log_stk, msg);
+ p++;
+ }
+ }
+ free (str);
+}
+
+void
+logmsg_printf (int prio, const char *fmt, ...)
+{
+ va_list ap;
+ va_start (ap, fmt);
+ logmsg_vprintf (prio, fmt, ap);
+ va_end (ap);
+}
+
+void
+grecs_print_diag (grecs_locus_t *locus, int err, int errcode, const char *msg)
+{
+ if (locus)
+ {
+ if (errcode)
+ logmsg (err ? LOG_ERR : LOG_WARNING, "%s:%lu: %s: %s",
+ locus->file, (unsigned long)locus->line, msg,
+ strerror (errcode));
+ else
+ logmsg (err ? LOG_ERR : LOG_WARNING, "%s:%lu: %s",
+ locus->file, (unsigned long)locus->line, msg);
+ }
+ else
+ {
+ if (errcode)
+ logmsg (err ? LOG_ERR : LOG_WARNING, "%s: %s", msg,
+ strerror (errcode));
+ else
+ logmsg (err ? LOG_ERR : LOG_WARNING, "%s", msg);
+ }
+}
+
diff --git a/src/meta.c b/src/meta.c
new file mode 100644
index 0000000..9acc3bb
--- /dev/null
+++ b/src/meta.c
@@ -0,0 +1,127 @@
+/* This file is part of Pies.
+ Copyright (C) 2008, 2009 Sergey Poznyakoff
+
+ 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.
+
+ 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 Pies. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "pies.h"
+#include <c-ctype.h>
+
+static const char *
+meta_expand (struct metadef *def, void *data)
+{
+ if (!def->value)
+ {
+ if (def->expand)
+ return def->expand (def, data);
+ def->value = "INTERNAL ERROR: NONEXPANDABLE DATA";
+ }
+ return def->value;
+}
+
+static const char *
+find_expansion_char (int c, struct metadef *def, void *data)
+{
+ for (; def->kw; def++)
+ if (def->kw[1] == 0 && def->kw[0] == c)
+ return meta_expand (def, data);
+ return NULL;
+}
+
+static const char *
+find_expansion_word (const char *kw, size_t len,
+ struct metadef *def, void *data)
+{
+ for (; def->kw; def++)
+ if (strlen (def->kw) == len && memcmp (def->kw, kw, len) == 0)
+ return meta_expand (def, data);
+ return NULL;
+}
+
+char *
+meta_expand_string (const char *string, struct metadef *def, void *data)
+{
+ const char *p, *s;
+ char *res;
+ struct obstack stk;
+
+ if (!string)
+ return NULL;
+
+ obstack_init (&stk);
+
+ for (p = string; *p;)
+ {
+ char *e;
+ size_t len = strcspn (p, "$");
+
+ obstack_grow (&stk, p, len);
+ p += len;
+ if (*p == '$')
+ {
+ switch (*++p)
+ {
+ case '$':
+ obstack_grow (&stk, p, 1);
+ p++;
+ break;
+
+ case '{':
+ e = strchr (p + 1, '}');
+ if (e && (s = find_expansion_word (p + 1, e - p - 1, def, data)))
+ {
+ obstack_grow (&stk, s, strlen (s));
+ p = e + 1;
+ }
+ else
+ {
+ obstack_grow (&stk, p - 1, 2);
+ p++;
+ }
+ break;
+
+ default:
+ if ((s = find_expansion_char (*p, def, data)) != NULL)
+ len = strlen (s);
+ else
+ {
+ s = p - 1;
+ len = 1;
+ }
+
+ obstack_grow (&stk, s, len);
+ p++;
+ }
+ }
+ else
+ obstack_grow (&stk, p, 1);
+ }
+ obstack_1grow (&stk, 0);
+ res = xstrdup (obstack_finish (&stk));
+ obstack_free (&stk, NULL);
+ return res;
+}
+
+void
+meta_free (struct metadef *def)
+{
+ for (; def->kw; def++)
+ {
+ if (def->storage)
+ {
+ free (def->storage);
+ def->value = def->storage = NULL;
+ }
+ }
+}
+
diff --git a/src/pies.c b/src/pies.c
index f36c21f..87ddad3 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -15,6 +15,8 @@
along with Pies. If not, see <http://www.gnu.org/licenses/>. */
#include "pies.h"
+#include <locale.h>
+#include <configmake.h>
#include "meta1lex.h"
char *conffile = SYSCONFDIR "/pies.conf";
@@ -106,7 +108,7 @@ _cb_action (enum grecs_callback_command cmd,
return 0;
}
-struct grecs_keyword return_code_cfg_param[] = {
+struct grecs_keyword return_code_keywords[] = {
{"action",
/* TRANSLATORS: disable and restart are keywords, do not translate them. */
N_("arg: {disable | restart}"),
@@ -718,7 +720,7 @@ _cb_limits (enum grecs_callback_command cmd,
return 0;
}
-struct grecs_keyword component_cfg_param[] = {
+struct grecs_keyword component_keywords[] = {
{"mode",
/* TRANSLATORS: The words between '{' and '}' are keywords, do not
translate them. */
@@ -868,7 +870,7 @@ struct grecs_keyword component_cfg_param[] = {
N_("<tag: exit-code-list>"),
NULL, /* FIXME: Docstring? */
grecs_type_section, NULL, 0,
- return_code_section_parser, NULL, return_code_cfg_param},
+ return_code_section_parser, NULL, return_code_keywords},
{NULL}
};
@@ -877,7 +879,7 @@ find_component_keyword (const char *ident)
{
struct grecs_keyword *kwp;
- for (kwp = component_cfg_param; kwp->ident; kwp++)
+ for (kwp = component_keywords; kwp->ident; kwp++)
if (strcmp (kwp->ident, ident) == 0)
return kwp;
return NULL;
@@ -1028,6 +1030,10 @@ component_section_parser (enum grecs_callback_command cmd,
case grecs_callback_section_end:
comp = *(struct component **) section_data;
component_finish (comp, locus);
+ break;
+
+ case grecs_callback_set_value:
+ grecs_error (locus, 0, _("expected block statement"));
}
return 0;
}
@@ -1064,13 +1070,13 @@ _cm_include_meta1 (enum grecs_callback_command cmd,
return 0;
}
-struct grecs_keyword pies_cfg_param[] = {
+struct grecs_keyword pies_keywords[] = {
/* FIXME */
{"component",
N_("<tag: string>"),
NULL, /* FIXME: Docstring */
grecs_type_section, NULL, 0,
- component_section_parser, NULL, component_cfg_param},
+ component_section_parser, NULL, component_keywords},
{"syslog",
NULL,
N_("Configure syslog logging"),
@@ -1140,7 +1146,7 @@ struct grecs_keyword pies_cfg_param[] = {
N_("<tag: exit-code-list>"),
NULL, /* FIXME: Docstring? */
grecs_type_section, &default_component, 0,
- return_code_section_parser, NULL, return_code_cfg_param},
+ return_code_section_parser, NULL, return_code_keywords},
{"acl",
N_("name: string"),
N_("Define ACL."),
@@ -1164,7 +1170,7 @@ struct grecs_keyword pies_cfg_param[] = {
void
config_init ()
{
- grecs_set_keywords (pies_cfg_param);
+ grecs_set_keywords (pies_keywords);