From: Angelos Karageorgiou on 12 Feb 2007 10:53 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 22 Feb 2007 05:49 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
|
Pages: 1 Prev: host name lookup failure Next: Synonym Configuration Problem |