Example #1
0
File: spf.c Project: Exim/exim
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;
}
Example #2
0
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);
}
Example #3
0
File: spf.c Project: Gnitset/.bah
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;
}
Example #4
0
File: spf.c Project: fanf2/exim
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;
}
Example #5
0
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;
}
Example #6
0
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;
}
Example #7
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;  
}
Example #8
0
File: spf.c Project: badzong/mopher
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;
}