static sfsistat blacklist_header(SMFICTX *ctx, char *headerf, char *headerv) { if(strcmp(headerf, "From") == 0) { if(strstr(headerv, "System Anti-Virus Administrator") || (strncasecmp(headerv, "mailsweeper@", 12) == 0) || strstr(headerv, "amavisd-new")) { smfi_setreply(ctx, "554", "5.7.1", "Forged bounce message not accepted - update your virus scanner"); syslog(LOG_NOTICE, "Blocked by blacklist-milter"); return SMFIS_REJECT; } } else if(strcmp(headerf, "Subject") == 0) { if((strcmp(headerv, "Virus in mail from you.") == 0) || (strcmp(headerv, "MailMarshal has detected a Virus in your message") == 0) || (strcmp(headerv, "Returned due to virus") == 0) || (strstr(headerv, "antivirus system report") != NULL) || (strcmp(headerv, "Aviso: Detectado formato de ficheiros invalido.") == 0) || (strcmp(headerv, "Warning: E-mail viruses detected") == 0) || (strcmp(headerv, "Banned file: message.scr in mail from you") == 0) || (strcmp(headerv, "AtenciĆ³n: Virus detectado en e-mail") == 0) || (strcmp(headerv, "Banned file: \"message_user.txt .pif\" in mail from you") == 0) || (strncmp(headerv, " Returned due to virus", 22) == 0) || (strncmp(headerv, "Virus Detected by ", 18) == 0) || (strcmp(headerv, "Virus Blocked") == 0) || (strcmp(headerv, "**Virus in mail from you**") == 0) || (strncmp(headerv, "[avast! - INFECTED]", 19) == 0) || (strstr(headerv, "ANTIVIRUS Notification") != NULL) || (strcmp(headerv, "VIRUS IN YOUR MAIL") == 0)) { smfi_setreply(ctx, "554", "5.7.1", "Forged bounce message not accepted - update your virus scanner"); syslog(LOG_NOTICE, "Blocked by blacklist-milter"); return SMFIS_REJECT; } } return SMFIS_CONTINUE; }
/*}}}*/ } priv_t; static char * xfree (char *s) /*{{{*/ { if (s) free (s); return NULL; }/*}}}*/ static bool_t xcopy (char **buf, const char *str) /*{{{*/ { if (*buf) free (*buf); *buf = str ? strdup (str) : NULL; return (! str) || *buf ? true : false; }/*}}}*/ static void priv_clear (priv_t *p) /*{{{*/ { if (p) { p -> x_agn = 0; p -> from = xfree (p -> from); p -> receiver = charc_free_all (p -> receiver); p -> prev = NULL; p -> info = xfree (p -> info); } }/*}}}*/ static priv_t * priv_free (priv_t *p) /*{{{*/ { if (p) { priv_clear (p); if (p -> lg) log_free (p -> lg); if (p -> cfg) cfg_free (p -> cfg); free (p); } return NULL; }/*}}}*/ static priv_t * priv_alloc (void) /*{{{*/ { priv_t *p; if (p = (priv_t *) malloc (sizeof (priv_t))) if (p -> cfg = cfg_alloc (cfgfile)) { p -> is_local = false; p -> x_agn = 0; p -> from = NULL; p -> receiver = NULL; p -> prev = NULL; p -> info = NULL; if (! (p -> lg = log_alloc (NULL, program, loglevel))) p = priv_free (p); } else { free (p); p = NULL; } return p; }/*}}}*/ static bool_t priv_setfrom (priv_t *p, const char *from) /*{{{*/ { return xcopy (& p -> from, from); }/*}}}*/ static bool_t priv_setto (priv_t *p, const char *to) /*{{{*/ { charc_t *r; if (r = charc_alloc (to)) { if (p -> prev) p -> prev -> next = r; else p -> receiver = r; p -> prev = r; } return r ? true : false; }/*}}}*/ static bool_t priv_addinfo (priv_t *p, const char *info) /*{{{*/ { char *temp; if ((! p -> info) || (! p -> info[0])) return xcopy (& p -> info, info); if (temp = malloc (strlen (p -> info) + strlen (info) + 2)) { sprintf (temp, "%s,%s", p -> info, info); free (p -> info); p -> info = temp; return true; } return false; }/*}}}*/ static bool_t priv_addinfopair (priv_t *p, const char *var, const char *val) /*{{{*/ { bool_t rc; char *scratch, *ptr; if (scratch = malloc (strlen (var) + strlen (val) + 2)) { for (ptr = scratch; *var; *ptr++ = *var++) ; *ptr++ = '='; for (;*val; ++val) *ptr++ = *val == ',' ? '_' : *val; *ptr = '\0'; rc = priv_addinfo (p, scratch); free (scratch); } else rc = false; return rc; }/*}}}*/ static sfsistat handle_connect (SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) /*{{{*/ { priv_t *p; if (! (p = priv_alloc ())) return SMFIS_TEMPFAIL; if (hostaddr -> sa_family == AF_INET) { struct sockaddr_in *iaddr = (struct sockaddr_in *) hostaddr; if (ntohl (iaddr -> sin_addr.s_addr) == INADDR_LOOPBACK) p -> is_local = true; } # ifdef AF_INET6 else if (hostaddr -> sa_family == AF_INET6) { struct sockaddr_in6 *i6addr = (struct sockaddr_in6 *) hostaddr; static struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT; if (memcmp (& i6addr -> sin6_addr, & loopback, sizeof (i6addr -> sin6_addr)) == 0) p -> is_local = true; } # endif /* AF_INET6 */ smfi_setpriv (ctx, p); return SMFIS_CONTINUE; }/*}}}*/ static sfsistat handle_from (SMFICTX *ctx, char **argv) /*{{{*/ { priv_t *p = (priv_t *) smfi_getpriv (ctx); if (! p) return SMFIS_TEMPFAIL; priv_clear (p); if (! priv_setfrom (p, argv[0])) return SMFIS_TEMPFAIL; priv_addinfopair (p, "from", argv[0]); return SMFIS_CONTINUE; }/*}}}*/ static sfsistat handle_to (SMFICTX *ctx, char **argv) /*{{{*/ { priv_t *p = (priv_t *) smfi_getpriv (ctx); char *chk, *opt; bool_t reject, tempfail; if (! p) return SMFIS_TEMPFAIL; if (p -> is_local) return SMFIS_CONTINUE; if (! (chk = cfg_valid_address (p -> cfg, argv[0]))) { log_out (p -> lg, LV_ERROR, "Unable to setup initial data for `%s'", argv[0]); return SMFIS_TEMPFAIL; } if (opt = strchr (chk, ':')) *opt++ = '\0'; reject = false; tempfail = false; if (! strcmp (chk, ID_REJECT)) reject = true; else if (! strcmp (chk, ID_TEMPFAIL)) tempfail = true; else if ((! strcmp (chk, ID_ACCEPT)) && opt) priv_addinfo (p, opt); priv_addinfopair (p, "to", argv[0]); free (chk); if (reject) { log_out (p -> lg, LV_INFO, "Receiver `%s' is rejected", argv[0]); smfi_setreply (ctx, (char *) "550", (char *) "5.1.1", (char *) "No such user"); return SMFIS_REJECT; } if (tempfail) { log_out (p -> lg, LV_INFO, "Receiver `%s' is temp. disbaled", argv[0]); smfi_setreply (ctx, (char *) "400", (char *) "4.0.0", (char *) "Please try again later"); return SMFIS_TEMPFAIL; } if (! priv_setto (p, argv[0])) return SMFIS_TEMPFAIL; return SMFIS_CONTINUE; }/*}}}*/
static sfsistat action_reject_msg(SMFICTX *ctx) { struct CLAMFI *cf; char buf[1024]; if(!rejectfmt || !(cf = (struct CLAMFI *)smfi_getpriv(ctx))) return SMFIS_REJECT; snprintf(buf, sizeof(buf), rejectfmt, cf->virusname); buf[sizeof(buf)-1] = '\0'; smfi_setreply(ctx, "550", "5.7.1", buf); return SMFIS_REJECT; }
int smfi_setmlreply (SMFICTX *context, const char *return_code, const char *extended_code, ...) { int result = MI_SUCCESS; GString *string = g_string_new(NULL); va_list var_args; const gchar *message; va_start(var_args, extended_code); message = va_arg(var_args, gchar *); while (message) { size_t length; length = strlen(message); if (length > MAXREPLYLEN) { milter_error("a line is too long: <%" G_GSIZE_FORMAT ">: " "max: <%d>: <%s>", length, MAXREPLYLEN, message); result = MI_FAILURE; } else if (strchr(message, '\r')) { milter_error("a line should not include '\\r': <%s>", message); result = MI_FAILURE; } if (result == MI_FAILURE) break; g_string_append(string, message); message = va_arg(var_args, gchar *); if (message) g_string_append(string, "\n"); } va_end(var_args); if (result == MI_SUCCESS) { if (string->len > 0) result = smfi_setreply(context, (char *)return_code, (char *)extended_code, string->str); } g_string_free(string, TRUE); return result; }
/*}}}*/ } priv_t; static char * xfree (char *s) /*{{{*/ { if (s) free (s); return NULL; }/*}}}*/ static bool_t xcopy (char **buf, const char *str) /*{{{*/ { if (*buf) free (*buf); *buf = str ? strdup (str) : NULL; return (! str) || *buf ? true : false; }/*}}}*/ static void priv_clear (priv_t *p) /*{{{*/ { if (p) { p -> x_agn = 0; p -> from = xfree (p -> from); p -> receiver = charc_free_all (p -> receiver); p -> prev = NULL; p -> info = xfree (p -> info); } }/*}}}*/ static priv_t * priv_free (priv_t *p) /*{{{*/ { if (p) { priv_clear (p); if (p -> lg) log_free (p -> lg); if (p -> cfg) cfg_free (p -> cfg); free (p); } return NULL; }/*}}}*/ static priv_t * priv_alloc (void) /*{{{*/ { priv_t *p; if (p = (priv_t *) malloc (sizeof (priv_t))) if (p -> cfg = cfg_alloc (cfgfile)) { p -> is_local = false; p -> x_agn = 0; p -> from = NULL; p -> receiver = NULL; p -> prev = NULL; p -> info = NULL; if (! (p -> lg = log_alloc (NULL, program, loglevel))) p = priv_free (p); } else { free (p); p = NULL; } return p; }/*}}}*/ static bool_t priv_setfrom (priv_t *p, const char *from) /*{{{*/ { return xcopy (& p -> from, from); }/*}}}*/ static bool_t priv_setto (priv_t *p, const char *to) /*{{{*/ { charc_t *r; if (r = charc_alloc (to)) { if (p -> prev) p -> prev -> next = r; else p -> receiver = r; p -> prev = r; } return r ? true : false; }/*}}}*/ static bool_t priv_addinfo (priv_t *p, const char *info) /*{{{*/ { char *temp; if ((! p -> info) || (! p -> info[0])) return xcopy (& p -> info, info); if (temp = malloc (strlen (p -> info) + strlen (info) + 2)) { sprintf (temp, "%s,%s", p -> info, info); free (p -> info); p -> info = temp; return true; } return false; }/*}}}*/ static bool_t priv_addinfopair (priv_t *p, const char *var, const char *val) /*{{{*/ { bool_t rc; char *scratch, *ptr; if (scratch = malloc (strlen (var) + strlen (val) + 2)) { for (ptr = scratch; *var; *ptr++ = *var++) ; *ptr++ = '='; for (;*val; ++val) *ptr++ = *val == ',' ? '_' : *val; *ptr = '\0'; rc = priv_addinfo (p, scratch); free (scratch); } else rc = false; return rc; }/*}}}*/ static sfsistat handle_connect (SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) /*{{{*/ { priv_t *p; if (! (p = priv_alloc ())) return SMFIS_TEMPFAIL; if (hostaddr -> sa_family == AF_INET) { struct sockaddr_in *iaddr = (struct sockaddr_in *) hostaddr; if (ntohl (iaddr -> sin_addr.s_addr) == INADDR_LOOPBACK) p -> is_local = true; } # ifdef AF_INET6 else if (hostaddr -> sa_family == AF_INET6) { struct sockaddr_in6 *i6addr = (struct sockaddr_in6 *) hostaddr; static struct in6_addr loopback = IN6ADDR_LOOPBACK_INIT; if (memcmp (& i6addr -> sin6_addr, & loopback, sizeof (i6addr -> sin6_addr)) == 0) p -> is_local = true; } # endif /* AF_INET6 */ smfi_setpriv (ctx, p); return SMFIS_CONTINUE; }/*}}}*/ static sfsistat handle_from (SMFICTX *ctx, char **argv) /*{{{*/ { priv_t *p = (priv_t *) smfi_getpriv (ctx); if (! p) return SMFIS_TEMPFAIL; priv_clear (p); if (! priv_setfrom (p, argv[0])) return SMFIS_TEMPFAIL; priv_addinfopair (p, "from", argv[0]); return SMFIS_CONTINUE; }/*}}}*/ static sfsistat handle_to (SMFICTX *ctx, char **argv) /*{{{*/ { priv_t *p = (priv_t *) smfi_getpriv (ctx); char *chk, *opt; bool_t reject, tempfail; if (! p) return SMFIS_TEMPFAIL; if (p -> is_local) return SMFIS_CONTINUE; if (! (chk = cfg_valid_address (p -> cfg, argv[0]))) { log_out (p -> lg, LV_ERROR, "Unable to setup initial data for `%s'", argv[0]); return SMFIS_TEMPFAIL; } if (opt = strchr (chk, ':')) *opt++ = '\0'; reject = false; tempfail = false; if (! strcmp (chk, ID_REJECT)) reject = true; else if (! strcmp (chk, ID_TEMPFAIL)) tempfail = true; else if ((! strcmp (chk, ID_ACCEPT)) && opt) priv_addinfo (p, opt); priv_addinfopair (p, "to", argv[0]); free (chk); if (reject) { log_out (p -> lg, LV_INFO, "Receiver `%s' is rejected", argv[0]); smfi_setreply (ctx, (char *) "550", (char *) "5.1.1", (char *) "No such user"); return SMFIS_REJECT; } if (tempfail) { log_out (p -> lg, LV_INFO, "Receiver `%s' is temp. disbaled", argv[0]); smfi_setreply (ctx, (char *) "400", (char *) "4.0.0", (char *) "Please try again later"); return SMFIS_TEMPFAIL; } if (! priv_setto (p, argv[0])) return SMFIS_TEMPFAIL; return SMFIS_CONTINUE; }/*}}}*/ static sfsistat handle_header (SMFICTX *ctx, char *field, char *value) /*{{{*/ { priv_t *p = (priv_t *) smfi_getpriv (ctx); if (! p) return SMFIS_TEMPFAIL; if (p -> is_local) return SMFIS_CONTINUE; if (! strcasecmp (field, X_LOOP)) { log_out (p -> lg, LV_WARNING, "Mail from `%s' has already loop marker set, rejected", p -> from); smfi_setreply (ctx, (char *) "500", (char *) "5.4.6", (char *) "Loop detected"); return SMFIS_REJECT; } if (! strcasecmp (field, X_AGN)) p -> x_agn++; return SMFIS_CONTINUE; }/*}}}*/
static sfsistat blacklist_body(SMFICTX *ctx, u_char *bodyp, size_t len) { char *string = malloc(len + 1); int rc, i; struct privdata *privdata; time_t now; struct bip *bip; if(string == NULL) return SMFIS_CONTINUE; if(len == 0) { /* unlikely */ free(string); return SMFIS_CONTINUE; } memcpy(string, bodyp, len); string[len] = '\0'; if(strstr(string, "One or more viruses were detected in the message") || strstr(string, "This message contains malware or a virus ") || strstr(string, "Virus Warning Message") || strstr(string, "infected with the W32/Netsky.p@MM virus and was not successfully cleaned.") || strstr(string, " contains virus W32.Email.W.NetSky.Q. Action: Deleted") || strstr(string, "Our firewall determined the e-mails containing worm copies are being sent from your computer.") || strstr(string, "The message has been blocked because it contains a component") || strstr(string, "virus(es) in your email to the following recipient(s):") || strstr(string, "An attachment in that mail was of a file type that the Spam Firewall is set to block.") || strstr(string, "Mail-Header, Mail-Body and Error Description are attached") || strstr(string, "The following email message was blocked by MailMarshal:") || strstr(string, "Il sistema antivirus ha rilevato una infezione nel messaggio:-") || strstr(string, "The original message content contained a virus or was blocked") || strstr(string, "Found virus WORM_MYDOOM.M in file ") || strstr(string, "Alerta! Posible Virus Detectado ") || strstr(string, "The following email message was blocked by ") || strstr(string, "Unrepairable Virus Detected. Your mail has not been sent.") || strstr(string, "ANTIVIRUS SYSTEM FOUND VIRUSES") || strstr(string, "An e-mail sent by you has been blocked by our automated software") || strstr(string, "Please check your system for viruses") || strstr(string, "foi rejeitado por conter virus") || strstr(string, "This is a message from the MailScanner E-Mail Virus Protection Service") || strstr(string, "was blocked by our Spam Firewall. The email you sent with the following subject ") || strstr(string, "Certain attachments are not allowed for security reasons.Your message has been rejected.")) { smfi_setreply(ctx, "554", "5.7.1", "Forged bounce message not accepted - update your virus scanner"); syslog(LOG_NOTICE, "Blocked by blacklist-milter"); rc = SMFIS_REJECT; } else rc = SMFIS_CONTINUE; free(string); privdata = smfi_getpriv(ctx); if(privdata == NULL) /* * Not the first call to blacklist_body for this message */ return rc; now = time((time_t *)0); for(i = 0, bip = bips; i < NBLACKLISTED; i++, bip++) if(strcmp(bip->ip, privdata->ip) == 0) { if((now - bip->time) < TIMEOUT) { /* * Another spam in the same connection */ syslog(LOG_NOTICE, "Rejected message from blacklisted IP %s\n", privdata->ip); smfi_setreply(ctx, "550", "5.7.1", "Your IP is blacklisted because you are sending spam"); thread_sleep(2); /* waste their time */ bip->time = now; return SMFIS_REJECT; } else /* timeout */ bip->ip[0] = '\0'; break; } if(rememberIP(ctx, privdata->ip)) return rc; free(privdata); smfi_setpriv(ctx, NULL); return SMFIS_TEMPFAIL; }
/* * Sendmail wants to establish a connection to us */ static sfsistat blacklist_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr) { const char *remoteIP; struct privdata *privdata; time_t now; int i; struct bip *bip; char ip[INET_ADDRSTRLEN]; /* IPv4 only */ if(hostname == NULL) { syslog(LOG_ERR, "blacklist_connect: hostname is null"); return SMFIS_CONTINUE; } if((hostaddr == NULL) || (&(((struct sockaddr_in *)(hostaddr))->sin_addr) == NULL)) /* * According to the sendmail API hostaddr is NULL if * "the type is not supported in the current version". What * the documentation doesn't say is the type of what. * * Possibly the input is not a TCP/IP socket e.g. stdin? */ return SMFIS_ACCEPT; remoteIP = inet_ntop(AF_INET, &((struct sockaddr_in *)(hostaddr))->sin_addr, ip, sizeof(ip)); #ifdef DEBUG printf("blacklist_milter: connection from %s\n", remoteIP); #endif syslog(LOG_INFO, "blacklist_milter: connection from %s", remoteIP); if(remoteIP == NULL) { #ifdef DEBUG puts("blacklist_connect: remoteIP is null"); #endif syslog(LOG_ERR, "blacklist_connect: remoteIP is null"); return SMFIS_CONTINUE; } if(strcmp(remoteIP, "127.0.0.1") == 0) { /*syslog(LOG_DEBUG, "blacklist_connect: not scanning outgoing messages");*/ #ifdef DEBUG puts("blacklist_connect: not scanning outgoing messages"); #endif return SMFIS_ACCEPT; } if(isLocalAddr(inet_addr(remoteIP))) { #ifdef DEBUG puts("blacklist_connect: not scanning local messages"); #endif /*syslog(LOG_DEBUG, "blacklist_connect: not scanning local messages");*/ return SMFIS_ACCEPT; } if(isWhiteList(remoteIP)) { /*syslog(LOG_DEBUG, "blacklist_connect: not scanning %s", remoteIP);*/ #ifdef DEBUG printf("blacklist_connect: not scanning %s\n", remoteIP); #endif return SMFIS_ACCEPT; } for(i = 0, bip = bips; i < NBLACKLISTED; i++, bip++) if(strcmp(bip->ip, remoteIP) == 0) { now = time((time_t *)0); if((now - bip->time) < TIMEOUT) { syslog(LOG_NOTICE, "Rejected connexion from blacklisted IP %s for %s\n", remoteIP, bip->reason); thread_sleep(2); /* waste their time */ smfi_setreply(ctx, "550", "5.7.1", "Your IP is blacklisted because you are sending spam"); bip->time = now; return SMFIS_REJECT; } else /* timeout */ bip->ip[0] = '\0'; break; } privdata = (struct privdata *)calloc(1, sizeof(struct privdata)); smfi_setpriv(ctx, privdata); strcpy(privdata->ip, remoteIP); return SMFIS_CONTINUE; }
static sfsistat cb_eom(SMFICTX *ctx) { struct context *context; sfsistat action = SMFIS_CONTINUE; char buf[2048]; int pos = 0, retry = 0; if ((context = (struct context *)smfi_getpriv(ctx)) == NULL) { msg(LOG_ERR, NULL, "cb_eom: smfi_getpriv"); return (SMFIS_ACCEPT); } msg(LOG_DEBUG, context, "cb_eom()"); if (context->fd < 0) goto done; context->symbols[0] = 0; /* no more writing data to spamd, want to read result now */ if (shutdown(context->fd, SHUT_WR)) { msg(LOG_ERR, context, "cb_eom: shutdown: %s", strerror(errno)); goto done; } if (fcntl(context->fd, F_SETFL, fcntl(context->fd, F_GETFL) | O_NONBLOCK)) { msg(LOG_ERR, context, "cb_eom: fcntl: %s", strerror(errno)); goto done; } /* try at most 6 times (10 seconds timeout each) */ while (action == SMFIS_CONTINUE && retry < 6) { fd_set fds; struct timeval tv; int r, i; char b[8192]; FD_ZERO(&fds); FD_SET(context->fd, &fds); tv.tv_sec = 10; tv.tv_usec = 0; r = select(context->fd + 1, &fds, NULL, NULL, &tv); if (r < 0) { if (errno != EINTR) { msg(LOG_ERR, context, "cb_eom: select: %s", strerror(errno)); break; } continue; } else if (r == 0 || !FD_ISSET(context->fd, &fds)) { retry++; msg(LOG_DEBUG, context, "cb_eom: waiting for " "spamd reply (retry %d)", retry); continue; } r = read(context->fd, b, sizeof(b)); if (r < 0) { if (errno != EINTR) { msg(LOG_ERR, context, "cb_eom: read: %s", strerror(errno)); break; } continue; } else if (r == 0) /* connection closed by spamd */ break; for (i = 0; i < r; ++i) if (b[i] == '\n' || pos == sizeof(buf) - 1) { if (pos > 0 && buf[pos - 1] == '\r') buf[pos - 1] = 0; else buf[pos] = 0; /* sets action when done */ spamd_reply(buf, context, &action); pos = 0; } else buf[pos++] = b[i]; } if (retry == 6) msg(LOG_ERR, context, "cb_eom: spamd connection timed out"); done: if (context->fd >= 0) { close(context->fd); context->fd = -1; } /* either way, we don't want to continue */ if (action == SMFIS_CONTINUE) action = (context->spam && context->score > REJECT_SPAM_LEVEL) ? SMFIS_REJECT : SMFIS_ACCEPT; msg(action == SMFIS_REJECT ? LOG_NOTICE : LOG_INFO, context, "%s (%s %.1f/%.1f%s%s), From: %s, To: %s, Subject: %s", (action == SMFIS_REJECT ? "REJECT" : "ACCEPT"), (context->spam ? "SPAM" : "ham"), context->score, context->threshold, (context->symbols[0] ? " " : ""), context->symbols, context->hdr_from, context->hdr_to, context->hdr_subject); if (action == SMFIS_REJECT) { char m[1024]; snprintf(m, sizeof(m), "Spam (score %.1f)", context->score); if (smfi_setreply(ctx, RCODE_REJECT, XCODE_REJECT, m) != MI_SUCCESS) msg(LOG_ERR, context, "smfi_setreply"); } else { char m[1024]; int j=0; int starcnt = (int)context->score; const char *star = "*"; char stars[1024]; stars[0]='\0'; snprintf(m, sizeof(m), "%s, %s%.1f %s%.1f%s%s", (context->spam ? "Yes" : "No"),"score=", context->score, "required=",context->threshold, (context->symbols[0] ? " " : ""), context->symbols); if (smfi_addheader(ctx, "X-Spam-Flag", context->spam ? "YES" : "NO") != MI_SUCCESS) { msg(LOG_ERR, context, "smfi_addheader"); } if (smfi_addheader(ctx, "X-Spam-Status", m) != MI_SUCCESS) { msg(LOG_ERR, context, "smfi_addheader"); } for (j = 0; j < starcnt; j++) { strlcat(stars, star, sizeof (stars)); } if (smfi_addheader(ctx, "X-Spam-Level", stars) != MI_SUCCESS) { msg(LOG_ERR, context, "smfi_addheader"); } } context->pos = context->hdr_from[0] = context->hdr_to[0] = context->hdr_subject[0] = context->state = context->spam = context->symbols[0] = 0; context->score = context->threshold = 0.0; return (action); }
static sfsistat mlfi_dnslcheck(SMFICTX * ctx) { struct mlfiPriv *priv = GETCONTEXT(ctx); struct listNode *blp; uint8_t blisted; struct listNode *wlp; uint8_t wlisted; size_t len; char *msg; uint8_t a = (priv->hostaddr & 0xff000000) >> 24; uint8_t b = (priv->hostaddr & 0x00ff0000) >> 16; uint8_t c = (priv->hostaddr & 0x0000ff00) >> 8; uint8_t d = (priv->hostaddr & 0x000000ff); switch (a) { /* Loopback */ case 127: priv->stamp = STAMP_SKIPPED; return SMFIS_CONTINUE; break; /* RFC1910 (Private networks) */ case 10: /* Class A (10.0.0.0/8) */ priv->stamp = STAMP_SKIPPED; return SMFIS_CONTINUE; break; case 172: /* Class B (172.16.0.0/12) */ if ((b & 0xf0) == 0x10) { priv->stamp = STAMP_SKIPPED; return SMFIS_CONTINUE; } break; case 192: /* Class C (192.168.0.0/16) */ if (b == 168) { priv->stamp = STAMP_SKIPPED; return SMFIS_CONTINUE; } break; default: break; } /* blacklist */ blp = blacklist; blisted = 0; while ((blp != NULL) && (blisted == 0)) { #ifdef DEBUG mlog(LOG_DEBUG, "%s: Looking up %u.%u.%u.%u.%s.", (priv->msgid != NULL)? priv->msgid : priv->connectfrom, d, c, b, a, blp->dnsl); #endif if (dns_check(a, b, c, d, blp->dnsl) == DNSL_EXIST) { mlog(LOG_INFO, "%s: %s [%u.%u.%u.%u] is blacklisted on %s", (priv->msgid != NULL)? priv->msgid : priv->connectfrom, priv->connectfrom, a, b, c, d, blp->dnsl); blisted = 1; } else blp = blp->next; } if (blisted == 0) { priv->stamp = STAMP_PASSED; return SMFIS_CONTINUE; } /* whitelist */ wlp = whitelist; wlisted = 0; while ((wlp != NULL) && (wlisted == 0)) { #ifdef DEBUG mlog(LOG_DEBUG, "%s: Looking up %u.%u.%u.%u.%s.", (priv->msgid != NULL)? priv->msgid : priv->connectfrom, d, c, b, a, wlp->dnsl); #endif if (dns_check(a, b, c, d, wlp->dnsl) == DNSL_EXIST) { mlog(LOG_INFO, "%s: %s [%u.%u.%u.%u] is whitelisted on %s", (priv->msgid != NULL)? priv->msgid : priv->connectfrom, priv->connectfrom, a, b, c, d, wlp->dnsl); wlisted = 1; } else wlp = wlp->next; } if (wlisted != 0) { priv->stamp = STAMP_WHITELISTED; return SMFIS_CONTINUE; } priv->stamp = STAMP_BLACKLISTED; if(config.drymode) return SMFIS_CONTINUE; /* "Client address [aaa.bbb.ccc.ddd] blocked. " + msg + "aaa.bbb.ccc.ddd" + '\0' */ len = 43 + strlen(blp->msg) + 15 + 1; msg = malloc(len); if (msg == NULL) { mlog(LOG_ERR, "%s: %s: Memory allocation failed", (priv->msgid != NULL)? priv->msgid : priv->connectfrom, "mlfi_dnslcheck()"); smfi_setreply(ctx, "550", "5.7.1", blp->msg); } else { snprintf(msg, len, "Client address [%u.%u.%u.%u] blocked. %s%u.%u.%u.%u", (unsigned int) a, (unsigned int) b, (unsigned int) c, (unsigned int) d, blp->msg, (unsigned int) a, (unsigned int) b, (unsigned int) c, (unsigned int) d); smfi_setreply(ctx, "550", "5.7.1", msg); free(msg); msg = NULL; } mlfi_cleanup(ctx); return SMFIS_REJECT; }