rendered paste body#include <netinet/in.h>#include <sys/types.h>#include <sys/param.h>#include <sys/quota.h>#include <sys/socket.h>#include <sys/time.h>#include <sys/stat.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sysexits.h>#include <time.h>#include <unistd.h>#include <syslog.h>#include <ctype.h>#include <netdb.h>#include <errno.h>#include <lber.h>#include <ldap.h>#include <fcntl.h>#include <regex.h>#include <pwd.h>#include <sys/wait.h>#include <rpc/types.h>#include <rpc/xdr.h>#include <rpc/rpc.h>#include <rpc/pmap_prot.h>#include <rpcsvc/rquota.h>#include <libmilter/mfapi.h>#define LDAP_SERVER "localhost"#define LDAP_PORT 389#define DOMAIN_NAME_REGEX "([^.]*[.][^.]*)[.]*$"#define DEBUGGING 1static regex_t re_sld;void sigSEGV() { regfree(&re_sld); syslog(LOG_ERR, "(sigSEGV) Caught SIGSEGV"); closelog(); abort(); exit(0);}void lowercase(char *buf) { if(buf) { while(*buf) { if(isupper(*buf)) *buf = tolower(*buf); buf++; } }}char* vispuser2uid(char *username, char *isp) { char filter[256]; char *attrs[2]; char **values; char *rv = NULL; LDAP *ld; LDAPMessage *res; LDAPMessage *entry; char *basedn = "ou=People,dc=aracnet,dc=com"; int i; if(username == NULL || isp == NULL) return NULL; attrs[0] = "uid"; attrs[1] = NULL; if((ld = ldap_init(LDAP_SERVER, LDAP_PORT)) == NULL) { /*syslog(LOG_ERR, "ldap_init: Failed");*/ ldap_unbind(ld); return NULL; } if((i = ldap_simple_bind_s(ld, "", "")) != 0) { /*syslog(LOG_ERR, "ldap_simple_bind_s: %s", ldap_err2string(i));*/ ldap_unbind(ld); return NULL; } snprintf(filter, sizeof(filter), "(&(username=%s)(isp=%s))", username, isp); if((i = ldap_search_s(ld, basedn, LDAP_SCOPE_ONELEVEL, filter, attrs, 0, &res)) != 0) { if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); return NULL; } if((entry = ldap_first_entry(ld, res)) == NULL) { if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); return NULL; } values = ldap_get_values(ld, res, "uid"); if(values != NULL) { rv = strdup(values[0]); ldap_value_free(values); } if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); return rv;}char* lookup_virtuser(char *username, char *domain) { int i; char filter[256]; char *attrs[2]; char **values; char *rv = NULL; LDAP *ld; LDAPMessage *res; LDAPMessage *entry; char *basedn = "ou=VirtUserTable,ou=Mail,dc=aracnet,dc=com"; if(domain == NULL) return NULL; attrs[0] = "realEmail"; attrs[1] = NULL; if((ld = ldap_init(LDAP_SERVER, LDAP_PORT)) == NULL) { /*syslog(LOG_ERR, "ldap_init: Failed");*/ ldap_unbind(ld); return NULL; } if((i = ldap_simple_bind_s(ld, "", "")) != 0) { /*syslog(LOG_ERR, "ldap_simple_bind_s: %s", ldap_err2string(i));*/ ldap_unbind(ld); return NULL; } if(username != NULL) { snprintf(filter, sizeof(filter), "(virtemail=%s@%s)", username, domain); } else { snprintf(filter, sizeof(filter), "(virtemail=@%s)", domain); } if((i = ldap_search_s(ld, basedn, LDAP_SCOPE_ONELEVEL, filter, attrs, 0, &res)) != 0) { if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); return NULL; } if((entry = ldap_first_entry(ld, res)) == NULL) { if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); return NULL; } values = ldap_get_values(ld, res, "realEmail"); if(values != NULL) { char *username = values[0]; char *domain; if((domain = strchr(username, '@'))) { domain++; if(strcasecmp(domain, "aracnet.com") == 0) { domain--; *domain = '\0'; rv = vispuser2uid(username, "aracnet"); } else if(strcasecmp(domain, "spiritone.com") == 0) { domain--; *domain = '\0'; rv = vispuser2uid(username, "spiritone"); } else if(strcasecmp(domain, "involved.com") == 0) { domain--; *domain = '\0'; rv = vispuser2uid(username, "involved.com"); } else { rv = strdup(values[0]); } } else { rv = strdup(values[0]); } ldap_value_free(values); } if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); return rv;}intcall_rpc(char *hostname, int prognum, int versnum, int procnum, xdrproc_t inproc, struct getquota_args *in, xdrproc_t outproc, struct getquota_rslt *out){ struct addrinfo *hstaddr; struct sockaddr_in server_addr; enum clnt_stat clnt_stat; struct timeval wait, timeout; CLIENT *client = NULL; int socket = RPC_ANYSOCK; wait.tv_usec = 0; wait.tv_sec = 6; timeout.tv_usec = 0; timeout.tv_sec = 25; if(getaddrinfo(hostname, NULL, NULL, &hstaddr) != 0) return RPC_UNKNOWNHOST; server_addr.sin_addr = ((struct sockaddr_in*)hstaddr->ai_addr)->sin_addr; freeaddrinfo(hstaddr); server_addr.sin_family = AF_INET; server_addr.sin_port = 0; if ((client = clntudp_create(&server_addr, prognum, versnum, wait, &socket)) == NULL) return ((int) rpc_createerr.cf_stat); client->cl_auth = authunix_create_default(); clnt_stat = clnt_call(client, procnum, inproc, (caddr_t)in, outproc, (caddr_t)out, timeout); close(socket); auth_destroy(client->cl_auth); client->cl_auth = NULL; clnt_destroy(client); client = NULL; return ((int) clnt_stat);}int over_quota(char *username, char *domain) { struct getquota_rslt gqr; struct getquota_args gqa; struct passwd pw; struct passwd *pwp = NULL; char *hostname = "opal.spiritone.com"; char *realemail = NULL; char buf[256]; int rc; int overquota = 0; if(domain != NULL) { realemail = lookup_virtuser(username, domain); if(realemail == NULL) realemail = lookup_virtuser(NULL, domain); if(realemail == NULL) return 0; if(strcasecmp(realemail, "nobody@aracnet.com") == 0) { free(realemail); return 1; } if((rc = getpwnam_r(realemail, &pw, buf, sizeof(buf), &pwp)) != 0 || pwp == NULL) { free(realemail); if(rc) syslog(LOG_ERR, "(over_quota) Error getting password entry: %d", rc); return 0; } free(realemail); gqa.gqa_uid = pw.pw_uid; } else { if((rc = getpwnam_r(username, &pw, buf, sizeof(buf), &pwp)) != 0 || pwp == NULL) { if(rc) syslog(LOG_ERR, "(over_quota) Error getting password entry: %d", rc); return 0; } gqa.gqa_uid = pw.pw_uid; } gqa.gqa_pathp = "/var/spool/mail"; if (call_rpc(hostname, RQUOTAPROG, RQUOTAVERS, RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args, &gqa, (xdrproc_t)xdr_getquota_rslt, &gqr) != 0) { syslog(LOG_ERR, "RPC Error: %m"); } else { switch (gqr.status) { case Q_OK: if(gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit > 0) { if(gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit <= gqr.getquota_rslt_u.gqr_rquota.rq_curblocks) { overquota = 1; } } break; case Q_NOQUOTA: break; case Q_EPERM: syslog(LOG_ERR, "quota permission error, host: %s", hostname); break; default: syslog(LOG_ERR, "bad rpc result, host: %s", hostname); break; } } if(overquota) syslog(LOG_ERR, "Over Quota: %s@%s", username, domain); return overquota;/* char command[512]; int i; char realemail[256]; if(domain != NULL) { snprintf(realemail, sizeof(realemail), "%s@%s", username, domain); } else { snprintf(realemail, sizeof(realemail), "%s", username); } sprintf(command, "/usr/local/sbin/lookup_quota %s", realemail); i = system(command); if(i == 256) { syslog(LOG_ERR, "Over Quota: %s (%d)", realemail, i); return 1; } return 0;*/}/* Domain is SLD only! ie, "aracnet", not "aracnet.com" */int user_disabled(char *username, char *domain) { int i; int mailinactive = 0; char filter[256]; char *attrs[2]; char **values; char *basedn = "ou=People,dc=aracnet,dc=com"; LDAP *ld; LDAPMessage *res; LDAPMessage *entry; attrs[0] = "mailstatus"; attrs[1] = NULL; if(username == NULL || domain == NULL) return 0; if((ld = ldap_init(LDAP_SERVER, LDAP_PORT)) == NULL) { syslog(LOG_ERR, "ldap_init: Failed"); ldap_unbind(ld); return 0; } if((i = ldap_simple_bind_s(ld, "", "")) != 0) { syslog(LOG_ERR, "ldap_simple_bind_s: %s", ldap_err2string(i)); ldap_unbind(ld); return 0; } snprintf(filter, sizeof(filter), "(&(username=%s)(isp=%s))", username, domain); if((i = ldap_search_s(ld, basedn, LDAP_SCOPE_ONELEVEL, filter, attrs, 0, &res)) != 0) { if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); if(i) return 0; } if((entry = ldap_first_entry(ld, res)) == NULL) { if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); return 0; } values = ldap_get_values(ld, res, "mailStatus"); if(values != NULL) { if(strcasecmp(values[0], "inactive") == 0) { syslog(LOG_ERR, "User Disabled: %s@%s", username, domain); mailinactive = 1; } ldap_value_free(values); } if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); return mailinactive;}/* Domain is FQDN! */int invalid_visp(char *username, char *domain) { int i; char filter[256]; char *attrs[2]; char *basedn = "ou=virtusertable,ou=mail,dc=aracnet,dc=com"; LDAP *ld; LDAPMessage *res; LDAPMessage *entry; attrs[0] = "realEmail"; attrs[1] = NULL; if(username == NULL || domain == NULL) return 0; if((ld = ldap_init(LDAP_SERVER, LDAP_PORT)) == NULL) { syslog(LOG_ERR, "ldap_init: Failed"); ldap_unbind(ld); return 0; } if((i = ldap_simple_bind_s(ld, "", "")) != 0) { syslog(LOG_ERR, "ldap_simple_bind_s: %s", ldap_err2string(i)); ldap_unbind(ld); return 0; } snprintf(filter, sizeof(filter), "(virtemail=%s@%s)", username, domain); if((i = ldap_search_s(ld, basedn, LDAP_SCOPE_ONELEVEL, filter, attrs, 0, &res)) != 0) { if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); if(i) return 0; } if((entry = ldap_first_entry(ld, res)) == NULL) { /* Invalid User */ if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); syslog(LOG_ERR, "User Unknown: %s@%s", username, domain); return 1; } if(res != NULL) ldap_msgfree(res); ldap_unbind(ld); return 0;}sfsistat mlfi_connect(SMFICTX *ctx, char* hostname, _SOCK_ADDR *hostaddr) { unsigned char *ipa; /* connection from opal for warnquota mail bypasses filter */ ipa = (unsigned char *)&((struct sockaddr_in *)hostaddr)->sin_addr.s_addr; if(ipa[0] == 216 && ipa[1] == 99 && ipa[2] == 193 && ipa[3] == 141) return SMFIS_ACCEPT; return SMFIS_CONTINUE;}sfsistat mlfi_envrcpt(SMFICTX *ctx, char **argv) { char *username; char *domain; char *chr; regmatch_t pmatch; if(argv == NULL || *argv == NULL) syslog(LOG_DEBUG, "(mlfi_envrcpt) Trapped NULL!"); lowercase(*argv); if(**argv == '<') username = (*argv)+1; else username = *argv; chr = strchr(username, '>'); if(chr != NULL) *chr = '\0'; domain = strchr(username, '@'); if(domain != NULL) { *domain = '\0'; domain++; if(strcasecmp(domain, "mail.aracnet.com") == 0) { smfi_setreply(ctx, "550", "5.1.1", "Please use @aracnet.com"); return SMFIS_REJECT; } if(strcasecmp(domain, "lists.aracnet.com") == 0 || strcasecmp(domain, "list2.aracnet.com") == 0) { return SMFIS_CONTINUE; } else if(regexec(&re_sld, domain, 1, &pmatch, 0) == 0) { if(strncasecmp(domain+pmatch.rm_so, "aracnet.com", 11) == 0) { if(invalid_visp(username, "aracnet.com")) { smfi_setreply(ctx, "550", "5.1.1", "User Unknown"); return SMFIS_REJECT; } if(user_disabled(username, "aracnet")) { smfi_setreply(ctx, "550", "5.1.1", "User account inactive"); return SMFIS_REJECT; } if(over_quota(username, NULL)) { smfi_setreply(ctx, "552", "5.2.2", "Mailbox full"); return SMFIS_REJECT; } } else if(strncasecmp(domain+pmatch.rm_so, "involved.com", 12) == 0) { if(invalid_visp(username, "involved.com")) { smfi_setreply(ctx, "550", "5.1.1", "User Unknown"); return SMFIS_REJECT; } if(user_disabled(username, "involved")) { smfi_setreply(ctx, "550", "5.1.1", "User account inactive"); return SMFIS_REJECT; } if(over_quota(username, "involved.com")) { smfi_setreply(ctx, "552", "5.2.2", "Mailbox full"); return SMFIS_REJECT; } } else if(strncasecmp(domain+pmatch.rm_so, "spiritone.com", 13) == 0) { if(invalid_visp(username, "spiritone.com")) { smfi_setreply(ctx, "550", "5.1.1", "User Unknown"); return SMFIS_REJECT; } if(user_disabled(username, "spiritone")) { smfi_setreply(ctx, "550", "5.1.1", "User account inactive"); return SMFIS_REJECT; } if(over_quota(username, "spiritone.com")) { smfi_setreply(ctx, "552", "5.2.2", "Mailbox full"); return SMFIS_REJECT; } } else { if(over_quota(username, domain)) { smfi_setreply(ctx, "552", "5.2.2", "Mailbox full"); return SMFIS_REJECT; } } } } else { if(user_disabled(username, "aracnet")) { smfi_setreply(ctx, "550", "5.1.1", "User account inactive"); return SMFIS_REJECT; } if(over_quota(username, NULL)) { smfi_setreply(ctx, "552", "5.2.2", "Mailbox full"); return SMFIS_REJECT; } } return SMFIS_CONTINUE;}sfsistat mlfi_close(SMFICTX *ctx) { return SMFIS_CONTINUE;}sfsistat mlfi_abort(SMFICTX *ctx) { return SMFIS_CONTINUE;}struct smfiDesc smfilter ={ "VerifyUserMilter", /* filter name */ SMFI_VERSION, /* version code -- do not change */ SMFIF_ADDHDRS, /* flags */ mlfi_connect, /* connection info filter */ NULL, /* SMTP HELO command filter */ NULL, /* envelope sender filter */ mlfi_envrcpt, /* envelope recipient filter */ NULL, /* header filter */ NULL, /* end of header */ NULL, /* body block filter */ NULL, /* end of message */ mlfi_abort, /* message aborted */ mlfi_close /* connection cleanup */};int main(int argc, char *argv[]) { int c; const char *args = "p:"; /* 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); } (void) smfi_setconn(optarg); break; } } if (smfi_register(smfilter) == MI_FAILURE) { fprintf(stderr, "smfi_register failed\n"); exit(EX_UNAVAILABLE); } if(regcomp(&re_sld, DOMAIN_NAME_REGEX, REG_EXTENDED) != 0) { fprintf(stderr, "VerifyUserMilter: error compiling regex: %m"); exit(EX_UNAVAILABLE); } openlog("VerifyUserMilter", LOG_PID, LOG_LOCAL6); signal(SIGSEGV, sigSEGV); chdir("/"); if(fork() == 0) { freopen("/dev/null", "r", stdin); freopen("/dev/null", "w", stdout); freopen("/dev/null", "w", stderr); return smfi_main(); } else return 0;}