From: Angelos Karageorgiou on
A milter to verify valid from addresses



/*
Ugly hack to verify from addresses , code grabbed from sample-milter.c and
sun docs
can be further enhanced by verifying if the IPs from the from addresses's
belong to a particular ISP
any takers ?


Makefile
LdapVfrom-milter: LdapVfrom-milter.o
gcc -g -o LdapVfrom-milter
LdapVfrom-milter.o -L../sendmail-8.14.0/obj.Linux.2.4.21-4.ELsmp.i686/libmilter/
-lmilter -lpthread -llber -lldap

LdapVfrom-milter.o: LdapVfrom-milter.c
gcc -g -DDEBUG -c LdapVfrom-milter.c -I../sendmail-8.14.0/include/


Reduces back scatter from spammers


ldap organization is as follows
o=TOP
|
ou=domains
|
+----------- ou=unix.gr ------------------------- ou=someother_domain
|
mail=angelos(a)unix.gr
|
mail=sdfsdfsdf

Angelos Karageorgiou Feb 2007
angelos(a)unix.gr
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <syslog.h>
#include <ldap.h>
#include <signal.h>

#include "libmilter/mfapi.h"

/* Change these as needed. */
#define HOSTNAME "lookup1"
#define BASEDN "ou=domains,o=TOP"
#define DOMAINFILTER
"(&(ou=%s)(objectclass=organizationalunit)(objectClass=qmailUser))"
#define MAILFILTER
"(&(|(mail=%s)(mailalternateaddress=%s)(mailalternateaddress=catchall@%s))(accountstatus=active))"
#define MAILUID 8
#define MAILGID 12
#define UNVERIFIABLE -1
#define XHEADER "X-LdapVfrom"



#ifndef bool
# define bool int
# define TRUE 1
# define FALSE 0
#endif /* ! bool */


int ldapquery( char *filter, char *base);
void daemonize() {
int f;
switch(fork()) {
case 0: /* child */
break;
case -1: /* error */
exit(EX_TEMPFAIL);
default: /* parent */
exit(EX_OK);
}
#ifdef HAVE_SETSID
setsid();
#endif
/* FIXME: implement chrooting! */
chdir("/etc/mail");
setuid(MAILUID);
setgid(MAILGID);

}

struct mlfiPriv
{
char *mlfi_fname;
char *mlfi_connectfrom;
char *mlfi_helofrom;
FILE *mlfi_fp;
int VERIFIED;
};

#define MLFIPRIV ((struct mlfiPriv *) smfi_getpriv(ctx))

extern sfsistat mlfi_cleanup(SMFICTX *, bool);

/* recipients to add and reject (set with -a and -r options) */
char *add = NULL;
char *reject = NULL;

sfsistat
mlfi_connect(ctx, hostname, hostaddr)
SMFICTX *ctx;
char *hostname;
_SOCK_ADDR *hostaddr;
{
struct mlfiPriv *priv;
char *ident;

/* allocate some private memory */
priv = malloc(sizeof *priv);
if (priv == NULL)
{
/* can't accept this message right now */
return SMFIS_TEMPFAIL;
}
memset(priv, '\0', sizeof *priv);

/* save the private data */
smfi_setpriv(ctx, priv);

ident = smfi_getsymval(ctx, "_");
if (ident == NULL)
ident = "???";
if ((priv->mlfi_connectfrom = strdup(ident)) == NULL)
{
(void) mlfi_cleanup(ctx, FALSE);
return SMFIS_TEMPFAIL;
}

/* continue processing */
return SMFIS_CONTINUE;
}

sfsistat
mlfi_helo(ctx, helohost)
SMFICTX *ctx;
char *helohost;
{
size_t len;
char *tls;
char *buf;
struct mlfiPriv *priv = MLFIPRIV;

/* continue processing */
return SMFIS_CONTINUE;
}

sfsistat
mlfi_envfrom(ctx, argv)
SMFICTX *ctx;
char **argv;
{
char base[1000];
char filter[1000];
struct mlfiPriv *priv = MLFIPRIV;
char *mailaddr = smfi_getsymval(ctx, "{mail_addr}");

char mail[1000];
strncpy(mail,mailaddr,999);
char delimiter[]="@";
const char *delim=delimiter;
char *username=strtok(mail,delim);

if ( username == NULL ) {
syslog(LOG_ERR,"invalid From '%s'",mailaddr);
(void) mlfi_cleanup(ctx, FALSE);
priv->VERIFIED=UNVERIFIABLE;
return SMFIS_CONTINUE;
}


char *domain=strtok(NULL,delim);
if ( domain == NULL ) {
syslog(LOG_ERR,"invalid From '%s'",mailaddr);
(void) mlfi_cleanup(ctx, FALSE);
priv->VERIFIED=UNVERIFIABLE;
return SMFIS_CONTINUE;
}


sprintf(base,"%s",BASEDN);
sprintf(filter,DOMAINFILTER,domain);
priv->VERIFIED=ldapquery(filter,base);

if ( priv->VERIFIED<= 0 ){
priv->VERIFIED=UNVERIFIABLE; /* just in case */
syslog(LOG_INFO,"%s Domain not in LDAP server",filter);
(void) mlfi_cleanup(ctx, FALSE);
return SMFIS_CONTINUE;
}
syslog(LOG_INFO,"%s domain found",filter);


sprintf(base,"ou=%s,%s",domain,BASEDN);
sprintf(filter,MAILFILTER,mailaddr,mailaddr,domain);
priv->VERIFIED=ldapquery(filter,base);


if (priv->VERIFIED < 0 ){
syslog(LOG_ERR,"%s %s %s ldap query failed",base,filter,mailaddr);
return SMFIS_CONTINUE;
}

if (priv->VERIFIED ==0 ){
syslog(LOG_ERR,"%s %s mailaddr invalid %s",base,filter,mailaddr);
char msg[1024];
sprintf(msg,"Your From Address is Invalid",mailaddr);
smfi_setreply(ctx, "550", "5.7.1",msg);
return SMFIS_REJECT;
}

syslog(LOG_INFO,"%s %s mailaddr %s OK",base,filter,mailaddr);
return SMFIS_CONTINUE;
}



