sfsistat mlfi_envfrom(SMFICTX * ctx, char **argv) { struct mlfiPriv *priv = GETCONTEXT(ctx); char *msgid; /* SMTP Authenticated. Skip DNS blacklist checks */ if (smfi_getsymval(ctx, "{auth_type}") != NULL) return SMFIS_ACCEPT; /* store message ID */ msgid = smfi_getsymval(ctx, "{i}"); if (msgid != NULL) { priv->msgid = strdup(msgid); if (priv->msgid == NULL) { mlog(LOG_ERR, "%s: %s: Memory allocation failed", priv->connectfrom, "mlfi_envfrom()"); mlfi_cleanup(ctx); return SMFIS_TEMPFAIL; } } else priv->msgid = NULL; /* store sender's address */ priv->envfrom = strdup(argv[0]); if (priv->envfrom == NULL) { mlog(LOG_ERR, "%s: %s: Memory allocation failed", (priv->msgid != NULL)? priv->msgid : priv->connectfrom, "mlfi_envfrom()"); mlfi_cleanup(ctx); return SMFIS_TEMPFAIL; } #if SMFI_VERSION > 3 /* null-envelope sender address, defer DNS checks till mlfi_data() */ if (strncmp(argv[0], "<>\0", 3) == 0) { #ifdef DEBUG mlog(LOG_DEBUG, "%s: Null-envelope sender address, deferring", (priv->msgid != NULL)? priv->msgid : priv->connectfrom); #endif priv->check = 1; return SMFIS_CONTINUE; } #endif priv->check = 0; return mlfi_dnslcheck(ctx); }
static int rememberIP(SMFICTX *ctx, const char *addr) { int i; time_t now; struct ip *ip; if(smfi_getsymval(ctx, "i") == NULL) { syslog(LOG_WARNING, "Add define(`confMILTER_MACROS_ENVFROM', `i')dnl to sendmail.mc"); return 0; } now = time((time_t *)0); for(i = 0, ip = ips; i < NIDS; i++, ip++) if((ip->ip[0] != '\0' && ((now - ip->time) < TIMEOUT))) if(ip->ctx == ctx) { #ifdef DEBUG printf("rememberIP %s->%s already known\n", ip->sendmailID, addr); #endif ip->time = now; /* "touch" to put off time-outs */ return 1; } #ifdef DEBUG printf("rememberIP %s ID %s\n", addr, smfi_getsymval(ctx, "i")); #endif for(i = 0, ip = ips; i < NIDS; i++, ip++) if((ip->ip[0] == '\0' || ((now - ip->time) > TIMEOUT))) { strcpy(ip->ip, addr); strcpy(ip->sendmailID, smfi_getsymval(ctx, "i")); ip->ctx = ctx; #ifdef DEBUG printf("rememberIP %s->%s\n", ip->sendmailID, addr); #endif ip->time = now; break; } if(i == NIDS) { syslog(LOG_ERR, "blacklist_body: out of NIDS"); timeout(); return 0; } return 1; }
sfsistat clamfi_envfrom(SMFICTX *ctx, char **argv) { struct CLAMFI *cf; const char *login = smfi_getsymval(ctx, "{auth_authen}"); if(login && smtpauthed(login)) { logg("*Skipping scan for authenticated user %s\n", login); return SMFIS_ACCEPT; } if(whitelisted(argv[0], 1)) { logg("*Skipping scan for %s (whitelisted from)\n", argv[0]); return SMFIS_ACCEPT; } if(!(cf = (struct CLAMFI *)malloc(sizeof(*cf)))) { logg("!Failed to allocate CLAMFI struct\n"); return FailAction; } cf->totsz = 0; cf->bufsz = 0; cf->main = cf->alt = -1; cf->all_whitelisted = 1; cf->gotbody = 0; cf->msg_subj = cf->msg_date = cf->msg_id = NULL; if(addxvirus==1) { cf->scanned_count = 0; cf->status_count = 0; } smfi_setpriv(ctx, (void *)cf); return SMFIS_CONTINUE; }
sfsistat mlfi_data(SMFICTX * ctx) { struct mlfiPriv *priv = GETCONTEXT(ctx); char *msgid; /* In Postfix, the Sendmail macro 'i' is only available in the DATA, EOH, and EOM milter protocol stages so we try get the msgid again */ if (priv->msgid != NULL) goto check; msgid = smfi_getsymval(ctx, "{i}"); if (msgid != NULL) { priv->msgid = strdup(msgid); if (priv->msgid == NULL) { mlog(LOG_ERR, "%s: %s: Memory allocation failed", priv->connectfrom, "mlfi_data()"); mlfi_cleanup(ctx); return SMFIS_TEMPFAIL; } } check: if (priv->check != 0) return mlfi_dnslcheck(ctx); /* continue processing */ return SMFIS_CONTINUE; }
static int test_reply(SMFICTX *ctx, int code) { const char **cpp; const char *symval; for (cpp = macro_names; *cpp; cpp++) if ((symval = smfi_getsymval(ctx, (char *) *cpp)) != 0) printf("macro: %s=\"%s\"\n", *cpp, symval); (void) fflush(stdout); /* In case output redirected. */ if (code == SMFIR_REPLYCODE) { if (smfi_setmlreply(ctx, reply_code, reply_dsn, reply_message, reply_message, (char *) 0) == MI_FAILURE) fprintf(stderr, "smfi_setmlreply failed\n"); printf("test_reply %s\n", reply_code); return (reply_code[0] == '4' ? SMFIS_TEMPFAIL : SMFIS_REJECT); } else { printf("test_reply %d\n\n", code); return (code); } }
sfsistat clamfi_eom(SMFICTX *ctx) { struct CLAMFI *cf; char *reply; int len, ret; unsigned int crcpt; if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) return SMFIS_CONTINUE; /* whatever */ if(!cf->totsz) { /* got no headers and no body */ logg("*Not scanning an empty message\n"); ret = CleanAction(ctx); nullify(ctx, cf, CF_NONE); free(cf); return ret; } if(cf->local) { lseek(cf->alt, 0, SEEK_SET); if(nc_sendmsg(cf->main, cf->alt) == -1) { logg("!FD send failed\n"); nullify(ctx, cf, CF_ALT); free(cf); return FailAction; } } else { uint32_t sendmetoo = 0; cf->sendme = htonl(cf->bufsz); if((cf->bufsz && nc_send(cf->main, &cf->sendme, cf->bufsz + 4)) || nc_send(cf->main, &sendmetoo, 4)) { logg("!Failed to flush STREAM\n"); nullify(ctx, cf, CF_NONE); free(cf); return FailAction; } } reply = nc_recv(cf->main); if(cf->local) close(cf->alt); cf->alt = -1; if(!reply) { logg("!No reply from clamd\n"); nullify(ctx, cf, CF_NONE); free(cf); return FailAction; } len = strlen(reply); if(len>5 && !strcmp(reply + len - 5, ": OK\n")) { if(addxvirus) add_x_header(ctx, "Clean", cf->scanned_count, cf->status_count); if(loginfected & LOGCLN_FULL) { const char *id = smfi_getsymval(ctx, "{i}"); const char *from = smfi_getsymval(ctx, "{mail_addr}"); const char *msg_subj = makesanehdr(cf->msg_subj); const char *msg_date = makesanehdr(cf->msg_date); const char *msg_id = makesanehdr(cf->msg_id); if(multircpt && cf->nrecipients) { for(crcpt = 0; crcpt < cf->nrecipients; crcpt++) logg("~Clean message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s'\n", id, from, cf->recipients[crcpt], msg_subj, msg_id, msg_date); } else { const char *to = smfi_getsymval(ctx, "{rcpt_addr}"); logg("~Clean message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s'\n", id, from, to ? to : HDR_UNAVAIL, msg_subj, msg_id, msg_date); } } else if(loginfected & LOGCLN_BASIC) { const char *from = smfi_getsymval(ctx, "{mail_addr}"); if(multircpt && cf->nrecipients) { for(crcpt = 0; crcpt < cf->nrecipients; crcpt++) logg("~Clean message from <%s> to <%s>\n", from, cf->recipients[crcpt]); } else { const char *to = smfi_getsymval(ctx, "{rcpt_addr}"); logg("~Clean message from <%s> to <%s>\n", from, to ? to : HDR_UNAVAIL); } } ret = CleanAction(ctx); } else if (len>7 && !strcmp(reply + len - 7, " FOUND\n")) { cf->virusname = NULL; if((loginfected & (LOGINF_BASIC | LOGINF_FULL)) || addxvirus || rejectfmt || viraction) { char *vir; reply[len-7] = '\0'; vir = strrchr(reply, ' '); if(vir) { unsigned int have_multi = (multircpt != 0 && cf->nrecipients); unsigned int lst_rcpt = (have_multi * (cf->nrecipients - 1)) + 1; vir++; if(rejectfmt) cf->virusname = vir; if(addxvirus) { char msg[255]; snprintf(msg, sizeof(msg), "Infected (%s)", vir); msg[sizeof(msg)-1] = '\0'; add_x_header(ctx, msg, cf->scanned_count, cf->status_count); } for(crcpt = 0; crcpt < lst_rcpt; crcpt++) { if(loginfected || viraction) { const char *from = smfi_getsymval(ctx, "{mail_addr}"); const char *to = have_multi ? cf->recipients[crcpt] : smfi_getsymval(ctx, "{rcpt_addr}"); if(!from) from = HDR_UNAVAIL; if(!to) to = HDR_UNAVAIL; if((loginfected & LOGINF_FULL) || viraction) { const char *id = smfi_getsymval(ctx, "{i}"); const char *msg_subj = makesanehdr(cf->msg_subj); const char *msg_date = makesanehdr(cf->msg_date); const char *msg_id = makesanehdr(cf->msg_id); if(!id) id = HDR_UNAVAIL; if(loginfected & LOGINF_FULL) logg("~Message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s' infected by %s\n", id, from, to, msg_subj, msg_id, msg_date, vir); if(viraction) { char er[256]; char *e_id = strdup(id); char *e_from = strdup(from); char *e_to = strdup(to); char *e_msg_subj = strdup(msg_subj); char *e_msg_date = strdup(msg_date); char *e_msg_id = strdup(msg_id); pid_t pid; logg("*VirusEvent: about to execute '%s' '%s' '%s' '%s' '%s' '%s' '%s' '%s'\n", viraction, vir, e_id, e_from, e_to, e_msg_subj, e_msg_id, e_msg_date); pthread_mutex_lock(&virusaction_lock); pid = fork(); if(!pid) { char * args[9]; /* avoid element is not computable at load time warns */ args[0]= viraction; args[1] = vir; args[2] = e_id; args[3] = e_from; args[4] = e_to; args[5] = e_msg_subj; args[6] = e_msg_id; args[7] = e_msg_date; args[8] = NULL; exit(execvp(viraction, args)); } else if(pid > 0) { int wret; pthread_mutex_unlock(&virusaction_lock); while((wret = waitpid(pid, &ret, 0)) == -1 && errno == EINTR); if(wret<0) logg("!VirusEvent: waitpid() failed: %s\n", cli_strerror(errno, er, sizeof(er))); else { if(WIFEXITED(ret)) logg("*VirusEvent: child exited with code %d\n", WEXITSTATUS(ret)); else if(WIFSIGNALED(ret)) logg("*VirusEvent: child killed by signal %d\n", WTERMSIG(ret)); else logg("*VirusEvent: child lost\n"); } } else { logg("!VirusEvent: fork failed: %s\n", cli_strerror(errno, er, sizeof(er))); } free(e_id); free(e_from); free(e_to); free(e_msg_subj); free(e_msg_date); free(e_msg_id); } } if(loginfected & LOGINF_BASIC) logg("~Message from <%s> to <%s> infected by %s\n", from, to, vir); } } } } ret = InfectedAction(ctx); } else { logg("!Unknown reply from clamd\n"); ret = FailAction; } nullify(ctx, cf, CF_MAIN); free(cf); free(reply); return ret; }
static sfsistat cb_header(SMFICTX *ctx, char *name, char *value) { struct context *context; if ((context = (struct context *)smfi_getpriv(ctx)) == NULL) { msg(LOG_ERR, context, "cb_header: smfi_getpriv"); return (SMFIS_ACCEPT); } msg(LOG_DEBUG, context, "cb_header('%s', '%s')", name, value); if (context->fd < 0) { const char *sendmail_name = smfi_getsymval(ctx, "j"); const char *sendmail_queue = smfi_getsymval(ctx, "i"); const char *sendmail_date = smfi_getsymval(ctx, "b"); const char *auth_type = smfi_getsymval(ctx, "{auth_type}"); const char *auth_ssf = smfi_getsymval(ctx, "{auth_ssf}"); if ((context->fd = get_spamd_fd(context)) < 0) return (SMFIS_ACCEPT); fdprintf(context->fd, "SYMBOLS SPAMC/1.2\r\n"); if (spamd_user[0]) fdprintf(context->fd, "User: %s\r\n", spamd_user); fdprintf(context->fd, "\r\n"); /* send fake Received: header */ fdprintf(context->fd, "Received: from %s (%s [%s])", context->helo, context->host, context->addr); if (auth_type != NULL && auth_type[0]) { fdprintf(context->fd, "\r\n\t(authenticated"); if (auth_ssf != NULL && auth_ssf[0]) fdprintf(context->fd, " bits=%s", auth_ssf); fdprintf(context->fd, ")"); } if (sendmail_name != NULL && sendmail_name[0]) { fdprintf(context->fd, "\r\n\tby %s (milter-spamd)", sendmail_name); if (sendmail_queue != NULL && sendmail_queue[0]) fdprintf(context->fd, " id %s", sendmail_queue); } if (context->env_rcpt[0]) fdprintf(context->fd, "\r\n\tfor %s", context->env_rcpt); if (sendmail_date != NULL && sendmail_date[0]) fdprintf(context->fd, "; %s", sendmail_date); else { char d[128]; time_t t = time(NULL); if (strftime(d, sizeof(d), "%a, %e %b %Y %H:%M:%S %z", localtime(&t))) fdprintf(context->fd, "; %s", d); } fdprintf(context->fd, "\r\n"); } fdprintf(context->fd, "%s: %s\r\n", name, value); if (!strcasecmp(name, "From")) strlcpy(context->hdr_from, value, sizeof(context->hdr_from)); else if (!strcasecmp(name, "To")) strlcpy(context->hdr_to, value, sizeof(context->hdr_to)); else if (!strcasecmp(name, "Subject")) strlcpy(context->hdr_subject, value, sizeof(context->hdr_subject)); return (SMFIS_CONTINUE); }
sfsistat clamfi_eom(SMFICTX *ctx) { struct CLAMFI *cf; char *reply; int len, ret; if(!(cf = (struct CLAMFI *)smfi_getpriv(ctx))) return SMFIS_CONTINUE; /* whatever */ if(!cf->totsz) { /* got no headers and no body */ logg("*Not scanning an empty message\n"); ret = CleanAction(ctx); nullify(ctx, cf, CF_NONE); return ret; } if(cf->local) { if(nc_send(cf->main, "nFILDES\n", 8)) { logg("!FD scan request failed\n"); nullify(ctx, cf, CF_ALT); return FailAction; } lseek(cf->alt, 0, SEEK_SET); if(nc_sendmsg(cf->main, cf->alt) == -1) { logg("!FD send failed\n"); nullify(ctx, cf, CF_ALT); return FailAction; } } else { if(cf->bufsz && nc_send(cf->alt, cf->buffer, cf->bufsz)) { logg("!Failed to flush STREAM\n"); nullify(ctx, cf, CF_MAIN); return FailAction; } close(cf->alt); } reply = nc_recv(cf->main); if(cf->local) close(cf->alt); cf->alt = -1; if(!reply) { logg("!No reply from clamd\n"); nullify(ctx, cf, CF_NONE); return FailAction; } len = strlen(reply); if(len>5 && !strcmp(reply + len - 5, ": OK\n")) { if(addxvirus) add_x_header(ctx, "Clean", cf->scanned_count, cf->status_count); ret = CleanAction(ctx); } else if (len>7 && !strcmp(reply + len - 7, " FOUND\n")) { cf->virusname = NULL; if(loginfected || addxvirus || rejectfmt) { char *vir; reply[len-7] = '\0'; vir = strrchr(reply, ' '); if(vir) { vir++; if(rejectfmt) cf->virusname = vir; if(addxvirus) { char msg[255]; snprintf(msg, sizeof(msg), "Infected (%s)", vir); msg[sizeof(msg)-1] = '\0'; add_x_header(ctx, msg, cf->scanned_count, cf->status_count); } if(loginfected) { const char *from = smfi_getsymval(ctx, "{mail_addr}"); const char *to = smfi_getsymval(ctx, "{rcpt_addr}"); if(!from) from = HDR_UNAVAIL; if(!to) to = HDR_UNAVAIL; if(loginfected == LOGINF_FULL) { const char *id = smfi_getsymval(ctx, "{i}"); const char *msg_subj = makesanehdr(cf->msg_subj); const char *msg_date = makesanehdr(cf->msg_date); const char *msg_id = makesanehdr(cf->msg_id); if(!id) id = HDR_UNAVAIL; logg("~Message %s from <%s> to <%s> with subject '%s' message-id '%s' date '%s' infected by %s\n", id, from, to, msg_subj, msg_id, msg_date, vir); } else logg("~Message from <%s> to <%s> infected by %s\n", from, to, vir); } } } ret = InfectedAction(ctx); } else { logg("!Unknown reply from clamd\n"); ret = FailAction; } nullify(ctx, cf, CF_MAIN); free(reply); return ret; }