/* $Id: milter-greylist.h,v 1.46.2.3 2006/11/07 05:12:12 manu Exp $ */
/*
* Copyright (c) 2004 Emmanuel Dreyfus
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Emmanuel Dreyfus
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _MILTER_GREYLIST_H_
#define _MILTER_GREYLIST_H_
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <libmilter/mfapi.h>
#include "config.h"
#include "dump.h"
#define NUMLEN 20
#define QSTRLEN 1024
#define REGEXLEN 1024
#define HDRLEN 1024
#define HEADERNAME "X-Greylist"
#if defined(HAVE_GETNAMEINFO)
#define IPADDRSTRLEN NI_MAXHOST
#elif defined(INET6_ADDRSTRLEN)
#define IPADDRSTRLEN INET6_ADDRSTRLEN
#else
#define IPADDRSTRLEN IPADDRLEN
#endif
typedef union {
struct in_addr in4;
#ifdef AF_INET6
struct in6_addr in6;
#endif
} ipaddr;
typedef union {
struct sockaddr sa;
struct sockaddr_in sin;
#ifdef AF_INET6
struct sockaddr_in6 sin6;
#endif
} sockaddr_t;
#define SA(sa) ((struct sockaddr *)(sa))
#define SA4(sa) ((struct sockaddr_in *)(sa))
#define SADDR4(sa) (&SA4(sa)->sin_addr)
#ifdef AF_INET6
#define SA6(sa) ((struct sockaddr_in6 *)(sa))
#define SADDR6(sa) (&SA6(sa)->sin6_addr)
#endif
/* Notes:
* -For IPv6 not using s6_addr32 as Solaris 8 for some reason has it only
* defined for its kernel...
* -Using also first two characters in "from" and "rcpt" to distribute
* potentially lot of triplets coming from a single host (first two chars
* only because "<>" is the "shortest" email address)
*/
#define F2B(s) (tolower((int)*(s)) | (tolower((int)*((s)+1)) << 8))
#define F2B_SPICE(from, rcpt) (conf.c_lazyaw ? 0 : (F2B(from) ^ F2B(rcpt)))
#define BUCKET_HASH_V4(v4a, v4m, from, rcpt, bucket_count) \
((ntohl((v4a)->s_addr & (v4m)->s_addr) \
^ F2B_SPICE(from, rcpt)) \
% bucket_count)
#ifdef AF_INET6
#define IN6CAST32(_a) ((uint32_t *)(&(_a)->s6_addr))
#define BUCKET_HASH_V6(v6a, v6m, from, rcpt, bucket_count) \
((ntohl(IN6CAST32(v6a)[0] & IN6CAST32(v6m)[0]) ^ \
ntohl(IN6CAST32(v6a)[1] & IN6CAST32(v6m)[1]) ^ \
ntohl(IN6CAST32(v6a)[2] & IN6CAST32(v6m)[2]) ^ \
ntohl(IN6CAST32(v6a)[3] & IN6CAST32(v6m)[3]) \
^ F2B_SPICE(from, rcpt)) \
% bucket_count)
#define BUCKET_HASH(sa, from, rcpt, bucket_count) \
(sa->sa_family == AF_INET ? \
BUCKET_HASH_V4(SADDR4(sa), \
&conf.c_match_mask, \
from, rcpt, bucket_count) \
: sa->sa_family == AF_INET6 ? \
BUCKET_HASH_V6(SADDR6(sa), \
&conf.c_match_mask6, \
from, rcpt, bucket_count) \
: 0)
#else /* AF_INET6 */
#define BUCKET_HASH(sa, from, rcpt, bucket_count) \
(sa->sa_family == AF_INET ? \
BUCKET_HASH_V4(SADDR4(sa), \
&conf.c_match_mask, \
from, rcpt, bucket_count) \
: 0)
#endif
struct mlfi_priv {
sockaddr_t priv_addr;
socklen_t priv_addrlen;
char priv_hostname[ADDRLEN + 1];
char priv_helo[ADDRLEN + 1];
char priv_from[ADDRLEN + 1];
char priv_rcpt[ADDRLEN + 1];
time_t priv_elapsed;
int priv_whitelist;
char *priv_queueid;
int priv_delayed_reject;
time_t priv_remaining;
int priv_acl_line;
time_t priv_delay;
time_t priv_autowhite;
char *priv_code;
char *priv_ecode;
char *priv_msg;
};
sfsistat mlfi_connect(SMFICTX *, char *, _SOCK_ADDR *);
sfsistat mlfi_helo(SMFICTX *, char *);
sfsistat mlfi_envfrom(SMFICTX *, char **);
sfsistat mlfi_envrcpt(SMFICTX *, char **);
sfsistat mlfi_eom(SMFICTX *);
sfsistat mlfi_close(SMFICTX *);
void usage(char *);
int humanized_atoi(char *);
struct in_addr *prefix2mask4(int, struct in_addr *);
#ifdef AF_INET6
struct in6_addr *prefix2mask6(int, struct in6_addr *);
#endif
void cleanup_sock(char *);
void unmappedaddr(struct sockaddr *, socklen_t *);
void final_dump(void);
int main(int, char **);
void mg_log(int, char *, ...);
char *strncpy_rmsp(char *, char *, size_t);
#ifdef HAVE_STRLCAT
/* #include <string.h> */
#define mystrlcat strlcat
#else
size_t mystrlcat(char *, const char *src, size_t size);
#endif
#if (defined(HAVE_SPF) || defined(HAVE_SPF_ALT))
#define MLFI_HELO mlfi_helo
#else
#define MLFI_HELO NULL
#endif
/*
* Locking management
*/
#define WRLOCK(lock) { \
int err; \
\
if ((err = pthread_rwlock_wrlock(&(lock))) != 0) { \
syslog(LOG_ERR, "%s:%d pthread_rwlock_wrlock failed: %s", \
__FILE__, __LINE__, strerror(err)); \
exit(EX_SOFTWARE); \
} \
}
#define RDLOCK(lock) { \
int err; \
\
if ((err = pthread_rwlock_rdlock(&(lock))) != 0) { \
syslog(LOG_ERR, "%s:%d pthread_rwlock_rdlock failed: %s", \
__FILE__, __LINE__, strerror(err)); \
exit(EX_SOFTWARE); \
} \
}
/*
* There is a bug in GNU pth-2.0.0 that will cause a spurious EPERM
* error when a thread releases a read lock that has been shared by
* two threads and already released by the other one. As a workaround
* for that problem, we just avoid quitting on this error.
*/
#ifndef HAVE_BROKEN_RWLOCK
#define UNLOCK(lock) { \
int err; \
\
if ((err = pthread_rwlock_unlock(&(lock))) != 0) { \
syslog(LOG_ERR, "%s:%d pthread_rwlock_unlock failed: %s", \
__FILE__, __LINE__, strerror(err)); \
exit(EX_SOFTWARE); \
} \
}
#else
#define UNLOCK(lock) { \
int err; \
\
if ((err = pthread_rwlock_unlock(&(lock))) != 0) { \
syslog(LOG_DEBUG, "%s:%d pthread_rwlock_unlock failed: " \
"%s (ignored)", __FILE__, __LINE__, strerror(err)); \
} \
}
#endif
#ifdef HAVE_MISSING_TIMERADD
#define timeradd(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec; \
if ((vvp)->tv_usec >= 1000000) { \
(vvp)->tv_sec++; \
(vvp)->tv_usec -= 1000000; \
} \
} while (/* CONSTCOND */ 0)
#define timersub(tvp, uvp, vvp) \
do { \
(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec; \
(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec; \
if ((vvp)->tv_usec < 0) { \
(vvp)->tv_sec--; \
(vvp)->tv_usec += 1000000; \
} \
} while (/* CONSTCOND */ 0)
#endif
#define ADD_REASON(whystr, reason) \
{ \
if (whystr[0] != '\0') \
mystrlcat(whystr, ", ", sizeof(whystr)); \
mystrlcat(whystr, reason, sizeof(whystr)); \
}
#endif /* _MILTER_GREYLIST_H_ */
syntax highlighted by Code2HTML, v. 0.9.1