mlfi_envrcpt(ctx, argv)
SMFICTX *ctx;
char **argv;
{
return SMFIS_CONTINUE;


}

sfsistat
mlfi_header(ctx, headerf, headerv)
SMFICTX *ctx;
char *headerf;
unsigned char *headerv;
{
return SMFIS_CONTINUE;
}

sfsistat
mlfi_eoh(ctx)
SMFICTX *ctx;
{
return SMFIS_CONTINUE;
}

sfsistat
mlfi_body(ctx, bodyp, bodylen)
SMFICTX *ctx;
unsigned char *bodyp;
size_t bodylen;
{
return SMFIS_CONTINUE;

}

sfsistat
mlfi_eom(ctx)
SMFICTX *ctx;
{
bool ok = TRUE;
struct mlfiPriv *priv = MLFIPRIV;

char *msgid=smfi_getsymval(ctx, "i");
char *mailaddr = smfi_getsymval(ctx, "{mail_addr}");
char msg[1024];


if ( priv->VERIFIED < 0 ){
sprintf(msg,"MsgID:%s From Address:%s unverifiable",msgid,mailaddr);
smfi_addheader(ctx, XHEADER,"From Address UnVerifiable");
} else if ( priv->VERIFIED > 0 ){
sprintf(msg,"MsgID:%s From Address:%s Verified",msgid,mailaddr);
smfi_addheader(ctx, XHEADER,"From Address Verified");
} else {
sprintf(msg,"MsgID:%s From Address:%s Program Error, I should not be
here",msgid,mailaddr);
smfi_addheader(ctx, XHEADER,"Program/logical Error Logical");
}

syslog(LOG_INFO,msg);
return mlfi_cleanup(ctx, ok);
}

sfsistat mlfi_abort(ctx) SMFICTX *ctx;
{
return mlfi_cleanup(ctx, FALSE);
}

sfsistat
mlfi_cleanup(ctx, ok)
SMFICTX *ctx;
bool ok;
{
sfsistat rstat = SMFIS_CONTINUE;
struct mlfiPriv *priv = MLFIPRIV;
return SMFIS_CONTINUE;
}

sfsistat
mlfi_close(ctx)
SMFICTX *ctx;
{
struct mlfiPriv *priv = MLFIPRIV;

if (priv == NULL)
return SMFIS_CONTINUE;
if (priv->mlfi_connectfrom != NULL)
free(priv->mlfi_connectfrom);
if (priv->mlfi_helofrom != NULL)
free(priv->mlfi_helofrom);
free(priv);
smfi_setpriv(ctx, NULL);
return SMFIS_CONTINUE;
}

sfsistat
mlfi_unknown(ctx, cmd)
SMFICTX *ctx;
char *cmd;
{
return SMFIS_CONTINUE;
}

sfsistat
mlfi_data(ctx)
SMFICTX *ctx;
{
return SMFIS_CONTINUE;
}

sfsistat
mlfi_negotiate(ctx, f0, f1, f2, f3, pf0, pf1, pf2, pf3)
SMFICTX *ctx;
unsigned long f0;
unsigned long f1;
unsigned long f2;
unsigned long f3;
unsigned long *pf0;
unsigned long *pf1;
unsigned long *pf2;
unsigned long *pf3;
{
return SMFIS_ALL_OPTS;
}

struct smfiDesc smfilter =
{
"LdapVfrom", /* filter name */
SMFI_VERSION, /* version code -- do not change */
SMFIF_ADDHDRS, /* flags */
mlfi_connect, /* connection info filter */
mlfi_helo, /* SMTP HELO command filter */
mlfi_envfrom, /* envelope sender filter */
mlfi_envrcpt, /* envelope recipient filter */
mlfi_header, /* header filter */
mlfi_eoh, /* end of header */
mlfi_body, /* body block filter */
mlfi_eom, /* end of message */
mlfi_abort, /* message aborted */
mlfi_close, /* connection cleanup */
mlfi_unknown, /* unknown SMTP commands */
mlfi_data, /* DATA command */
mlfi_negotiate /* Once, at the start of each SMTP connection */
};

static void
usage(prog)
char *prog;
{
fprintf(stderr,
"Usage: %s -p socket-addr [-t timeout]\n",
prog);
}

int main(int argc, char **argv) {

bool setconn = FALSE;
int c;
const char *args = "p:t:h";
extern char *optarg;

/* Process command line options */
while ((c = getopt(argc, argv, args)) != -1)
{
switch (c)
{
case 'p':
if (optarg == NULL || *optarg == '\0')
{
(void) fprintf(stderr, "Illegal conn: %s\n",
optarg);
exit(EX_USAGE);
}
if (smfi_setconn(optarg) == MI_FAILURE)
{
(void) fprintf(stderr,
"smfi_setconn failed\n");
exit(EX_SOFTWARE);
}

/*
** If we're using a local socket, make sure it
** doesn't already exist. Don't ever run this
** code as root!!
*/

if (strncasecmp(optarg, "unix:", 5) == 0)
unlink(optarg + 5);
else if (strncasecmp(optarg, "local:", 6) == 0)
unlink(optarg + 6);
setconn = TRUE;
break;

case 't':
if (optarg == NULL || *optarg == '\0')
{
(void) fprintf(stderr, "Illegal timeout: %s\n",
optarg);
exit(EX_USAGE);
}
if (smfi_settimeout(atoi(optarg)) == MI_FAILURE)
{
(void) fprintf(stderr,
"smfi_settimeout failed\n");
exit(EX_SOFTWARE);
}
break;

case 'h':
default:
usage(argv[0]);
exit(EX_USAGE);
}
}
if (!setconn)
{
fprintf(stderr, "%s: Missing required -p argument\n", argv[0]);
usage(argv[0]);
exit(EX_USAGE);
}
if (smfi_register(smfilter) == MI_FAILURE)
{
fprintf(stderr, "smfi_register failed\n");
exit(EX_UNAVAILABLE);
}
daemonize();
openlog("LdapVfrom",LOG_NOWAIT|LOG_PID,LOG_MAIL);

/* block the SIGCHLD signal */
signal(SIGCHLD, SIG_BLOCK);

/* enter main 'loop' */
syslog(LOG_INFO,"Ldap From Verifier starting ");
return smfi_main();
}


/*
ugly hack ripped from docs.sun.com

Angelos Karageorgiou Feb 2007
*/


int ldapquery( char *filter, char *base)
{
LDAP *ld;
LDAPMessage *res, *msg;
LDAPControl **serverctrls;
BerElement *ber;
char *a, *dn, *matched_msg = NULL, *error_msg = NULL;
char **vals, **referrals;
int version, i, rc, parse_rc, msgtype, num_entries = 0,
num_refs = 0;

/* Get a handle to an LDAP connection. */
if ( (ld = ldap_init( HOSTNAME, LDAP_PORT )) == NULL ) {
syslog(LOG_ERR,"ldap_init failed" );
return( -1 );
}

version = LDAP_VERSION3;
if ( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ) !=
LDAP_SUCCESS ) {
syslog( LOG_ERR, "ldap_set_option: failed");
ldap_unbind( ld );
}

/* Bind to the server anonymously. */
rc = ldap_simple_bind_s( ld, NULL, NULL );
if ( rc != LDAP_SUCCESS ) {
syslog( LOG_ERR, "ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
if ( matched_msg != NULL && *matched_msg != '\0' ) {
syslog( LOG_ERR, "Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
ldap_unbind_s( ld );
return( -1 );
}
/* Perform the search operation. */
rc = ldap_search_s( ld, base, LDAP_SCOPE_SUBTREE, filter, NULL, 0, &res );

if ( rc != LDAP_SUCCESS ) {
syslog( LOG_ERR, "ldap_search_ext_s: %s\n", ldap_err2string( rc ) );
if ( error_msg != NULL && *error_msg != '\0' ) {
syslog( LOG_ERR, "%s\n", error_msg );
}
if ( matched_msg != NULL && *matched_msg != '\0' ) {
syslog( LOG_ERR, "Part of the DN that matches an existing entry: %s\n",
matched_msg );
}
ldap_unbind_s( ld );
return( -1 );
}
num_entries = ldap_count_entries( ld, res );
num_refs = ldap_count_references( ld, res );

#ifdef DEUBG
syslog(LOG_INFO,"Found %d entries base=%s
filter=%s\n",num_entries,base,filter);
syslog(LOG_INFO,"Found %d referrals base=%s filter=%s
\n",num_refs,base,filter);
#endif

/* Disconnect when done. */
ldap_unbind( ld );
return( num_entries );
}









From: jmaimon on
On Feb 12, 10:53 am, "Angelos Karageorgiou" <ange...(a)unix.gr> wrote:
> Amilterto verify valid from addresses
>
I have posted this to the milter list, with a local copy of code,
under the Open Source section, as you hadnt mentioned either a license
or URL

http://www.jmaimon.com/sendmail/milters