int spf_process(const uschar **listptr, uschar *spf_envelope_sender, int action) { int sep = 0; const uschar *list = *listptr; uschar *spf_result_id; int rc = SPF_RESULT_PERMERROR; if (!(spf_server && spf_request)) /* no global context, assume temp error and skip to evaluation */ rc = SPF_RESULT_PERMERROR; else if (SPF_request_set_env_from(spf_request, CS spf_envelope_sender)) /* Invalid sender address. This should be a real rare occurrence */ rc = SPF_RESULT_PERMERROR; else { /* get SPF result */ if (action == SPF_PROCESS_FALLBACK) { SPF_request_query_fallback(spf_request, &spf_response, CS spf_guess); spf_result_guessed = TRUE; } else SPF_request_query_mailfrom(spf_request, &spf_response); /* set up expansion items */ spf_header_comment = US SPF_response_get_header_comment(spf_response); spf_received = US SPF_response_get_received_spf(spf_response); spf_result = US SPF_strresult(SPF_response_result(spf_response)); spf_smtp_comment = US SPF_response_get_smtp_comment(spf_response); rc = SPF_response_result(spf_response); } /* We got a result. Now see if we should return OK or FAIL for it */ DEBUG(D_acl) debug_printf("SPF result is %s (%d)\n", SPF_strresult(rc), rc); if (action == SPF_PROCESS_GUESS && (!strcmp (SPF_strresult(rc), "none"))) return spf_process(listptr, spf_envelope_sender, SPF_PROCESS_FALLBACK); while ((spf_result_id = string_nextinlist(&list, &sep, NULL, 0))) { BOOL negate, result; if ((negate = spf_result_id[0] == '!')) spf_result_id++; result = Ustrcmp(spf_result_id, spf_result_id_list[rc].name) == 0; if (negate != result) return OK; } /* no match */ return FAIL; }
static VALUE t_query (VALUE self, VALUE map) { int retcode = SPF_RESULT_PASS; SPF_server_t *spf_server = NULL; SPF_request_t *spf_request = NULL; SPF_response_t *spf_response = NULL; SPF_response_t *spf_response_2mx = NULL; char * ip = STR2CSTR (rb_hash_aref (map,rb_str_new2 ("client_address"))); char * helo = STR2CSTR (rb_hash_aref (map,rb_str_new2 ("helo_name"))); char * sender = STR2CSTR (rb_hash_aref (map,rb_str_new2 ("sender"))); char * recipient = STR2CSTR (rb_hash_aref (map,rb_str_new2 ("recipient"))); spf_server = SPF_server_new (SPF_DNS_CACHE, 0); if (spf_server == NULL) rb_raise (rb_eRuntimeError, "can't initialize SPF library"); spf_request = SPF_request_new (spf_server); if (SPF_request_set_ipv4_str (spf_request, ip)) rb_raise (rb_eTypeError, "error, invalid IP address"); if (SPF_request_set_helo_dom (spf_request, helo)) rb_raise (rb_eTypeError, "error, invalid helo domain"); if (SPF_request_set_env_from (spf_request, sender)) rb_raise (rb_eTypeError, "error, invalid envelope from address"); SPF_request_query_mailfrom (spf_request, &spf_response); if (SPF_response_result (spf_response) != SPF_RESULT_PASS) { SPF_request_query_rcptto (spf_request, &spf_response_2mx, recipient); if (SPF_response_result (spf_response_2mx) == SPF_RESULT_PASS) { return INT2NUM(SPF_RESULT_PASS); } retcode = SPF_response_result (spf_response); } SPF_server_free(spf_server); return INT2NUM(retcode); }
int main() { int spf; char *me, *remote, *helo, *sender, *spf_env; const char *header; SPF_server_t *spf_server; SPF_request_t *spf_request; SPF_response_t *spf_response; /** * env variables **/ if (getenv("RELAYCLIENT") || /* known user */ !(spf_env = getenv("SPF"))) return 0; /* plugin disabled */ spf = atoi(spf_env); if (spf < 1 || spf > 6) { if (spf > 6) fprintf(stderr, "spf: ERROR: invalid value (%d) of SPF variable\n", spf); return 0; } remote = getenv("TCPREMOTEIP"); me = getenv("TCPLOCALHOST"); if (!me) me = getenv("TCPLOCALIP"); if (!remote || !me) { /* should never happen */ fprintf(stderr, "spf: ERROR: can't get tcpserver variables\n"); if(!remote) fprintf(stderr, "spf: can't read TCPREMOTEIP\n"); else fprintf(stderr, "spf: can't read TCPLOCALHOST nor TCPLOCALIP\n"); return 0; } sender = getenv("SMTPMAILFROM"); if (!sender) { /* should never happen */ fprintf(stderr, "spf: ERROR: can't get envelope sender address\n"); fprintf(stderr, "spf: can't read SMTPMAILFROM\n"); return 0; } if (!*sender) return 0; /* null sender mail */ helo = getenv("SMTPHELOHOST"); /** * SPF **/ spf_server = SPF_server_new(SPF_DNS_CACHE, 0); if (!spf_server) { fprintf(stderr, "spf: ERROR: can't initialize libspf2\n"); return 0; } spf_request = SPF_request_new(spf_server); if (!spf_request) { fprintf(stderr, "spf: ERROR: can't initialize libspf2\n"); return 0; } if (SPF_request_set_ipv4_str(spf_request, remote)) { fprintf(stderr, "spf: can't parse TCPREMOTEIP\n"); return 0; } SPF_server_set_rec_dom(spf_server, me); if (helo) SPF_request_set_helo_dom(spf_request, helo); SPF_request_set_env_from(spf_request, sender); /* Perform actual lookup */ SPF_request_query_mailfrom(spf_request, &spf_response); /* check whether mail needn`t to be blocked */ switch (SPF_response_result(spf_response)) { case SPF_RESULT_PASS: break; case SPF_RESULT_FAIL: if (spf > 0) { block(spf_response); return 0; } break; case SPF_RESULT_SOFTFAIL: if (spf > 1) { block(spf_response); return 0; } break; case SPF_RESULT_NEUTRAL: if (spf > 2) { block(spf_response); return 0; } break; case SPF_RESULT_NONE: if (spf > 3) { block(spf_response); return 0; } break; case SPF_RESULT_TEMPERROR: case SPF_RESULT_PERMERROR: if (spf > 4) { block(spf_response); return 0; } break; #if 0 case SPF_RESULT_UNKNOWN: if (spf > 5) { block(spf_response); return 0; } break; case SPF_RESULT_UNMECH: break; #else // FIXME: UNKNOWN and UNMECH above map how? // INVALID should not ever occur, it indicates a bug. case SPF_RESULT_INVALID: if (spf > 5) { block(spf_response); return 0; } break; #endif } /* add header */ header = SPF_response_get_received_spf(spf_response); if (header) printf("H%s\n", header); else { fprintf(stderr, "spf: libspf2 library failed to produce Received-SPF header\n", SPF_strerror(SPF_response_errcode(spf_response))); /* Example taken from libspf2: */ /* fprintf ( stderr, "spf: diag: result = %s (%d)\n", SPF_strresult(SPF_response_result(spf_response)), SPF_response_result(spf_response)); fprintf ( stderr, "spf: diag: err = %s (%d)\n", SPF_strerror(SPF_response_errcode(spf_response)), SPF_response_errcode(spf_response)); for (i = 0; i < SPF_response_messages(spf_response); i++) { SPF_error_t *err = SPF_response_message(spf_response, i); fprintf ( stderr, "spf: diag: %s_msg = (%d) %s\n", (SPF_error_errorp(err) ? "warn" : "err"), SPF_error_code(err), SPF_error_message(err)); } */ } SPF_response_free(spf_response); SPF_request_free(spf_request); SPF_server_free(spf_server); return 0; }
int spf_process(uschar **listptr, uschar *spf_envelope_sender, int action) { int sep = 0; uschar *list = *listptr; uschar *spf_result_id; uschar spf_result_id_buffer[128]; int rc = SPF_RESULT_PERMERROR; if (!(spf_server && spf_request)) { /* no global context, assume temp error and skip to evaluation */ rc = SPF_RESULT_PERMERROR; goto SPF_EVALUATE; }; if (SPF_request_set_env_from(spf_request, CS spf_envelope_sender)) { /* Invalid sender address. This should be a real rare occurence */ rc = SPF_RESULT_PERMERROR; goto SPF_EVALUATE; } /* get SPF result */ if (action == SPF_PROCESS_FALLBACK) SPF_request_query_fallback(spf_request, &spf_response, CS spf_guess); else SPF_request_query_mailfrom(spf_request, &spf_response); /* set up expansion items */ spf_header_comment = (uschar *)SPF_response_get_header_comment(spf_response); spf_received = (uschar *)SPF_response_get_received_spf(spf_response); spf_result = (uschar *)SPF_strresult(SPF_response_result(spf_response)); spf_smtp_comment = (uschar *)SPF_response_get_smtp_comment(spf_response); rc = SPF_response_result(spf_response); /* We got a result. Now see if we should return OK or FAIL for it */ SPF_EVALUATE: debug_printf("SPF result is %s (%d)\n", SPF_strresult(rc), rc); if (action == SPF_PROCESS_GUESS && (!strcmp (SPF_strresult(rc), "none"))) return spf_process(listptr, spf_envelope_sender, SPF_PROCESS_FALLBACK); while ((spf_result_id = string_nextinlist(&list, &sep, spf_result_id_buffer, sizeof(spf_result_id_buffer))) != NULL) { int negate = 0; int result = 0; /* Check for negation */ if (spf_result_id[0] == '!') { negate = 1; spf_result_id++; }; /* Check the result identifier */ result = Ustrcmp(spf_result_id, spf_result_id_list[rc].name); if (!negate && result==0) return OK; if (negate && result!=0) return OK; }; /* no match */ return FAIL; }
int main( int argc, char *argv[] ) { SPF_client_options_t *opts; SPF_client_request_t *req = NULL; SPF_server_t *spf_server = NULL; SPF_request_t *spf_request = NULL; SPF_response_t *spf_response = NULL; SPF_response_t *spf_response_2mx = NULL; SPF_errcode_t err; int opt_keep_comments = 0; #ifdef TO_MX char *p, *p_end; #endif int request_limit=0; int major, minor, patch; int res = 0; int c; const char *partial_result; char *result = NULL; int result_len = 0; char hostname[255]; char pf_result[100]; struct hostent *fullhostname; /* Figure out our name */ progname = strrchr(argv[0], '/'); if (progname != NULL) ++progname; else progname = argv[0]; /*open syslog*/ openlog(progname, LOG_PID|LOG_CONS|LOG_NDELAY|LOG_NOWAIT, LOG_MAIL); /* Redefine libSPF2 output routines to go to syslog */ SPF_error_handler = SPF_error_syslog; SPF_warning_handler = SPF_warning_syslog; SPF_info_handler = SPF_info_syslog; SPF_debug_handler = SPF_debug_syslog; opts = (SPF_client_options_t *)malloc(sizeof(SPF_client_options_t)); memset(opts, 0, sizeof(SPF_client_options_t)); /* * check the arguments */ for (;;) { int option_index; /* Largely unused */ c = getopt_long_only (argc, argv, "f:i:s:h:r:lt::gemcnd::kz:a:v", long_options, &option_index); if (c == -1) break; switch (c) { case 'l': opts->localpolicy = optarg; break; case 't': if (optarg == NULL) opts->use_trusted = 1; else opts->use_trusted = atoi(optarg); break; case 'g': opts->fallback = optarg; break; case 'e': opts->explanation = optarg; break; case 'm': opts->max_lookup = atoi(optarg); break; case 'c': /* "clean" */ opts->sanitize = atoi(optarg); break; case 'n': /* name of host doing SPF checking */ opts->rec_dom = optarg; break; case 'a': unimplemented('a'); break; case 'z': unimplemented('z'); break; case 'v': fprintf( stderr, "policyd-spf-fs version information:\n" ); fprintf( stderr, "policyd-spf-fs version: $Rev: 27 $\n"); fprintf( stderr, "SPF test system version: %s\n", SPF_TEST_VERSION ); fprintf( stderr, "Compiled with SPF library version: %d.%d.%d\n", SPF_LIB_VERSION_MAJOR, SPF_LIB_VERSION_MINOR, SPF_LIB_VERSION_PATCH ); SPF_get_lib_version( &major, &minor, &patch ); fprintf( stderr, "Running with SPF library version: %d.%d.%d\n", major, minor, patch ); fprintf( stderr, "\n" ); FAIL_ERROR; break; case 0: case '?': help(); FAIL_ERROR; break; case 'k': opt_keep_comments = 1; break; case 'd': if (optarg == NULL) opts->debug = 1; else opts->debug = atoi( optarg ); break; default: fprintf( stderr, "Error: getopt returned character code 0%o ??\n", c); FAIL_ERROR; } } if (optind != argc) { help(); FAIL_ERROR; } if (!opts->rec_dom) { gethostname(hostname, 255); fullhostname = gethostbyname(hostname); if (opts->debug > 1) syslog(LOG_DEBUG, "Hostname: %s\n",fullhostname->h_name); opts->rec_dom = fullhostname->h_name; } /* * set up the SPF configuration */ spf_server = SPF_server_new(SPF_DNS_CACHE, opts->debug > 2 ? opts->debug-2 : 0); if ( opts->rec_dom ) SPF_server_set_rec_dom( spf_server, opts->rec_dom ); if ( opts->sanitize ) SPF_server_set_sanitize( spf_server, opts->sanitize ); if ( opts->max_lookup ) SPF_server_set_max_dns_mech(spf_server, opts->max_lookup); if (opts->localpolicy) { err = SPF_server_set_localpolicy( spf_server, opts->localpolicy, opts->use_trusted, &spf_response); if ( err ) { response_print_errors("Error setting local policy", spf_response, err); WARN_ERROR; } FREE_RESPONSE(spf_response); } if ( !opts->explanation ) { opts->explanation = DEFAULT_EXPLANATION; } err = SPF_server_set_explanation( spf_server, opts->explanation, &spf_response ); if ( err ) { response_print_errors("Error setting default explanation", spf_response, err); WARN_ERROR; } FREE_RESPONSE(spf_response); /* * process the SPF request */ request_limit=0; while ( request_limit < REQUEST_LIMIT ) { request_limit++; if (request_limit == 0) { free(req); } req = (SPF_client_request_t *)malloc(sizeof(SPF_client_request_t)); memset(req, 0, sizeof(SPF_client_request_t)); if (read_request_from_pf(opts, req)) { syslog(LOG_WARNING, "IO Closed while reading, exiting"); EXIT_OK; } if (opts->debug > 1) syslog(LOG_DEBUG, "Reincarnation %d\n", request_limit); /* We have to do this here else we leak on CONTINUE_ERROR */ FREE_REQUEST(spf_request); FREE_RESPONSE(spf_response); spf_request = SPF_request_new(spf_server); if (SPF_request_set_ipv4_str(spf_request, req->ip) && SPF_request_set_ipv6_str(spf_request, req->ip)) { syslog(LOG_WARNING, "Invalid IP address.\n" ); CONTINUE_ERROR; } if (req->helo) { if (SPF_request_set_helo_dom( spf_request, req->helo ) ) { syslog(LOG_WARNING, "Invalid HELO domain.\n" ); CONTINUE_ERROR; } } if (strchr(req->sender, '@') > 0) { if (SPF_request_set_env_from( spf_request, req->sender ) ) { syslog(LOG_WARNING, "Invalid envelope from address.\n" ); CONTINUE_ERROR; } } else { /* This is something we can not check*/ CONTINUE_DUNNO("no valid email address found"); } err = SPF_request_query_mailfrom(spf_request, &spf_response); if (opts->debug > 1) response_print("Main query", spf_response); if (err) { if (opts->debug > 1) response_print_errors("Failed to query MAIL-FROM", spf_response, err); CONTINUE_DUNNO("no SPF record found"); } if (result != NULL) result[0] = '\0'; APPEND_RESULT(SPF_response_result(spf_response)); #ifdef TO_MX /* This code returns usualy neutral and oferwrites a fail from the above spf code which is not what we like. So we disable it for the time deing ... */ if (req->rcpt_to != NULL && *req->rcpt_to != '\0' ) { p = req->rcpt_to; p_end = p + strcspn(p, ",;"); /* This is some incarnation of 2mx mode. */ while (SPF_response_result(spf_response)!=SPF_RESULT_PASS) { if (*p_end) *p_end = '\0'; else p_end = NULL; /* Note this is last rcpt */ err = SPF_request_query_rcptto(spf_request, &spf_response_2mx, p); if (opts->debug > 1) response_print("2mx query", spf_response_2mx); if (err) { response_print_errors("Failed to query RCPT-TO", spf_response, err); CONTINUE_ERROR; } /* append the result */ APPEND_RESULT(SPF_response_result(spf_response_2mx)); spf_response = SPF_response_combine(spf_response, spf_response_2mx); if (!p_end) break; p = p_end + 1; } } #endif /* TO_MX */ /* We now have an option to call SPF_request_query_fallback */ if (opts->fallback) { err = SPF_request_query_fallback(spf_request, &spf_response, opts->fallback); if (opts->debug > 1) response_print("fallback query", spf_response_2mx); if (err) { response_print_errors("Failed to query best-guess", spf_response, err); CONTINUE_ERROR; } /* append the result */ APPEND_RESULT(SPF_response_result(spf_response_2mx)); spf_response = SPF_response_combine(spf_response, spf_response_2mx); } /* printf( "R: %s\nSC: %s\nHC: %s\nRS: %s\n", result, X_OR_EMPTY(SPF_response_get_smtp_comment(spf_response)), X_OR_EMPTY(SPF_response_get_header_comment(spf_response)), X_OR_EMPTY(SPF_response_get_received_spf(spf_response)) ); */ pf_response(opts, spf_response, req); res = SPF_response_result(spf_response); fflush(stdout); } error: FREE(result, free); FREE_RESPONSE(spf_response); FREE_REQUEST(spf_request); FREE(spf_server, SPF_server_free); syslog(LOG_INFO, "Terminating with result %d, Reincarnation: %d\n", res, request_limit); return res; }
int spfc(thread_pool_t *info, thread_ctx_t *thread_ctx, edict_t *edict) { struct timespec ts, start, now, timeleft; chkresult_t *result; grey_tuple_t *request; SPF_server_t *spf_server = NULL; SPF_request_t *spf_request = NULL; SPF_response_t *spf_response = NULL; SPF_response_t *spf_response_2mx = NULL; const char *smtp_error; int ret; logstr(GLOG_DEBUG, "spfc called"); request = (grey_tuple_t *)edict->job; assert(request); result = (chkresult_t *)Malloc(sizeof(chkresult_t)); memset(result, 0, sizeof(*result)); result->judgment = J_UNDEFINED; result->checkname = "spf"; /* initialize if we are not yet initialized */ if (NULL == thread_ctx->state) { /* Initialize */ spf_server = SPF_server_new(SPF_DNS_CACHE, SPF_DEBUG_LEVEL); if (NULL == spf_server) { logstr(GLOG_ERROR, "SPF_server_new failed"); goto FINISH; } thread_ctx->state = spf_server; thread_ctx->cleanup = &cleanup_spfc; } else { spf_server = (SPF_server_t *) thread_ctx->state; } /* Now we are ready to query */ ret = SPF_server_set_explanation(spf_server, "Please see http://www.openspf.org/Why?id=%{S}&ip=%{C}", &spf_response); if (ret) logstr(GLOG_ERROR, "SPF: setting explanation failed"); spf_request = SPF_request_new(spf_server); ret = SPF_request_set_ipv4_str(spf_request, request->client_address); if (ret) { logstr(GLOG_ERROR, "invalid IP address %s", request->client_address); goto CLEANUP; } if (request->helo_name) { ret = SPF_request_set_helo_dom(spf_request, request->helo_name); if (ret) { logstr(GLOG_ERROR, "invalid HELO domain: %s.", request->helo_name); goto CLEANUP; } } ret = SPF_request_set_env_from(spf_request, request->sender); if (ret) { logstr(GLOG_ERROR, "invalid envelope sender address %s", request->sender); goto CLEANUP; } ret = SPF_request_query_mailfrom(spf_request, &spf_response); switch (ret) { case SPF_E_SUCCESS: case SPF_E_NOT_SPF: break; default: logstr(GLOG_ERROR, "spf: sender based query failed: %s", SPF_strerror(ret)); goto CLEANUP; } /* XXX: do we need 2mx checks? */ ret = SPF_response_result(spf_response); switch (ret) { case SPF_RESULT_FAIL: result->judgment = J_BLOCK; logstr(GLOG_DEBUG, "SPF: fail"); smtp_error = SPF_response_get_smtp_comment(spf_response); if (smtp_error) result->reason = strdup(smtp_error); else result->reason = strdup("SPF: policy violation: (no message available)"); break; case SPF_RESULT_SOFTFAIL: result->judgment = J_SUSPICIOUS; logstr(GLOG_DEBUG, "SPF softfail"); result->weight = 1; /* FIXME: configurable */ break; case SPF_RESULT_PASS: result->judgment = J_UNDEFINED; logstr(GLOG_DEBUG, "SPF: pass"); break; case SPF_RESULT_NEUTRAL: result->judgment = J_UNDEFINED; logstr(GLOG_DEBUG, "SPF: neutral"); break; case SPF_RESULT_NONE: result->judgment = J_UNDEFINED; logstr(GLOG_DEBUG, "SPF: no record"); break; default: logstr(GLOG_DEBUG, "Unexpected SPF result (%d)", ret); } CLEANUP: if (spf_request) SPF_request_free(spf_request); if (spf_response) SPF_response_free(spf_response); FINISH: send_result(edict, result); logstr(GLOG_DEBUG, "spfc returning"); request_unlink(request); return 0; }
static int verify_data(spctx_t* ctx) { char ebuf[256]; int n; SPF_request_t *spf_request = NULL; char * xforwardaddr = NULL; char * xforwardhelo = NULL; if(spf_server == NULL) { /* redirect errors */ SPF_error_handler = SPF_error_syslog; SPF_warning_handler = SPF_warning_syslog; SPF_info_handler = SPF_info_syslog; SPF_debug_handler = SPF_debug_syslog; spf_server = SPF_server_new(SPF_DNS_CACHE, 1); if (spf_server == NULL) return -1; } /* trim string */ if(ctx->xforwardaddr) xforwardaddr = trim_space(ctx->xforwardaddr); if(ctx->xforwardhelo) xforwardhelo = trim_space(ctx->xforwardhelo); sp_messagex(ctx, LOG_DEBUG, "New connection: ADDR %s - MAIL FROM %s - XF-ADDR %s - XF-HELO %s", ctx->client.peername, ctx->sender, xforwardaddr, xforwardhelo); spf_request = SPF_request_new(spf_server); if( xforwardaddr ) SPF_request_set_ipv4_str( spf_request, xforwardaddr ); else if ( ctx->client.peername ) SPF_request_set_ipv4_str( spf_request, ctx->client.peername ); if( xforwardhelo ) SPF_request_set_helo_dom( spf_request, xforwardhelo ); if( ctx->sender ) SPF_request_set_env_from( spf_request, ctx->sender ); SPF_response_t *spf_response = NULL; SPF_request_query_mailfrom(spf_request, &spf_response); char hostname[100]; strncpy(hostname, SPF_request_get_rec_dom(spf_request), 99); char *result_spf = NULL; switch(SPF_response_result(spf_response)) { case SPF_RESULT_NONE: sp_messagex(ctx, LOG_DEBUG, "No SPF policy found for %s", ctx->sender); result_spf = "none"; break; case SPF_RESULT_NEUTRAL: result_spf = "neutral"; sp_messagex(ctx, LOG_DEBUG, "SPF: NEUTRAL for %s", ctx->sender); break; case SPF_RESULT_SOFTFAIL: result_spf = "softfail"; sp_messagex(ctx, LOG_DEBUG, "SPF: SOFTFAIL for %s", ctx->sender); break; case SPF_RESULT_PASS: result_spf = "pass"; sp_messagex(ctx, LOG_DEBUG, "SPF: PASS for %s", ctx->sender); break; case SPF_RESULT_FAIL: buffer_reject_message("550 SPF Reject", ebuf, sizeof(ebuf)); buffer_reject_message(SPF_response_get_smtp_comment(spf_response), ebuf, sizeof(ebuf)); final_reject_message(ebuf, sizeof(ebuf)); sp_messagex(ctx, LOG_DEBUG, "SPF FAIL for %s, ignore message", ctx->sender); SPF_response_free(spf_response); SPF_request_free(spf_request); if(sp_fail_data(ctx, ebuf) == -1) return -1; else return 0; break; case SPF_RESULT_TEMPERROR: case SPF_RESULT_PERMERROR: case SPF_RESULT_INVALID: buffer_reject_message("450 temporary failure", ebuf, sizeof(ebuf)); final_reject_message(ebuf, sizeof(ebuf)); sp_messagex(ctx, LOG_DEBUG, "TEMP ERROR or INVALID RECORD in SPF for %s", ctx->sender); SPF_response_free(spf_response); SPF_request_free(spf_request); if(sp_fail_data(ctx, ebuf) == -1) return -1; else return 0; break; }; char auth_result_spf[1025]; snprintf(auth_result_spf, 1024, "spf=%s smtp.mailfrom=%s", result_spf, ctx->sender); SPF_response_free(spf_response); SPF_request_free(spf_request); /* Tell client to start sending data */ if(sp_start_data (ctx) < 0) return -1; /* Message already printed */ /* Setup DKIM verifier */ DKIMContext ctxt; DKIMVerifyOptions vopts = {0}; vopts.nCheckPractices = 1; vopts.pfnSelectorCallback = NULL; //SelectorCallback; n = DKIMVerifyInit( &ctxt, &vopts ); /* Read data into verifier */ int len = -1; const char *buffer = 0; do { len = sp_read_data(ctx, &buffer); if(len == -1) return -1; if(len > 0) { DKIMVerifyProcess( &ctxt, buffer, len ); sp_write_data( ctx, buffer, len ); } } while(len > 0); sp_write_data( ctx, NULL, 0 ); /* Verify DKIM */ n = DKIMVerifyResults( &ctxt ); /* Get verification details */ int nSigCount = 0; DKIMVerifyDetails* pDetails; char szPolicy[512]; DKIMVerifyGetDetails(&ctxt, &nSigCount, &pDetails, szPolicy ); /* Proxy based on verification results */ char auth_result_dkim[1025]; if(nSigCount == 0) { sp_messagex(ctx, LOG_DEBUG, "No DKIM signature, passthrough"); snprintf(auth_result_dkim, 1024, "dkim=none"); } else if (n == DKIM_SUCCESS || n == DKIM_PARTIAL_SUCCESS) { sp_messagex(ctx, LOG_DEBUG, "DKIM verification: Success, adding header information"); int strpos = 0; int i=0; for(; i<nSigCount; ++i) { snprintf(&auth_result_dkim[strpos], 1024 - strpos, "%sdkim=%s header.d=%s", (i>0 ? ";\n" : ""), (pDetails[i].nResult == DKIM_SUCCESS ? "pass" : "fail"), pDetails[i].szSignatureDomain); strpos = strlen(auth_result_dkim); } } else { sp_messagex(ctx, LOG_DEBUG, "DKIM verification: Failed, report error and ignore message."); buffer_reject_message("550 DKIM Signature failed verification (http://www.dkim.org/info/dkim-faq.html)", ebuf, sizeof(ebuf)); final_reject_message(ebuf, sizeof(ebuf)); DKIMVerifyFree( &ctxt ); if(sp_fail_data(ctx, ebuf) == -1) return -1; else return 0; } DKIMVerifyFree( &ctxt ); char auth_results_header[1025]; snprintf(auth_results_header, 1024, "Authentication-Results: %s;\n %s;\n %s;", hostname, auth_result_spf, auth_result_dkim); if( sp_done_data(ctx, auth_results_header) == -1) return -1; return 0; }
static int spf(milter_stage_t stage, char *name, var_t *attrs) { SPF_request_t *req = NULL; SPF_response_t *res = NULL; SPF_response_t *res_2mx = NULL; char *helo; char *envfrom; char from[321]; char *envrcpt; char rcpt[321]; char *spfstr; char *spfreason; struct sockaddr_storage *ss; struct sockaddr_in *sin; struct sockaddr_in6 *sin6; int r; if (acl_symbol_dereference(attrs, "hostaddr", &ss, "envfrom", &envfrom, "envrcpt", &envrcpt, "helo", &helo, NULL)) { log_error("spf: acl_symbol_dereference failed"); goto error; } sin = (struct sockaddr_in *) ss; sin6 = (struct sockaddr_in6 *) ss; if (util_strmail(from, sizeof from, envfrom) == -1 || util_strmail(rcpt, sizeof rcpt, envrcpt) == -1) { log_error("spf: util_strmail failed"); goto error; } req = SPF_request_new(spf_server); if (req == NULL) { log_error("spf: SPF_request_new failed"); goto error; } /* * Set client address */ if (ss->ss_family == AF_INET6) { r = SPF_request_set_ipv6(req, sin6->sin6_addr); } else { r = SPF_request_set_ipv4(req, sin->sin_addr); } if (r) { log_error("spf: SPF_request_set_ip failed"); goto error; } /* * Set helo */ r = SPF_request_set_helo_dom(req, helo); if (r) { log_error("spf: SPF_request_set_helo_dom failed"); goto error; } /* * Set envelope from */ r = SPF_request_set_env_from(req, from); if (r) { log_error("spf_query: SPF_request_set_env_from failed"); goto error; } /* * Perform SPF query */ SPF_request_query_mailfrom(req, &res); if(SPF_response_result(res) == SPF_RESULT_PASS) { goto result; } /* * If SPF fails check if we received the email from a secondary mx. */ SPF_request_query_rcptto(req, &res_2mx, rcpt); if(SPF_response_result(res_2mx) != SPF_RESULT_PASS) { goto result; } /* * Secondary mx */ log_notice("spf: \"%s\" is a secodary mx for \"%s\"", helo, rcpt); goto exit; result: spfstr = (char *) SPF_strresult(SPF_response_result(res)); if (spfstr == NULL) { log_error("spf: SPF_strresult failed"); goto error; } spfreason = (char *) SPF_strreason(SPF_response_result(res)); if (spfreason == NULL) { log_error("spf: SPF_strreason failed"); goto error; } log_message(LOG_ERR, attrs, "spf: helo=%s from=%s spf=%s", helo, from, spfstr); if (vtable_setv(attrs, VT_STRING, "spf", spfstr, VF_KEEP, VT_STRING, "spf_reason", spfreason, VF_KEEP, VT_NULL)) { log_error("spf: vtable_setv failed"); goto error; } exit: SPF_request_free(req); SPF_response_free(res); if(res_2mx) { SPF_response_free(res_2mx); } return 0; error: if(req) { SPF_request_free(req); } if(res) { SPF_response_free(res); } if(res_2mx) { SPF_response_free(res_2mx); } return -1; }