int nc_connect_rand(int *main, int *alt, int *local) { struct CP_ENTRY *cpe = cpool_get_rand(main); if(!cpe) return 1; *local = (cpe->server->sa_family == AF_UNIX); if(*local) { char *unlinkme; if(cli_gentempfd(tempdir, &unlinkme, alt) != CL_SUCCESS) { logg("!Failed to create temporary file\n"); close(*main); return 1; } unlink(unlinkme); free(unlinkme); if(nc_send(*main, "nFILDES\n", 8)) { logg("!FD scan request failed\n"); close(*alt); close(*main); return 1; } } else { if(nc_send(*main, "nINSTREAM\n", 10)) { logg("!Failed to communicate with clamd\n"); close(*main); return 1; } } return 0; }
static sfsistat sendchunk(struct CLAMFI *cf, unsigned char *bodyp, size_t len, SMFICTX *ctx) { if(cf->totsz >= maxfilesize || len == 0) return SMFIS_CONTINUE; if(!cf->totsz) { sfsistat ret; if(nc_connect_rand(&cf->main, &cf->alt, &cf->local)) { logg("!Failed to initiate streaming/fdpassing\n"); nullify(ctx, cf, CF_NONE); return FailAction; } cf->totsz = 1; /* do not infloop */ if((ret = sendchunk(cf, (unsigned char *)"From clamav-milter\n", 19, ctx)) != SMFIS_CONTINUE) return ret; cf->totsz -= 1; } if(cf->totsz + len > maxfilesize) len = maxfilesize - cf->totsz; cf->totsz += len; if(cf->local) { while(len) { int n = write(cf->alt, bodyp, len); if (n==-1) { logg("!Failed to write temporary file\n"); nullify(ctx, cf, CF_BOTH); return FailAction; } len -= n; bodyp += n; } } else { int sendfailed = 0; if(len < CLAMFIBUFSZ - cf->bufsz) { memcpy(&cf->buffer[cf->bufsz], bodyp, len); cf->bufsz += len; } else if(len < CLAMFIBUFSZ) { memcpy(&cf->buffer[cf->bufsz], bodyp, CLAMFIBUFSZ - cf->bufsz); sendfailed = nc_send(cf->alt, cf->buffer, CLAMFIBUFSZ); len -= (CLAMFIBUFSZ - cf->bufsz); memcpy(cf->buffer, &bodyp[CLAMFIBUFSZ - cf->bufsz], len); cf->bufsz = len; } else { if(nc_send(cf->alt, cf->buffer, cf->bufsz) || nc_send(cf->alt, bodyp, len)) sendfailed = 1; cf->bufsz = 0; } if(sendfailed) { logg("!Streaming failed\n"); nullify(ctx, cf, CF_MAIN); return FailAction; } } return SMFIS_CONTINUE; }
void nc_ping_entry(struct CP_ENTRY *cpe) { int s = nc_connect_entry(cpe); char *reply; if(s>=0 && !nc_send(s, "nPING\n", 6) && (reply = nc_recv(s))) { cpe->dead = strcmp(reply, "PONG\n")!=0; free(reply); close(s); } else cpe->dead = 1; return; }
int main( int argc, char *argv[] ) { int result = FALSE; if ( ! parse_cmdline( argc, argv ) ) { usage( argv[0] ); exit( EXIT_FAILURE ); } if ( mode == MODE_GET ) result = nc_get(); if ( mode == MODE_SEND ) result = nc_send(); if ( result ) return EXIT_SUCCESS; else return EXIT_FAILURE; }
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; }
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; }