Apologies for the bad session.c in my last post as it contains some copy paste errors. Try the session.c from this email. It will print a detailed information about what the current uid is at the critical stages,
Best regards, Janos Janos SUTO wrote:
Hello Attila, this looks strange to me. I also tried the latest build with group_type=0 and clapf copied messages to the queue directory. Anyway I have modified two source files and added some extra syslog()'ing. Please overwrite these two files, send a few emails, send send the log please. Janos
/* * session.c, 2009.05.17, SJ */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <signal.h> #include <syslog.h> #include "av.h" #include <clapf.h> #ifdef NEED_MYSQL #include <mysql.h> #endif #ifdef NEED_SQLITE3 #include <sqlite3.h> #endif #ifdef NEED_LDAP #include <ldap.h> #endif #ifdef HAVE_MYDB #include "mydb.h" #endif /* * kill child if it works too long or is frozen */ void kill_child(){ syslog(LOG_PRIORITY, "child is killed by force"); exit(0); } /* * init SMTP session */ void init_session_data(struct session_data *sdata){ int i; sdata->fd = -1; memset(sdata->ttmpfile, 0, SMALLBUFSIZE); make_rnd_string(&(sdata->ttmpfile[0])); unlink(sdata->ttmpfile); memset(sdata->mailfrom, 0, SMALLBUFSIZE); memset(sdata->client_addr, 0, IPLEN); sdata->uid = 0; sdata->tot_len = 0; sdata->skip_id_check = 0; sdata->num_of_rcpt_to = 0; sdata->unknown_client = 0; sdata->blackhole = 0; sdata->need_signo_check = 0; for(i=0; i<MAX_RCPT_TO; i++) memset(sdata->rcptto[i], 0, SMALLBUFSIZE); } #ifdef HAVE_LIBCLAMAV void postfix_to_clapf(int new_sd, struct url *blackhole, struct cl_limits limits, struct cl_node *root, struct __config *cfg){ #else void postfix_to_clapf(int new_sd, struct url *blackhole, struct __config *cfg){ #endif int i, pos, n, rav=AVIR_OK, inj=ERR_REJECT, state, prevlen=0; char *p, *q, buf[MAXBUFSIZE], puf[MAXBUFSIZE], resp[MAXBUFSIZE], prevbuf[MAXBUFSIZE], last2buf[2*MAXBUFSIZE+1], acceptbuf[MAXBUFSIZE]; char email[SMALLBUFSIZE], email2[SMALLBUFSIZE]; float spaminess; struct session_data sdata; struct _state sstate; struct __config my_cfg; int is_spam, db_conn=0; int rc; struct url *a; #ifdef HAVE_ANTISPAM char spaminessbuf[MAXBUFSIZE], reason[SMALLBUFSIZE], trainbuf[SMALLBUFSIZE], whitelistbuf[SMALLBUFSIZE]; int train_mode=T_TOE, utokens; spaminess=DEFAULT_SPAMICITY; struct timezone tz; struct timeval tv_spam_start, tv_spam_stop, tv1, tv2; #endif #ifdef HAVE_LIBCLAMAV /* http://www.clamav.net/doc/latest/html/node47.html */ srand(getpid()); #endif alarm(cfg->session_timeout); signal(SIGALRM, kill_child); state = SMTP_STATE_INIT; init_session_data(&sdata); sdata.Nham = 0; sdata.Nspam = 0; #ifdef HAVE_MYDB init_mydb(cfg->mydbfile, &sdata); #endif /* open database connection */ db_conn = 0; #ifdef NEED_MYSQL rc = 1; mysql_init(&(sdata.mysql)); mysql_options(&(sdata.mysql), MYSQL_OPT_CONNECT_TIMEOUT, (const char*)&cfg->mysql_connect_timeout); mysql_options(&(sdata.mysql), MYSQL_OPT_RECONNECT, (const char*)&rc); if(mysql_real_connect(&(sdata.mysql), cfg->mysqlhost, cfg->mysqluser, cfg->mysqlpwd, cfg->mysqldb, cfg->mysqlport, cfg->mysqlsocket, 0)) db_conn = 1; else syslog(LOG_PRIORITY, "%s", ERR_MYSQL_CONNECT); #endif if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: fork()", sdata.ttmpfile); /* send 220 SMTP/LMTP banner */ #ifdef HAVE_LMTP snprintf(buf, MAXBUFSIZE-1, LMTP_RESP_220_BANNER, cfg->hostid); #else snprintf(buf, MAXBUFSIZE-1, SMTP_RESP_220_BANNER, cfg->hostid); #endif send(new_sd, buf, strlen(buf), 0); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: sent: %s", sdata.ttmpfile, buf); while((n = recvtimeout(new_sd, puf, MAXBUFSIZE, 0)) > 0){ pos = 0; /* accept mail data */ if(state == SMTP_STATE_DATA){ /* join the last 2 buffer */ memset(last2buf, 0, 2*MAXBUFSIZE+1); memcpy(last2buf, prevbuf, MAXBUFSIZE); memcpy(last2buf+prevlen, puf, MAXBUFSIZE); pos = search_in_buf(last2buf, 2*MAXBUFSIZE+1, SMTP_CMD_PERIOD, 5); if(pos > 0){ /* fix position */ pos = pos - prevlen + strlen(SMTP_CMD_PERIOD); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: period: *%s*", sdata.ttmpfile, puf+pos); /* write data only to (and including) the trailing period (.) */ write(sdata.fd, puf, pos); sdata.tot_len += pos; if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: got: (.)", sdata.ttmpfile); state = SMTP_STATE_PERIOD; /* make sure we had a successful read, 2007.11.05, SJ */ rc = fsync(sdata.fd); close(sdata.fd); if(rc){ syslog(LOG_PRIORITY, "failed writing data: %s", sdata.ttmpfile); #ifdef HAVE_LMTP for(i=0; i<sdata.num_of_rcpt_to; i++){ #endif send(new_sd, SMTP_RESP_421_ERR_WRITE_FAILED, strlen(SMTP_RESP_421_ERR_WRITE_FAILED), 0); #ifdef HAVE_LMTP } #endif memset(puf, 0, MAXBUFSIZE); goto AFTER_PERIOD; } //write_delivery_info(&sdata, cfg->workdir); /* parse message */ sstate = parse_message(sdata.ttmpfile, &sdata, cfg); if(sstate.has_base64 == 0 && cfg->always_scan_message == 0) sdata.need_scan = 0; else sdata.need_scan = 1; /* do antivirus check, if we have to */ #ifdef HAVE_ANTIVIRUS #ifdef HAVE_LIBCLAMAV rav = do_av_check(&sdata, email, email2, limits, root, cfg); #else rav = do_av_check(&sdata, email, email2, cfg); #endif #endif /* open database backend handler */ #ifdef NEED_SQLITE3 db_conn = 0; rc = sqlite3_open(cfg->sqlite3, &(sdata.db)); if(rc) syslog(LOG_PRIORITY, "%s: %s", sdata.ttmpfile, ERR_SQLITE3_OPEN); else { db_conn = 1; rc = sqlite3_exec(sdata.db, cfg->sqlite3_pragma, 0, 0, NULL); if(rc != SQLITE_OK) syslog(LOG_PRIORITY, "%s: could not set pragma", sdata.ttmpfile); } #endif #ifdef NEED_LDAP sdata.ldap = do_bind_ldap(cfg->ldap_host, cfg->ldap_user, cfg->ldap_pwd, cfg->ldap_use_tls); #endif /* copy default config from clapf.conf, to enable policy support */ memcpy(&my_cfg, cfg, sizeof(struct __config)); #ifdef HAVE_LMTP for(i=0; i<sdata.num_of_rcpt_to; i++){ #else i = 0; #endif if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: round %d in injection", sdata.ttmpfile, i); memset(acceptbuf, 0, MAXBUFSIZE); memset(email, 0, SMALLBUFSIZE); is_spam = 0; spaminess = DEFAULT_SPAMICITY; extract_email(sdata.rcptto[i], email); /* get user from 'RCPT TO:', 2008.11.24, SJ */ #ifdef HAVE_USERS get_user_from_email(&sdata, email, &my_cfg); #endif /* read policy, 2008.11.24, SJ */ #ifdef HAVE_POLICY if(sdata.policy_group > 0) get_policy(&sdata, cfg, &my_cfg); #endif if(rav == AVIR_VIRUS){ if(my_cfg.deliver_infected_email == 1) goto END_OF_SPAM_CHECK; snprintf(acceptbuf, MAXBUFSIZE-1, "%s <%s>\r\n", SMTP_RESP_550_ERR_PREF, email); if(my_cfg.silently_discard_infected_email == 1) snprintf(acceptbuf, MAXBUFSIZE-1, "250 Ok %s <%s>\r\n", sdata.ttmpfile, email); else snprintf(acceptbuf, MAXBUFSIZE-1, "550 %s %s\r\n", sdata.ttmpfile, email); goto SEND_RESULT; } #ifdef HAVE_ANTISPAM memset(reason, 0, SMALLBUFSIZE); memset(trainbuf, 0, SMALLBUFSIZE); memset(whitelistbuf, 0, SMALLBUFSIZE); memset(spaminessbuf, 0, MAXBUFSIZE); gettimeofday(&tv_spam_start, &tz); /* is it a training request? */ if(sdata.num_of_rcpt_to == 1 && (strcasestr(sdata.rcptto[0], "+spam@") || strcasestr(sdata.rcptto[0], "+ham@") || strncmp(email, "spam@", 5) == 0 || strncmp(email, "ham@", 4) == 0 ) ){ #ifdef HAVE_USERS /* get user from 'MAIL FROM:', 2008.10.25, SJ */ get_user_from_email(&sdata, email2, cfg); /* If not found, then try to get it from the RCPT TO address. This may happen if your email address is x...@mail.domain.com, but x...@domain.com is set in your email client application as your email address. In this case send training emails to xy+s...@mail.domain.com */ if(sdata.name[0] == 0) get_user_from_email(&sdata, email, cfg); /* if still not found, then let this email slip through clapf, 2009.03.12, SJ */ if(sdata.name[0] == 0) goto END_OF_SPAM_CHECK; do_training(&sdata, email, &acceptbuf[0], &my_cfg); goto SEND_RESULT; #else /* if you have not specified --with-userdb=.... then we don't know much about the recipient, so you have to do the training with spamdrop */ snprintf(spaminessbuf, MAXBUFSIZE-1, "%s%s\r\n%sTraining request\r\n", cfg->clapf_header_field, sdata.ttmpfile, cfg->clapf_header_field); goto END_OF_SPAM_CHECK; #endif } /* force spamcheck if the message sent to the blackhole */ if(sdata.blackhole == 1) my_cfg.use_antispam = 1; /* run statistical antispam check */ if(my_cfg.use_antispam == 1 && (my_cfg.max_message_size_to_filter == 0 || sdata.tot_len < my_cfg.max_message_size_to_filter) ){ #ifdef SPAMC_EMUL rc = spamc_emul(sdata.ttmpfile, sdata.tot_len, cfg); gettimeofday(&tv_spam_stop, &tz); if(rc == 1){ snprintf(spaminessbuf, MAXBUFSIZE-1, "%s%s\r\n%s%ld ms\r\n%s", // !! cfg->clapf_header_field, sdata.ttmpfile, cfg->clapf_header_field, tvdiff(tv_spam_stop, tv_spam_start)/1000, cfg->clapf_spam_header_field); spaminess = 0.99; syslog(LOG_PRIORITY, "%s: SPAM", sdata.ttmpfile); } else { snprintf(spaminessbuf, MAXBUFSIZE-1, "%s%s\r\n%s%ld ms\r\n", cfg->clapf_header_field, sdata.ttmpfile, cfg->clapf_header_field, tvdiff(tv_spam_stop, tv_spam_start)/1000); } syslog(LOG_PRIORITY, "%s: %.4f %d in %ld [ms]", sdata.ttmpfile, spaminess, sdata.tot_len, tvdiff(tv_spam_stop, tv_spam_start)/1000); goto END_OF_SPAM_CHECK; #endif #ifdef HAVE_MYDB spaminess = bayes_file(&sdata, &sstate, cfg); goto END_OF_TRAINING; #endif /* some MTAs strip our signo from the bounce. So if we would raise the spaminess * then we may commit a false positive. Thus in case of a missing signo, let * the statistical analysis decide the fate of a dummy bounce message. 2009.01.20, SJ */ if(sdata.need_signo_check == 1){ if(sstate.found_our_signo == 1){ syslog(LOG_PRIORITY, "%s: bounce message, found our signo", sdata.ttmpfile); goto END_OF_TRAINING; } else syslog(LOG_PRIORITY, "%s: looks like a bounce, but our signo is missing", sdata.ttmpfile); } if(db_conn == 1){ /* check whitelist first */ #ifdef HAVE_WHITELIST if(is_sender_on_black_or_white_list(&sdata, email2, SQL_WHITE_FIELD_NAME, SQL_WHITE_LIST, &my_cfg) == 1){ syslog(LOG_PRIORITY, "%s: sender (%s) found on whitelist", sdata.ttmpfile, email2); snprintf(whitelistbuf, SMALLBUFSIZE-1, "%sFound on whitelist\r\n", cfg->clapf_header_field); goto END_OF_TRAINING; } #endif /* then give blacklist a try */ #ifdef HAVE_BLACKLIST if(is_sender_on_black_or_white_list(&sdata, email2, SQL_BLACK_FIELD_NAME, SQL_BLACK_LIST, &my_cfg) == 1){ syslog(LOG_PRIORITY, "%s: sender (%s) found on blacklist", sdata.ttmpfile, email2); snprintf(whitelistbuf, SMALLBUFSIZE-1, "%sFound on blacklist\r\n", cfg->clapf_header_field); snprintf(acceptbuf, MAXBUFSIZE-1, "250 Ok %s <%s>\r\n", sdata.ttmpfile, email); goto SEND_RESULT; } #endif if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: running Bayesian test", sdata.ttmpfile); syslog(LOG_PRIORITY, "%s: uid=%ld", sdata.ttmpfile, sdata.uid); spaminess = bayes_file(&sdata, &sstate, &my_cfg); syslog(LOG_PRIORITY, "%s: uid=%ld", sdata.ttmpfile, sdata.uid); if(spaminess > 0.9999) snprintf(reason, SMALLBUFSIZE-1, "%s%s\r\n", cfg->clapf_header_field, MSG_ABSOLUTELY_SPAM); /* skip TUM training on a blackhole message, unless it may learn a missed spam as a good email */ if( (sdata.blackhole == 0 && my_cfg.training_mode == T_TUM && ( (spaminess >= my_cfg.spam_overall_limit && spaminess < 0.99) || (spaminess < my_cfg.max_ham_spamicity && spaminess > 0.1) )) || (my_cfg.initial_1000_learning == 1 && (sdata.Nham < NUMBER_OF_INITIAL_1000_MESSAGES_TO_BE_LEARNED || sdata.Nspam < NUMBER_OF_INITIAL_1000_MESSAGES_TO_BE_LEARNED)) ) { if(spaminess >= my_cfg.spam_overall_limit){ is_spam = 1; syslog(LOG_PRIORITY, "%s: TUM training a spam", sdata.ttmpfile); } else { is_spam = 0; syslog(LOG_PRIORITY, "%s: TUM training a ham", sdata.ttmpfile); } snprintf(trainbuf, SMALLBUFSIZE-1, "%sTUM\r\n", cfg->clapf_header_field); train_message(&sdata, &sstate, 1, is_spam, train_mode, &my_cfg); } /* training a blackhole message as spam, if we have to */ if(sdata.blackhole == 1){ snprintf(reason, SMALLBUFSIZE-1, "%s%s\r\n", cfg->clapf_header_field, MSG_BLACKHOLED); if(spaminess < 0.99){ syslog(LOG_PRIORITY, "%s: training on a blackhole message", sdata.ttmpfile); snprintf(trainbuf, SMALLBUFSIZE-1, "%sTUM on blackhole\r\n", cfg->clapf_header_field); train_message(&sdata, &sstate, MAX_ITERATIVE_TRAIN_LOOPS, 1, T_TOE, &my_cfg); } } } /* update token timestamps */ if(cfg->update_tokens == 1){ gettimeofday(&tv1, &tz); #ifdef HAVE_MYSQL utokens = update_mysql_tokens(sdata.mysql, sstate.token_hash, sdata.uid); #endif #ifdef HAVE_SQLITE3 utokens = update_sqlite3_tokens(sdata.db, sstate.token_hash); #endif gettimeofday(&tv2, &tz); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: updated %d/%ld tokens: %ld [ms]", sdata.ttmpfile, utokens, sstate.n_token, tvdiff(tv2, tv1)/1000); } END_OF_TRAINING: /* save email to queue */ #ifdef HAVE_STORE syslog(LOG_PRIORITY, "%s: uid=%ld, username=%s", sdata.ttmpfile, sdata.uid, sdata.name); if(sdata.uid > 0) save_email_to_queue(&sdata, spaminess, &my_cfg); #endif gettimeofday(&tv_spam_stop, &tz); syslog(LOG_PRIORITY, "%s: %.4f %d in %ld [ms]", sdata.ttmpfile, spaminess, sdata.tot_len, tvdiff(tv_spam_stop, tv_spam_start)/1000); if(spaminess >= cfg->spam_overall_limit){ snprintf(spaminessbuf, MAXBUFSIZE-1, "%s%.4f\r\n%s%s\r\n%s%ld ms\r\n%s%s%s%s", // !! cfg->clapf_header_field, spaminess, cfg->clapf_header_field, sdata.ttmpfile, cfg->clapf_header_field, tvdiff(tv_spam_stop, tv_spam_start)/1000, reason, trainbuf, whitelistbuf, cfg->clapf_spam_header_field); log_ham_spam_per_email(sdata.ttmpfile, email, 1); } else { snprintf(spaminessbuf, MAXBUFSIZE-1, "%s%.4f\r\n%s%s\r\n%s%ld ms\r\n%s%s%s", cfg->clapf_header_field, spaminess, cfg->clapf_header_field, sdata.ttmpfile, cfg->clapf_header_field, tvdiff(tv_spam_stop, tv_spam_start)/1000, reason, trainbuf, whitelistbuf); log_ham_spam_per_email(sdata.ttmpfile, email, 0); } } /* end of running spam check */ else { /* set a reasonable stuff if we skipped the antispam check */ snprintf(spaminessbuf, MAXBUFSIZE-1, "%s%s\r\n", cfg->clapf_header_field, sdata.ttmpfile); } END_OF_SPAM_CHECK: /* then inject message back */ if(spaminess >= my_cfg.spam_overall_limit){ /* shall we redirect the message into oblivion? 2007.02.07, SJ */ if(spaminess >= my_cfg.spaminess_oblivion_limit) inj = ERR_DROP_SPAM; else inj = inject_mail(&sdata, i, cfg->spam_smtp_addr, cfg->spam_smtp_port, spaminessbuf, &my_cfg, NULL); } else { inj = inject_mail(&sdata, i, cfg->postfix_addr, cfg->postfix_port, spaminessbuf, &my_cfg, NULL); } #else END_OF_SPAM_CHECK: inj = inject_mail(&sdata, i, cfg->postfix_addr, cfg->postfix_port, NULL, &my_cfg, NULL); #endif /* set the accept buffer */ if(inj == OK || inj == ERR_DROP_SPAM){ snprintf(acceptbuf, MAXBUFSIZE-1, "250 Ok %s <%s>\r\n", sdata.ttmpfile, email); } else if(inj == ERR_REJECT){ snprintf(acceptbuf, MAXBUFSIZE-1, "550 %s <%s>\r\n", sdata.ttmpfile, email); } else { snprintf(acceptbuf, MAXBUFSIZE-1, "451 %s <%s>\r\n", sdata.ttmpfile, email); } SEND_RESULT: send(new_sd, acceptbuf, strlen(acceptbuf), 0); if(inj == ERR_DROP_SPAM) syslog(LOG_PRIORITY, "%s: dropped spam", sdata.ttmpfile); else if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: sent: %s", sdata.ttmpfile, acceptbuf); #ifdef HAVE_LMTP } /* for */ #endif unlink(sdata.ttmpfile); //unlink(sdata.deliveryinfo); /* free state lists */ free_list(sstate.urls); clearhash(sstate.token_hash, 0); /* close database backend handler */ #ifdef NEED_SQLITE3 db_conn = 0; sqlite3_close(sdata.db); rc = SQLITE_ERROR; #endif #ifdef NEED_IN_LDAP ldap_unbind_s(sdata.ldap); #endif /* if we have nothing after the trailing (.), we can read the next command from the network */ if(puf[n-3] == '.' && puf[n-2] == '\r' && puf[n-1] == '\n') continue; /* if we left something in the puffer, we are ready to proceed to handle the additional commands, such as QUIT */ /* if we miss the trailing \r\n, ie. we need another read */ if(puf[n-2] != '\r' && puf[n-1] != '\n'){ memmove(puf, puf+pos, n-pos); memset(puf+n-pos, 0, MAXBUFSIZE-n+pos); i = recvtimeout(new_sd, buf, MAXBUFSIZE, 0); strncat(puf, buf, MAXBUFSIZE-1-n+pos); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: partial read: %s", sdata.ttmpfile, puf); pos = 0; } } /* PERIOD found */ else { write(sdata.fd, puf, n); sdata.tot_len += n; memcpy(prevbuf, puf, n); prevlen = n; continue; } } /* SMTP DATA */ AFTER_PERIOD: /* handle smtp commands */ memset(resp, 0, MAXBUFSIZE); p = &puf[pos]; while((p = split_str(p, "\r\n", buf, MAXBUFSIZE-1))){ if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: got: %s", sdata.ttmpfile, buf); // EHLO if(strncasecmp(buf, SMTP_CMD_EHLO, strlen(SMTP_CMD_EHLO)) == 0 || strncasecmp(buf, LMTP_CMD_LHLO, strlen(LMTP_CMD_LHLO)) == 0){ if(state == SMTP_STATE_INIT) state = SMTP_STATE_HELO; snprintf(buf, MAXBUFSIZE-1, SMTP_RESP_250_EXTENSIONS, cfg->hostid); strncat(resp, buf, MAXBUFSIZE-1); continue; /* FIXME: implement the ENHANCEDSTATUSCODE extensions */ } // HELO, let's play it simple for kids and grandmas ... if(strncasecmp(buf, SMTP_CMD_HELO, strlen(SMTP_CMD_HELO)) == 0){ if(state == SMTP_STATE_INIT) state = SMTP_STATE_HELO; strncat(resp, SMTP_RESP_250_OK, MAXBUFSIZE-1); continue; } // XFORWARD if(strncasecmp(buf, SMTP_CMD_XFORWARD, strlen(SMTP_CMD_XFORWARD)) == 0){ /* extract client address */ trim(buf); q = strstr(buf, "ADDR="); if(q){ snprintf(sdata.client_addr, IPLEN-1, q+5); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: client address: %s", sdata.ttmpfile, sdata.client_addr); } /* * other possible XFORWARD variables * * XFORWARD NAME=83-131-14-231.adsl.net.t-com.hr ADDR=83.131.14.231.. * XFORWARD PROTO=SMTP HELO=rhwfsvji.. */ /* note if the client is unknown, 2007.12.06, SJ */ if(strstr(buf, " NAME=unknown ")){ sdata.unknown_client = 1; } strncat(resp, SMTP_RESP_250_OK, MAXBUFSIZE-1); continue; } // MAIL FROM if(strncasecmp(buf, SMTP_CMD_MAIL_FROM, strlen(SMTP_CMD_MAIL_FROM)) == 0){ if(state != SMTP_STATE_HELO){ strncat(resp, SMTP_RESP_503_ERR, MAXBUFSIZE-1); } else { state = SMTP_STATE_MAIL_FROM; /* if we ever need the SIZE argumentum from the MAIL FROM command */ /*q = strstr(buf, " SIZE="); if(q){ *q = '\0'; i = strcspn(q+6, " \r\n"); if(i > 0){ *(q+6+i) = '\0'; if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: size of message: *%s*", sdata.ttmpfile, q+6); } }*/ snprintf(sdata.mailfrom, SMALLBUFSIZE-1, "%s\r\n", buf); memset(email2, 0, SMALLBUFSIZE); extract_email(sdata.mailfrom, email2); //snprintf(buf, MAXBUFSIZE-1, SMTP_RESP_250_210_OK, email2); strncat(resp, SMTP_RESP_250_OK, strlen(SMTP_RESP_250_OK)); if((strstr(sdata.mailfrom, "MAILER-DAEMON") || strstr(sdata.mailfrom, "<>")) && strlen(cfg->our_signo) > 3) sdata.need_signo_check = 1; } continue; } // RCPT TO if(strncasecmp(buf, SMTP_CMD_RCPT_TO, strlen(SMTP_CMD_RCPT_TO)) == 0){ if(state == SMTP_STATE_MAIL_FROM || state == SMTP_STATE_RCPT_TO){ if(sdata.num_of_rcpt_to < MAX_RCPT_TO){ //memcpy(sdata.rcptto[sdata.num_of_rcpt_to], buf, SMALLBUFSIZE-1); snprintf(sdata.rcptto[sdata.num_of_rcpt_to], SMALLBUFSIZE-1, "%s\r\n", buf); sdata.num_of_rcpt_to++; } state = SMTP_STATE_RCPT_TO; /* check against blackhole addresses */ extract_email(buf, email); if(blackhole){ a = blackhole; while(a){ if(strcmp(a->url_str, email) == 0){ syslog(LOG_PRIORITY, "we have %s on the blacklist", email); sdata.blackhole = 1; break; } a = a->r; } } /* check against DHA trap address list, 2007.11.06, SJ */ #ifdef HAVE_BLACKHOLE if(strlen(cfg->dha_trap_address_list) > 4){ if(strstr(cfg->dha_trap_address_list, email)){ syslog(LOG_PRIORITY, "%s: %s trapped with %s on my DHA list", sdata.ttmpfile, sdata.client_addr, email); put_ip_to_dir(cfg->blackhole_path, sdata.client_addr); } } #endif strncat(resp, SMTP_RESP_250_OK, MAXBUFSIZE-1); } else { strncat(resp, SMTP_RESP_503_ERR, MAXBUFSIZE-1); } continue; } // DATA if(strncasecmp(buf, SMTP_CMD_DATA, strlen(SMTP_CMD_DATA)) == 0){ memset(last2buf, 0, 2*MAXBUFSIZE+1); memset(prevbuf, 0, MAXBUFSIZE); inj = ERR_REJECT; prevlen = 0; if(state != SMTP_STATE_RCPT_TO){ strncat(resp, SMTP_RESP_503_ERR, MAXBUFSIZE-1); } else { sdata.fd = open(sdata.ttmpfile, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); if(sdata.fd == -1){ syslog(LOG_PRIORITY, "%s: %s", ERR_OPEN_TMP_FILE, sdata.ttmpfile); strncat(resp, SMTP_RESP_451_ERR, MAXBUFSIZE-1); } else { state = SMTP_STATE_DATA; strncat(resp, SMTP_RESP_354_DATA_OK, MAXBUFSIZE-1); } } continue; } // QUIT if(strncasecmp(buf, SMTP_CMD_QUIT, strlen(SMTP_CMD_QUIT)) == 0){ state = SMTP_STATE_FINISHED; snprintf(buf, MAXBUFSIZE-1, SMTP_RESP_221_GOODBYE, cfg->hostid); send(new_sd, buf, strlen(buf), 0); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: sent: %s", sdata.ttmpfile, buf); unlink(sdata.ttmpfile); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sdata.ttmpfile); goto QUITTING; } // NOOP if(strncasecmp(buf, SMTP_CMD_NOOP, strlen(SMTP_CMD_NOOP)) == 0){ strncat(resp, SMTP_RESP_250_OK, MAXBUFSIZE-1); continue; } // RSET if(strncasecmp(buf, SMTP_CMD_RESET, strlen(SMTP_CMD_RESET)) == 0){ /* we must send a 250 Ok */ strncat(resp, SMTP_RESP_250_OK, MAXBUFSIZE-1); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sdata.ttmpfile); unlink(sdata.ttmpfile); init_session_data(&sdata); state = SMTP_STATE_HELO; continue; } /* by default send 502 command not implemented message */ syslog(LOG_PRIORITY, "%s: invalid command: %s", sdata.ttmpfile, buf); strncat(resp, SMTP_RESP_502_ERR, MAXBUFSIZE-1); } /* now we can send our buffered response */ if(strlen(resp) > 0){ send(new_sd, resp, strlen(resp), 0); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: sent: %s", sdata.ttmpfile, resp); memset(resp, 0, MAXBUFSIZE); } } /* while */ /* * if we are not in SMTP_STATE_QUIT and the message was not injected, * ie. we have timed out than send back 421 error message, 2005.12.29, SJ */ if(state < SMTP_STATE_QUIT && inj != OK){ snprintf(buf, MAXBUFSIZE-1, SMTP_RESP_421_ERR, cfg->hostid); send(new_sd, buf, strlen(buf), 0); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: sent: %s", sdata.ttmpfile, buf); goto QUITTING; } QUITTING: #ifdef HAVE_MYDB close_mydb(sdata.mhash); #endif #ifdef NEED_MYSQL mysql_close(&(sdata.mysql)); #endif if(cfg->verbosity >= _LOG_INFO) syslog(LOG_PRIORITY, "child has finished"); _exit(0); }