summaryrefslogtreecommitdiff
path: root/libmailutils/server
diff options
context:
space:
mode:
Diffstat (limited to 'libmailutils/server')
-rw-r--r--libmailutils/server/acl.c366
-rw-r--r--libmailutils/server/ipsrv.c83
-rw-r--r--libmailutils/server/msrv.c348
3 files changed, 228 insertions, 569 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);
}
diff --git a/libmailutils/server/ipsrv.c b/libmailutils/server/ipsrv.c
index a80290834..73b2e361e 100644
--- a/libmailutils/server/ipsrv.c
+++ b/libmailutils/server/ipsrv.c
@@ -34,13 +34,13 @@
#include <mailutils/diag.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
+#include <mailutils/sockaddr.h>
struct _mu_ip_server
{
char *ident;
- struct sockaddr *addr;
- int addrlen;
+ struct mu_sockaddr *addr;
int fd;
int type;
mu_acl_t acl;
@@ -66,8 +66,7 @@ struct _mu_ip_server
#define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
int
-mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
- int addrlen, int type)
+mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr, int type)
{
struct _mu_ip_server *srv;
@@ -84,14 +83,7 @@ mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
srv = calloc (1, sizeof *srv);
if (!srv)
return ENOMEM;
- srv->addr = calloc (1, addrlen);
- if (!srv->addr)
- {
- free (srv);
- return ENOMEM;
- }
- memcpy (srv->addr, addr, addrlen);
- srv->addrlen = addrlen;
+ srv->addr = addr;
srv->type = type;
srv->fd = -1;
switch (type)
@@ -120,7 +112,7 @@ mu_ip_server_destroy (mu_ip_server_t *psrv)
if (srv->f_free)
srv->f_free (srv->data);
close (srv->fd);
- free (srv->addr);
+ mu_sockaddr_free (srv->addr);
free (srv->ident);
if (srv->type == MU_IP_UDP && srv->v.udp_data.buf)
free (srv->v.udp_data.buf);
@@ -234,6 +226,11 @@ mu_address_family_to_domain (int family)
case AF_INET:
return PF_INET;
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ return PF_INET6;
+#endif
+
default:
abort ();
}
@@ -247,14 +244,11 @@ mu_ip_server_open (mu_ip_server_t srv)
if (!srv || srv->fd != -1)
return EINVAL;
- if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0))
- {
- char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
- mu_debug_log ("opening server \"%s\" %s", IDENTSTR (srv), p);
- free (p);
- }
+ mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
+ ("opening server \"%s\" %s", IDENTSTR (srv),
+ mu_sockaddr_str (srv->addr)));
- fd = socket (mu_address_family_to_domain (srv->addr->sa_family),
+ fd = socket (mu_address_family_to_domain (srv->addr->addr->sa_family),
((srv->type == MU_IP_UDP) ? SOCK_DGRAM : SOCK_STREAM), 0);
if (fd == -1)
{
@@ -263,7 +257,7 @@ mu_ip_server_open (mu_ip_server_t srv)
return errno;
}
- switch (srv->addr->sa_family)
+ switch (srv->addr->addr->sa_family)
{
case AF_UNIX:
{
@@ -299,7 +293,7 @@ mu_ip_server_open (mu_ip_server_t srv)
}
break;
- case AF_INET:
+ default:
{
int t;
@@ -308,7 +302,7 @@ mu_ip_server_open (mu_ip_server_t srv)
}
}
- if (bind (fd, srv->addr, srv->addrlen) == -1)
+ if (bind (fd, srv->addr->addr, srv->addr->addrlen) == -1)
{
mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
("%s: bind: %s", IDENTSTR (srv), mu_strerror (errno)));
@@ -336,12 +330,9 @@ mu_ip_server_shutdown (mu_ip_server_t srv)
{
if (!srv || srv->fd != -1)
return EINVAL;
- if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0))
- {
- char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
- mu_debug_log ("closing server \"%s\" %s", IDENTSTR (srv), p);
- free (p);
- }
+ mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
+ ("closing server \"%s\" %s", IDENTSTR (srv),
+ mu_sockaddr_str (srv->addr)));
close (srv->fd);
return 0;
}
@@ -356,6 +347,9 @@ mu_ip_tcp_accept (mu_ip_server_t srv, void *call_data)
struct sockaddr sa;
struct sockaddr_in s_in;
struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
} client;
socklen_t size = sizeof (client);
@@ -407,6 +401,9 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
struct sockaddr sa;
struct sockaddr_in s_in;
struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
} client;
fd_set rdset;
@@ -463,7 +460,7 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
IDENTSTR (srv), strerror (rc)));
if (res == mu_acl_result_deny)
{
- char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
+ char *p = mu_sockaddr_to_astr (&client.sa, salen);
mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p);
free (p);
return 0;
@@ -528,22 +525,16 @@ mu_udp_server_get_rdata (mu_ip_server_t srv, char **pbuf, size_t *pbufsize)
}
int
-mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct sockaddr *s, int *size)
+mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa)
{
- int len;
-
- if (!srv || !s)
+ if (!srv || !psa)
return EINVAL;
- if (s == 0)
- len = srv->addrlen;
- else
- {
- len = srv->addrlen;
- if (*size < len)
- return MU_ERR_BUFSPACE;
- memcpy (s, srv->addr, len);
- }
- *size = len;
- return 0;
+ return mu_sockaddr_copy (psa, srv->addr);
}
-
+
+const char *
+mu_ip_server_addrstr (mu_ip_server_t srv)
+{
+ return mu_sockaddr_str (srv->addr);
+}
+
diff --git a/libmailutils/server/msrv.c b/libmailutils/server/msrv.c
index 5c46e9d70..d5ceb8a39 100644
--- a/libmailutils/server/msrv.c
+++ b/libmailutils/server/msrv.c
@@ -41,6 +41,8 @@
#include <mailutils/nls.h>
#include <mailutils/daemon.h>
#include <mailutils/acl.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
typedef RETSIGTYPE (*mu_sig_handler_t) (int);
@@ -65,19 +67,6 @@ set_signal (int sig, mu_sig_handler_t handler)
# define NSIG 64
#endif
-union m_sockaddr
-{
- struct sockaddr s_sa;
- struct sockaddr_in s_in;
- struct sockaddr_un s_un;
-};
-
-struct m_default_address
-{
- union m_sockaddr s;
- int len;
-};
-
struct _mu_m_server
{
char *ident; /* Server identifier, for logging purposes.*/
@@ -98,7 +87,7 @@ struct _mu_m_server
size_t num_children; /* Current number of running sub-processes. */
pid_t *child_pid;
char *pidfile; /* Name of a PID-file. */
- struct m_default_address defaddr; /* Default address. */
+ struct mu_sockaddr_hints hints; /* Default address hints. */
time_t timeout; /* Default idle timeout. */
mu_acl_t acl; /* Global access control list. */
@@ -112,7 +101,7 @@ struct _mu_m_server
struct m_srv_config /* Configuration data for a single TCP server. */
{
mu_m_server_t msrv; /* Parent m-server. */
- mu_ip_server_t tcpsrv; /* TCP server these data are for. */
+ mu_ip_server_t tcpsrv; /* TCP server these data are for. */
mu_acl_t acl; /* Access control list for this server. */
int single_process; /* Should it run as a single process? */
int transcript; /* Enable session transcript. */
@@ -395,33 +384,20 @@ mu_m_server_pidfile (mu_m_server_t srv)
}
void
-mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa,
- int salen)
+mu_m_server_set_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
{
- if (salen > sizeof srv->defaddr.s)
- {
- mu_error (_("unhandled sockaddr size"));
- abort ();
- }
- memcpy (&srv->defaddr.s.s_sa, sa, salen);
- srv->defaddr.len = salen;
+ if (!hints)
+ memset (&srv->hints, 0, sizeof (srv->hints));
+ else
+ memcpy (&srv->hints, hints, sizeof (srv->hints));
}
int
-mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
- int *salen)
+mu_m_server_get_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
{
- int len;
-
- if (!sa)
+ if (!hints)
return EINVAL;
- len = srv->defaddr.len;
- if (sa)
- {
- if (*salen < len)
- return MU_ERR_BUFSPACE;
- memcpy (sa, &srv->defaddr.s.s_sa, len);
- }
+ memcpy (hints, &srv->hints, sizeof (hints));
return 0;
}
@@ -429,11 +405,7 @@ mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
void
mu_m_server_set_default_port (mu_m_server_t srv, int num)
{
- struct sockaddr_in s_in;
- s_in.sin_family = AF_INET;
- s_in.sin_addr.s_addr = htonl (INADDR_ANY);
- s_in.sin_port = htons (num);
- mu_m_server_set_default_address (srv, (struct sockaddr*) &s_in, sizeof s_in);
+ srv->hints.port = num;
}
void
@@ -473,12 +445,12 @@ static int m_srv_conn (int fd, struct sockaddr *sa, int salen,
mu_ip_server_t srv);
static struct m_srv_config *
-add_server (mu_m_server_t msrv, struct sockaddr *s, int slen, int type)
+add_server (mu_m_server_t msrv, struct mu_sockaddr *s, int type)
{
mu_ip_server_t tcpsrv;
struct m_srv_config *pconf;
- MU_ASSERT (mu_ip_server_create (&tcpsrv, s, slen, type)); /* FIXME: type */
+ MU_ASSERT (mu_ip_server_create (&tcpsrv, s, type)); /* FIXME: type */
MU_ASSERT (mu_ip_server_set_conn (tcpsrv, m_srv_conn));
pconf = calloc (1, sizeof (*pconf));
if (!pconf)
@@ -513,8 +485,21 @@ mu_m_server_begin (mu_m_server_t msrv)
alloc_children (msrv);
mu_list_count (msrv->srvlist, &count);
- if (count == 0 && msrv->defaddr.len)
- add_server (msrv, &msrv->defaddr.s.s_sa, msrv->defaddr.len, msrv->deftype);
+ if (count == 0)
+ {
+ struct mu_sockaddr *ta;
+
+ msrv->hints.flags = MU_AH_PASSIVE;
+ rc = mu_sockaddr_from_node (&ta, NULL, NULL, &msrv->hints);
+ if (rc == 0)
+ while (ta)
+ {
+ struct mu_sockaddr *next = ta->next;
+ ta->next = ta->prev = NULL;
+ add_server (msrv, ta, msrv->deftype);
+ ta = next;
+ }
+ }
if (!msrv->foreground)
{
@@ -599,23 +584,13 @@ tcp_conn_free (void *conn_data, void *server_data)
static int
_open_conn (void *item, void *data)
{
- union
- {
- struct sockaddr sa;
- char pad[512];
- }
- addr;
- int addrlen = sizeof addr;
- char *p;
mu_ip_server_t tcpsrv = item;
mu_m_server_t msrv = data;
int rc = mu_ip_server_open (tcpsrv);
if (rc)
{
- mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
- p = mu_sockaddr_to_astr (&addr.sa, addrlen);
- mu_error (_("cannot open connection on %s: %s"), p, mu_strerror (rc));
- free (p);
+ mu_error (_("cannot open connection on %s: %s"),
+ mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
return 0;
}
rc = mu_server_add_connection (msrv->server,
@@ -624,10 +599,8 @@ _open_conn (void *item, void *data)
tcp_conn_handler, tcp_conn_free);
if (rc)
{
- mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
- p = mu_sockaddr_to_astr (&addr.sa, addrlen);
- mu_error (_("cannot add connection %s: %s"), p, mu_strerror (rc));
- free (p);
+ mu_error (_("cannot add connection %s: %s"),
+ mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
mu_ip_server_shutdown (tcpsrv);
mu_ip_server_destroy (&tcpsrv);
}
@@ -756,199 +729,55 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen,
}
-
-unsigned short
-get_port (const char *p)
-{
- if (p)
- {
- char *q;
- unsigned long n = strtoul (p, &q, 0);
- if (*q == 0)
- {
- if (n > USHRT_MAX)
- {
- mu_error (_("invalid port number: %s"), p);
- return 1;
- }
-
- return htons (n);
- }
- else
- {
- struct servent *sp = getservbyname (p, "tcp");
- if (!sp)
- return 0;
- return sp->s_port;
- }
- }
- return 0;
-}
-
-static int
-get_family (const char **pstr, sa_family_t *pfamily)
-{
- static struct family_tab
- {
- int len;
- char *pfx;
- int family;
- } ftab[] = {
-#define S(s,f) { sizeof (#s":") - 1, #s":", f }
- S (file, AF_UNIX),
- S (unix, AF_UNIX),
- S (local, AF_UNIX),
- S (socket, AF_UNIX),
- S (inet, AF_INET),
- S (tcp, AF_INET),
-#undef S
- { 0 }
- };
- struct family_tab *fp;
-
- const char *str = *pstr;
- int len = strlen (str);
- for (fp = ftab; fp->len; fp++)
- {
- if (len > fp->len && memcmp (str, fp->pfx, fp->len) == 0)
- {
- str += fp->len;
- if (str[0] == '/' && str[1] == '/')
- str += 2;
- *pstr = str;
- *pfamily = fp->family;
- return 0;
- }
- }
- return 1;
-}
-
-static int
-is_ip_addr (const char *arg)
-{
- int dot_count;
- int digit_count;
-
- dot_count = 0;
- digit_count = 0;
- for (; *arg != 0 && *arg != ':'; arg++)
- {
- if (*arg == '.')
- {
- if (++dot_count > 3)
- break;
- digit_count = 0;
- }
- else if (!(mu_isdigit (*arg) && ++digit_count <= 3))
- return 0;
- }
- return dot_count == 3;
-}
-
int
-_mu_m_server_parse_url (const char *arg, union m_sockaddr *s,
- int *psalen, struct sockaddr *defsa)
+mu_m_server_parse_url (mu_m_server_t msrv, const char *arg,
+ struct mu_sockaddr **psa)
{
- char *p;
- unsigned short n;
- int len;
-
- if (is_ip_addr (arg))
- s->s_sa.sa_family = AF_INET;
- else if (get_family (&arg, &s->s_sa.sa_family))
+ int rc;
+ mu_url_t url, url_hint;
+
+ if (arg[0] == '/')
+ url_hint = NULL;
+ else
{
- mu_error (_("invalid family"));
- return EINVAL;
+ rc = mu_url_create (&url_hint, "inet://");
+ if (rc)
+ return rc;
}
-
- switch (s->s_sa.sa_family)
+ rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
+ mu_url_destroy (&url_hint);
+ if (rc)
{
- case AF_INET:
- *psalen = sizeof (s->s_in);
- if ((n = get_port (arg)))
- {
- s->s_in.sin_addr.s_addr = htonl (INADDR_ANY);
- s->s_in.sin_port = htons (n);
- }
- else
- {
- p = strchr (arg, ':');
- if (p)
- *p++ = 0;
- if (inet_aton (arg, &s->s_in.sin_addr) == 0)
- {
- struct hostent *hp = gethostbyname (arg);
- if (hp)
- s->s_in.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
- else
- {
- mu_error (_("invalid IP address: %s"), arg);
- return EINVAL;
- }
- }
- if (p)
- {
- n = get_port (p);
- if (!n)
- {
- mu_error (_("invalid port number: %s"), p);
- return EINVAL;
- }
- s->s_in.sin_port = n;
- }
- else if (defsa && defsa->sa_family == AF_INET)
- s->s_in.sin_port = ((struct sockaddr_in*)defsa)->sin_port;
- else
- {
- mu_error (_("missing port number"));
- return EINVAL;
- }
- }
- break;
-
- case AF_UNIX:
- *psalen = sizeof (s->s_un);
- len = strlen (arg);
- if (len > sizeof s->s_un.sun_path - 1)
- {
- mu_error (_("%s: file name too long"), arg);
- return EINVAL;
- }
- strcpy (s->s_un.sun_path, arg);
- break;
+ mu_error (_("cannot parse URL `%s': %s"), arg, mu_strerror (rc));
+ return rc;
}
- return 0;
-}
-
-int
-mu_m_server_parse_url (mu_m_server_t msrv, char *arg,
- struct sockaddr *sa, int *psalen)
-{
- int rc;
- union m_sockaddr s;
- int salen;
- rc = _mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa);
+ msrv->hints.flags = MU_AH_PASSIVE;
+ rc = mu_sockaddr_from_url (psa, url, &msrv->hints);
if (rc)
- return rc;
- if (sa)
- {
- if (*psalen < salen)
- return MU_ERR_BUFSPACE;
- memcpy (sa, &s.s_sa, salen);
- }
- *psalen = salen;
- return 0;
+ mu_error (_("cannot create sockaddr for URL `%s': %s"), arg,
+ mu_strerror (rc));
+ mu_url_destroy (&url);
+ return rc;
}
static int
server_block_begin (const char *arg, mu_m_server_t msrv, void **pdata)
{
- union m_sockaddr s;
- int salen;
- if (_mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa))
+ struct mu_sockaddr *s;
+ if (mu_m_server_parse_url (msrv, arg, &s))
return 1;
- *pdata = add_server (msrv, &s.s_sa, salen, msrv->deftype);
+ if (s->next)
+ {
+ /* FIXME: (1) Find a way to handle all addresses.
+ (2) Print which address is being used.
+ */
+ mu_diag_output (MU_DIAG_WARNING,
+ _("%s resolves to several addresses, "
+ "only the first is used"), arg);
+ mu_sockaddr_free (s->next);
+ }
+ *pdata = add_server (msrv, s, msrv->deftype);
return 0;
}
@@ -1002,21 +831,46 @@ _cb_daemon_mode (void *data, mu_config_value_t *val)
return 0;
}
+unsigned short
+get_port (const char *p)
+{
+ if (p)
+ {
+ char *q;
+ unsigned long n = strtoul (p, &q, 0);
+ if (*q == 0)
+ {
+ if (n > USHRT_MAX)
+ {
+ mu_error (_("invalid port number: %s"), p);
+ return 1;
+ }
+
+ return htons (n);
+ }
+ else
+ {
+ struct servent *sp = getservbyname (p, "tcp");
+ if (!sp)
+ return 0;
+ return sp->s_port;
+ }
+ }
+ return 0;
+}
+
static int
_cb_port (void *data, mu_config_value_t *val)
{
- struct m_default_address *ap = data;
+ struct mu_sockaddr_hints *hp = data;
unsigned short num;
-
+
if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
return 1;
num = get_port (val->v.string);
if (!num)
return 1;
- ap->s.s_in.sin_family = AF_INET;
- ap->s.s_in.sin_addr.s_addr = htonl (INADDR_ANY);
- ap->s.s_in.sin_port = num;
- ap->len = sizeof ap->s.s_in;
+ hp->port = num;
return 0;
}
@@ -1036,7 +890,7 @@ static struct mu_cfg_param dot_server_cfg_param[] = {
N_("Store PID of the master process in this file."),
N_("file") },
{ "port", mu_cfg_callback,
- NULL, mu_offsetof (struct _mu_m_server,defaddr), _cb_port,
+ NULL, mu_offsetof (struct _mu_m_server, hints), _cb_port,
N_("Default port number.") },
{ "timeout", mu_cfg_time,
NULL, mu_offsetof (struct _mu_m_server,timeout), NULL,

Return to:

Send suggestions and report system problems to the System administrator.