Beispiel #1
0
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;
}
Beispiel #2
0
	/*}}}*/
}	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;
}/*}}}*/
Beispiel #3
0
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;
}
Beispiel #5
0
	/*}}}*/
}	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;
}/*}}}*/
Beispiel #6
0
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;
}
Beispiel #7
0
/*
 * 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;
}
Beispiel #8
0
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);
}
Beispiel #9
0
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;
}