Hi, For one of our client we need to create a patch to deny some user to receive mail from outside localnetwork.
We based our modifications on : Qmail-1.03 qmail-ldap-1.03-2006-0201 patch and B S Srinidhi patch for accountStatus localonly ( http://www.mail-archive.com/[email protected]/msg05248.html ) You need to apply all the patch including Srinidhi before. Rcptcheck need to be enable. Create an env variable for STMPD called LOCALNETWORK including the address and mask (CIDR notation) of your local network. Without this variable the test won't occur. eg "192.168.0.0/24" Debug log are level 4. Hope this could be usefull for some people, Thanks to B S Srinid for is usefull patch. Best regards, Olivier GAUDE Novovia diff -abur qmail-1.03/qldap-filter.c qmail-1.03-mod/qldap-filter.c --- qmail-1.03/qldap-filter.c 2006-08-02 18:11:50.000000000 +0200 +++ qmail-1.03-mod/qldap-filter.c 2006-08-02 17:44:21.000000000 +0200 @@ -208,3 +208,16 @@ { return extcnt; } + +char * +simple_filter_mail(char *mail) +{ + /* rebuild ldap filter */ + if (!stralloc_copys(&filter, "(|(mail=" )) return 0; + if (!stralloc_cats(&filter, mail)) return 0; + if (!stralloc_cats(&filter, ")(mailAlternateAddress=")) return 0; + if (!stralloc_cats(&filter, mail)) return 0; + if (!stralloc_cats(&filter, "))")) return 0; + if (!stralloc_0(&filter)) return 0; + return filter_objectclass(filter.s); +} diff -abur qmail-1.03/qmail-smtpd.c qmail-1.03-mod/qmail-smtpd.c --- qmail-1.03/qmail-smtpd.c 2006-08-02 18:12:06.000000000 +0200 +++ qmail-1.03-mod/qmail-smtpd.c 2006-08-02 17:47:51.000000000 +0200 @@ -36,6 +36,7 @@ #include "qldap-errno.h" #include "qmail-ldap.h" #include "limit.h" +#include "stdio.h" #ifdef SMTPEXECCHECK #include "execcheck.h" #endif @@ -158,6 +159,7 @@ void cleanup(void); const char *remoteip; +const char *localnet; void die_read(void) { logline(1,"read error or connection closed"); cleanup(); _exit(1); } void die_write(void) { logline(1,"write error, connection closed"); cleanup(); _exit(1); } @@ -423,6 +425,7 @@ remotehost = env_get("TCPREMOTEHOST"); if (!remotehost) remotehost = "unknown"; remoteinfo = env_get("TCPREMOTEINFO"); + localnet = env_get("LOCALNETWORK"); local = env_get("TCPLOCALHOST"); if (!local) local = env_get("TCPLOCALIP"); @@ -932,6 +935,54 @@ return 0; } +/* check if recipient's accountStatus is localonly */ +int localonly_rcpt(char *localaddr) +{ + const char *attrs[] = { LDAP_ISACTIVE, 0}; + char *filter; + struct qldap *q; + int rv; + int status; + + if (!localnet) { + logline(4,"localnet not defined"); + return 0; + } + + /* taken from qmail-lspawn.c :( */ + q = qldap_new(); + if (q == 0) + _exit(QLX_NOMEM); + rv = qldap_open(q); + if (rv != OK) goto fail; + rv = qldap_bind(q, 0, 0); + if (rv != OK) goto fail; + + /* simple_filter_mail call */ + filter = (char *) simple_filter_mail(localaddr); + if (filter == 0) { rv = ERRNO; goto fail; } + rv = qldap_lookup(q, filter, attrs); + if (rv != OK) goto fail; + + /* check if the ldap entry is localonly */ + rv = qldap_get_status(q, &status); + if (rv != OK) goto fail; + if (status == STATUS_LOCALONLY) { + logline(3,"account status is 'localonly'"); + relayclient = 0; + flagauthok = 0; + if (!env_unset("RELAYCLIENT=")) die_nomem(); + qldap_free(q); + return 1; + } + +fail: + qldap_free(q); + logline(3,"account status is not 'localonly'"); + return 0; +} + + void smtp_mail(char *arg) { unsigned int i,j; @@ -1151,6 +1202,38 @@ out("250 ok\r\n"); } + +unsigned int is_sender_ip_local (const char *ip) +{ + int byte1 = 0, byte2 = 0; + int byte3 = 0, byte4 = 0; + int mask = 0, decal = 0; + long unsigned int ipn = 0; + long unsigned int net = 0; + + logline2(4,"remote ip: ", ip); + logline2(4,"local network / mask: ", localnet); + + /* convert sender's ip string to long int */ + sscanf(ip, "%d.%d.%d.%d", &byte1, &byte2, &byte3, &byte4); + ipn = (byte1 << 24) + (byte2 << 16) + (byte3 << 8) + byte4; + + /* convert net ip string to long int and get mask from localnet */ + sscanf(localnet, "%d.%d.%d.%d/%d", &byte1, &byte2, &byte3, &byte4, &mask); + net = (byte1 << 24) + (byte2 << 16) + (byte3 << 8) + byte4; + + decal = 32 - mask; + ipn >>= decal; + net >>= decal; + + if (ipn == net) { + return 1 ; + } + + return 0; +} + + void smtp_rcpt(char *arg) { if (!seenmail) @@ -1230,6 +1313,17 @@ switch (ldaplookup(addr.s, &s)) { case 1: /* valid */ logline(4,"recipient verify OK"); + + /* recipients with localonly accountStatus + are not allowed to receive mail from non local network */ + if (localonly_rcpt(addr.s) == 1) { + if (!is_sender_ip_local(remoteip)) { + logline(4, "recipient is not allowed to receive non local mail"); + err_bmf(); + if (errdisconnect) err_quit(); + return; + } + } break; case 0: /* invalid */ logline2(2, "bad recipient: ", addr.s);
