summaryrefslogtreecommitdiff
path: root/libmailutils/server/acl.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-03-30 00:49:43 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-03-30 15:51:47 +0300
commitadca074d616ac562095a92e01f2b181e6d3593c8 (patch)
treef4c11a1c11fcb137cfada7643e6f284465a75c16 /libmailutils/server/acl.c
parent827cb66a4c639139c3f11c7af26aa5149f25a7e0 (diff)
downloadmailutils-adca074d616ac562095a92e01f2b181e6d3593c8.tar.gz
mailutils-adca074d616ac562095a92e01f2b181e6d3593c8.tar.bz2
Implement IPv6 support.
* am/ipv6.m4: New file. * examples/sa.c: New file. * include/mailutils/cidr.h: New file. * include/mailutils/sockaddr.h: New file. * libmailutils/cidr/Makefile.am: New file. * libmailutils/cidr/fromsa.c: New file. * libmailutils/cidr/fromstr.c: New file. * libmailutils/cidr/match.c: New file. * libmailutils/cidr/tosa.c: New file. * libmailutils/cidr/tostr.c: New file. * libmailutils/sockaddr/Makefile.am: New file. * libmailutils/sockaddr/copy.c: New file. * libmailutils/sockaddr/create.c: New file. * libmailutils/sockaddr/free.c: New file. * libmailutils/sockaddr/fromnode.c: New file. * libmailutils/sockaddr/insert.c: New file. * libmailutils/sockaddr/ipaddr.c: New file. * libmailutils/sockaddr/str.c: New file. * libmailutils/sockaddr/unlink.c: New file. * libmailutils/sockaddr/url.c: New file. * libmailutils/tests/cidr.c: New file. * configure.ac: Call MU_ENABLE_IPV6. Build libmailutils/sockaddr and libmailutils/cidr. * examples/.gitignore: Add mblconv and sa * examples/Makefile.am: (noinst_PROGRAMS): Add sa. * examples/aclck.c: Use new ACL API. * examples/echosrv.c: Use new mserv API. * include/mailutils/Makefile.am (pkginclude_HEADERS): Add cidr.h and sockaddr.h * include/mailutils/acl.h (mu_acl_append, mu_acl_prepend) (mu_acl_insert): Change signatures. * include/mailutils/debug.h (mu_sockaddr_to_str): Remove proto. * include/mailutils/mailutils.h: Include cidr.h and sockaddr.h * include/mailutils/server.h (mu_ip_server_create): Change signature. (mu_ip_server_get_sockaddr): Likewise. (mu_m_server_set_default_address) (mu_m_server_get_default_address): Remove. * include/mailutils/stream.h (mu_tcp_stream_create_from_sa): New proto. * include/mailutils/types.hin (mu_cidr, mu_sockaddr): New structs. * include/mailutils/url.h (MU_URL_IPV6): New flag. (MU_URL_PARSE_DSLASH_OPTIONAL): New parse flag. * libmailutils/Makefile.am: Descend into cidr and sockaddr. Link in libcidr and libsockaddr. * libmailutils/diag/debug.c (mu_debug_log_begin): Flush mu_strerr. * libmailutils/diag/errors (MU_ERR_NONAME) (MU_ERR_BADFLAGS,MU_ERR_SOCKTYPE) (MU_ERR_FAMILY,MU_ERR_SERVICE): New errors. * libmailutils/server/acl.c: Rewrite API using mu_cidr. * libmailutils/server/ipsrv.c: Rewrite AI using mu_sockaddr. * libmailutils/server/msrv.c: Likewise. * libmailutils/stream/tcp.c: Likewise. * libmailutils/tests/.gitignore: Add cidr. * libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add cidr. * libmailutils/tests/url-parse.c: Support command line options to tune the parsing. * libmailutils/tests/url.at: Pass options to url-parse. * libmailutils/url/create.c (getkn): Return meaningful error code. (_mu_url_ctx_parse_host): Accept IPv6 addresses. Set the MU_URL_IPV6 flag if one is given. (_mu_url_ctx_parse): Unless MU_URL_PARSE_DSLASH_OPTIONAL flag is given, request :// after scheme part. (mu_url_create): Add MU_URL_PARSE_DSLASH_OPTIONAL flag. * libmu_cfg/acl.c: Use new ACL API. * mu/acl.c: Likewise. * libproto/mailer/smtp.c (smtp_open): Use mu_tcp_stream_create_from_sa * libproto/pop/mbox.c (pop_open): Likewise. * mu/imap.c (com_connect): Likewise. * mu/pop.c (com_connect): Likewise. * testsuite/smtpsend.c (main): Likewise.
Diffstat (limited to 'libmailutils/server/acl.c')
-rw-r--r--libmailutils/server/acl.c366
1 files changed, 90 insertions, 276 deletions
diff --git a/libmailutils/server/acl.c b/libmailutils/server/acl.c
index 0b7a507e0..ba1a4b86b 100644
--- a/libmailutils/server/acl.c
+++ b/libmailutils/server/acl.c
@@ -40,14 +40,20 @@
#include <mailutils/kwd.h>
#include <mailutils/io.h>
#include <mailutils/util.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cidr.h>
+#include <mailutils/stream.h>
+#include <mailutils/stdstream.h>
+
+#ifndef MU_INADDR_BYTES
+#define MU_INADDR_BYTES 16
+#endif
struct _mu_acl_entry
{
mu_acl_action_t action;
void *arg;
- unsigned netmask;
- int salen;
- struct sockaddr sa[1];
+ struct mu_cidr cidr;
};
struct _mu_acl
@@ -64,52 +70,19 @@ _destroy_acl_entry (void *item)
/* FIXME: free arg? */
}
-static size_t
-mu_acl_entry_size (int salen)
-{
- return sizeof (struct _mu_acl_entry) + salen - sizeof (struct sockaddr);
-}
-
-static int
-prepare_sa (struct sockaddr *sa)
-{
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
- s_in->sin_addr.s_addr = ntohl (s_in->sin_addr.s_addr);
- break;
- }
-
- case AF_UNIX:
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
int
mu_acl_entry_create (struct _mu_acl_entry **pent,
mu_acl_action_t action, void *data,
- struct sockaddr *sa, int salen, unsigned long netmask)
+ struct mu_cidr *cidr)
{
- struct _mu_acl_entry *p = malloc (mu_acl_entry_size (salen));
+ struct _mu_acl_entry *p = malloc (sizeof (*p));
if (!p)
return EINVAL;
p->action = action;
p->arg = data;
- p->netmask = ntohl (netmask);
- p->salen = salen;
- memcpy (p->sa, sa, salen);
- if (prepare_sa (p->sa))
- {
- free (p);
- return EINVAL;
- }
+ memcpy (&p->cidr, cidr, sizeof (p->cidr));
+
*pent = p;
return 0;
}
@@ -165,15 +138,14 @@ mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr)
int
mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
- void *data, struct sockaddr *sa, int salen,
- unsigned long netmask)
+ void *data, struct mu_cidr *cidr)
{
int rc;
struct _mu_acl_entry *ent;
if (!acl)
return EINVAL;
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (rc)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -193,14 +165,14 @@ mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
int
mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
- struct sockaddr *sa, int salen, unsigned long netmask)
+ struct mu_cidr *cidr)
{
int rc;
struct _mu_acl_entry *ent;
if (!acl)
return EINVAL;
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (rc)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -219,8 +191,7 @@ mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
int
mu_acl_insert (mu_acl_t acl, size_t pos, int before,
- mu_acl_action_t act, void *data,
- struct sockaddr *sa, int salen, unsigned long netmask)
+ mu_acl_action_t act, void *data, struct mu_cidr *cidr)
{
int rc;
void *ptr;
@@ -236,7 +207,7 @@ mu_acl_insert (mu_acl_t acl, size_t pos, int before,
("No such entry %lu", (unsigned long) pos));
return rc;
}
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (!ent)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -279,124 +250,19 @@ mu_acl_string_to_action (const char *str, mu_acl_action_t *pres)
return rc;
}
-#define MU_S_UN_NAME(sa, salen) \
- ((salen < mu_offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path)
-
-static void
-debug_sockaddr (struct sockaddr *sa, int salen)
-{
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
- s_in.sin_addr.s_addr = htonl (s_in.sin_addr.s_addr);
- mu_debug_log_cont ("{AF_INET %s:%d}",
- inet_ntoa (s_in.sin_addr), ntohs (s_in.sin_port));
- break;
- }
-
- case AF_UNIX:
- {
- struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
- if (MU_S_UN_NAME(s_un, salen)[0] == 0)
- mu_debug_log_cont ("{AF_UNIX}");
- else
- mu_debug_log_cont ("{AF_UNIX %s}", s_un->sun_path);
- break;
- }
-
- default:
- mu_debug_log_cont ("{Unsupported family: %d}", sa->sa_family);
- }
-}
-
-size_t
-mu_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;
- }
-}
-
-void
-mu_sockaddr_to_str (const struct sockaddr *sa, int salen,
- char *bufptr, size_t buflen,
- size_t *plen)
+struct run_closure
{
- char *nbuf;
- size_t len = 0;
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
- len += mu_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr));
- len += mu_stpcpy (&bufptr, &buflen, ":");
- if (mu_asprintf (&nbuf, "%hu", ntohs (s_in.sin_port)) == 0)
- {
- len += mu_stpcpy (&bufptr, &buflen, nbuf);
- free (nbuf);
- }
- break;
- }
-
- case AF_UNIX:
- {
- struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
- if (MU_S_UN_NAME(s_un, salen)[0] == 0)
- len += mu_stpcpy (&bufptr, &buflen, "anonymous socket");
- else
- {
- len += mu_stpcpy (&bufptr, &buflen, "socket ");
- len += mu_stpcpy (&bufptr, &buflen, s_un->sun_path);
- }
- break;
- }
-
- default:
- len += mu_stpcpy (&bufptr, &buflen, "{Unsupported family");
- if (mu_asprintf (&nbuf, ": %d", sa->sa_family) == 0)
- {
- len += mu_stpcpy (&bufptr, &buflen, nbuf);
- free (nbuf);
- }
- len += mu_stpcpy (&bufptr, &buflen, "}");
- }
- if (plen)
- *plen = len + 1;
-}
+ unsigned idx;
+ struct mu_cidr addr;
-char *
-mu_sockaddr_to_astr (const struct sockaddr *sa, int salen)
-{
- size_t size;
- char *p;
-
- mu_sockaddr_to_str (sa, salen, NULL, 0, &size);
- p = malloc (size);
- if (p)
- mu_sockaddr_to_str (sa, salen, p, size, NULL);
- return p;
-}
+ char ipstr[40];
+ char *addrstr;
+ char *numbuf;
+ mu_acl_result_t *result;
+};
int
-_acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
+_acl_match (struct _mu_acl_entry *ent, struct run_closure *rp)
{
#define RESMATCH(word) \
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) \
@@ -404,76 +270,26 @@ _acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
{
- struct in_addr a;
-
- mu_debug_log_begin ("Does ");
- debug_sockaddr (sa, salen);
- mu_debug_log_cont (" match ");
- debug_sockaddr (ent->sa, salen);
- a.s_addr = ent->netmask;
- a.s_addr = htonl (a.s_addr);
- mu_debug_log_cont (" netmask %s? ", inet_ntoa (a));
+ char *s;
+
+ if (ent->cidr.len == 0)
+ s = strdup ("any");
+ mu_cidr_format (&ent->cidr, 0, &s);
+ if (!rp->addrstr)
+ mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
+ mu_debug_log_begin ("Does %s match %s? ", s, rp->addrstr);
+ free (s);
}
- if (ent->sa->sa_family != sa->sa_family)
+ if (ent->cidr.len > 0 && mu_cidr_match (&ent->cidr, &rp->addr))
{
RESMATCH ("no");
return 1;
}
-
- switch (ent->sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in *sin_ent = (struct sockaddr_in *)ent->sa;
- struct sockaddr_in *sin_item = (struct sockaddr_in *)sa;
-
- if (sin_ent->sin_addr.s_addr !=
- (sin_item->sin_addr.s_addr & ent->netmask))
- {
- RESMATCH ("no (address differs)");
- return 1;
- }
-
- if (sin_ent->sin_port && sin_item->sin_port
- && sin_ent->sin_port != sin_item->sin_port)
- {
- RESMATCH ("no (port differs)");
- return 1;
- }
- break;
- }
-
- case AF_UNIX:
- {
- struct sockaddr_un *sun_ent = (struct sockaddr_un *)ent->sa;
- struct sockaddr_un *sun_item = (struct sockaddr_un *)sa;
-
- if (MU_S_UN_NAME (sun_ent, ent->salen)[0]
- && MU_S_UN_NAME (sun_item, salen)[0]
- && strcmp (sun_ent->sun_path, sun_item->sun_path))
- {
- RESMATCH ("no");
- return 1;
- }
- break;
- }
- }
-
RESMATCH ("yes");
return 0;
}
-struct run_closure
-{
- unsigned idx;
- struct sockaddr *sa;
- char *numbuf;
- char *portbuf;
- int salen;
- mu_acl_result_t *result;
-};
-
#define SEQ(s, n, l) \
(((l) == (sizeof(s) - 1)) && memcmp (s, n, l) == 0)
@@ -489,40 +305,24 @@ acl_getvar (const char *name, size_t nlen, void *data)
return rp->numbuf;
}
- switch (rp->sa->sa_family)
+ if (SEQ ("address", name, nlen))
{
- case AF_INET:
- {
- struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa;
-
- if (SEQ ("address", name, nlen))
- {
- struct in_addr addr = s_in->sin_addr;
- addr.s_addr = htonl (addr.s_addr);
- return inet_ntoa (addr);
- }
+ if (!rp->addrstr)
+ mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
+ return rp->addrstr;
+ }
- if (SEQ ("port", name, nlen))
- {
- if (!rp->portbuf &&
- mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port)))
- return NULL;
- return rp->portbuf;
- }
- break;
-
- case AF_UNIX:
- if (SEQ ("address", name, nlen))
- {
- struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa;
- if (rp->salen == sizeof (s_un->sun_family))
- return NULL;
- else
- return s_un->sun_path;
- }
- }
- break;
+#if 0
+ /* FIXME?: */
+ if (SEQ ("port", name, nlen))
+ {
+ if (!rp->portbuf &&
+ mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port)))
+ return NULL;
+ return rp->portbuf;
}
+#endif
+
return NULL;
}
@@ -535,12 +335,18 @@ expand_arg (const char *cmdline, struct run_closure *rp, char **s)
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_TRACE, ("Expanding \"%s\"", cmdline));
env[0] = "family";
- switch (rp->sa->sa_family)
+ switch (rp->addr.family)
{
case AF_INET:
env[1] = "AF_INET";
break;
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ env[1] = "AF_INET6";
+ break;
+#endif
+
case AF_UNIX:
env[1] = "AF_UNIX";
break;
@@ -654,7 +460,7 @@ _run_entry (void *item, void *data)
mu_debug_log_begin ("%d:%s: ", rp->idx, s);
}
- if (_acl_match (ent, rp->sa, rp->salen) == 0)
+ if (_acl_match (ent, rp) == 0)
{
switch (ent->action)
{
@@ -678,8 +484,10 @@ _run_entry (void *item, void *data)
}
else
{
- debug_sockaddr (rp->sa, rp->salen);
- mu_debug_log_nl ();
+ if (!rp->addrstr)
+ mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY,
+ &rp->addrstr);
+ mu_diag_output (MU_DIAG_INFO, "%s", rp->addrstr);
}
}
break;
@@ -712,7 +520,7 @@ _run_entry (void *item, void *data)
}
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
- mu_debug_log_nl ();
+ mu_stream_flush (mu_strerr);
return status;
}
@@ -721,40 +529,39 @@ int
mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
mu_acl_result_t *pres)
{
+ int rc;
struct run_closure r;
if (!acl)
return EINVAL;
- r.sa = malloc (salen);
- if (!r.sa)
- return ENOMEM;
- memcpy (r.sa, sa, salen);
- if (prepare_sa (r.sa))
+ memset (&r, 0, sizeof (r));
+ if (sa->sa_family == AF_UNIX)
{
- free (r.sa);
- return EINVAL;
+ *pres = mu_acl_result_accept;
+ return 0;
}
- r.salen = salen;
+ rc = mu_cidr_from_sockaddr (&r.addr, sa);
+ if (rc)
+ return rc;
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
{
- mu_debug_log_begin ("Checking sockaddr ");
- debug_sockaddr (r.sa, r.salen);
+ mu_cidr_format (&r.addr, MU_CIDR_FMT_ADDRONLY, &r.addrstr);
+ mu_debug_log_begin ("Checking sockaddr %s", r.addrstr);
mu_debug_log_nl ();
}
r.idx = 0;
r.result = pres;
*r.result = mu_acl_result_undefined;
- r.numbuf = r.portbuf = NULL;
+ r.numbuf = NULL;
mu_list_do (acl->aclist, _run_entry, &r);
free (r.numbuf);
- free (r.portbuf);
- free (r.sa);
+ free (r.addrstr);
return 0;
}
-
+
int
mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp,
mu_acl_result_t *pres)
@@ -780,10 +587,17 @@ mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, mu_acl_result_t *pres)
int
mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres)
{
- struct sockaddr_in cs;
- socklen_t len = sizeof cs;
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 in6;
+#endif
+ } addr;
+ socklen_t len = sizeof addr;
- if (getpeername (fd, (struct sockaddr *) &cs, &len) < 0)
+ if (getpeername (fd, &addr.sa, &len) < 0)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
("Cannot obtain IP address of client: %s",
@@ -791,6 +605,6 @@ mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres)
return MU_ERR_FAILURE;
}
- return mu_acl_check_sockaddr (acl, (struct sockaddr *) &cs, len, pres);
+ return mu_acl_check_sockaddr (acl, &addr.sa, len, pres);
}

Return to:

Send suggestions and report system problems to the System administrator.