Пример #1
0
stringer_t * check_rand_mthread(void) {

	void *outcome = NULL;
	stringer_t *result = NULL;
	pthread_t *threads = NULL;

	if (!RAND_CHECK_MTHREADS) {
		return NULL;
	}
	else if (!(threads = mm_alloc(sizeof(pthread_t) * RAND_CHECK_MTHREADS))) {
		return st_dupe(NULLER("Thread allocation error."));;
	}

	for (uint64_t counter = 0; counter < RAND_CHECK_MTHREADS; counter++) {
		if (thread_launch(threads + counter, &check_rand_mthread_wrap, NULL)) {
			result = false;
		}
	}

	for (uint64_t counter = 0; counter < RAND_CHECK_MTHREADS; counter++) {
		if (thread_result(*(threads + counter), &outcome)) {
			st_cleanup(result);
			result = st_dupe(NULLER("Thread join error."));
		}
		else if (outcome) {
			st_cleanup(result);
			result = outcome;
		}
	}

	mm_free(threads);
	return result;
}
Пример #2
0
/**
 * @brief	Select a random truetype font from the directory specified in magma.http.fonts.
 * @return	NULL on failure, or a managed string containing the pathname of the randomly selected font file on success.
 */
stringer_t * register_captcha_random_font(void) {

	DIR *directory;
	stringer_t *path;
	struct dirent64 *dp;
	size_t count = 0, selection;

	// Open the current working directory.
	if (!(directory = opendir(magma.http.fonts))) {
		log_pedantic("Unable to open the font directory. { directory = %s }", magma.http.fonts);
		return NULL;
	}

	// Count the number of fonts.
	while ((dp = readdir64(directory))) {

		if (!st_cmp_ci_ends(NULLER(dp->d_name), PLACER(".ttf", 4))) {
			count++;
		}

	};

	// No fonts were found.
	if (!count) {
		log_pedantic("The web fonts directory is empty. { directory = %s }", magma.http.fonts);
		closedir(directory);
		return NULL;
	}

	// Pick a random font.
	selection = (rand_get_uint32() % count) + 1;

	// Reset the directory stream.
	rewinddir(directory);

	// Do the loop again.
	while (selection && (dp = readdir64(directory))) {

		if (!st_cmp_ci_ends(NULLER(dp->d_name), PLACER(".ttf", 4))) {
			selection--;
		}

	}

	// Build the path.
	if (selection || !dp || !(path = st_aprint("%s/%s", magma.http.fonts, dp->d_name))) {
		log_pedantic("Could not build the font file path.");
		closedir(directory);
		return NULL;
	}

	closedir(directory);
	return path;
}
Пример #3
0
int check_bsearch_months(int num, char *name) {

	struct check_mi_t *res, key;

	key.name = name;

	qsort(months, (sizeof(months) / sizeof(months[0])), sizeof(struct check_mi_t), check_bsearch_compare);
	res = bsearch(&key, months, (sizeof(months) / sizeof(months[0])), sizeof(struct check_mi_t), check_bsearch_compare);
	if (res == NULL || res->nr != num || st_cmp_cs_eq(NULLER(res->name), NULLER(name))) {
		return false;
	}
	return true;
}
Пример #4
0
/* modeled closely after args_parse() */
void check_args_parse(int argc, char *argv[]) {

	int_t i = 1;

	while (i < argc) {

		if (!st_cmp_cs_eq(NULLER(argv[i]), PLACER("-v", 2))) {

			if (!(virus_check_data_path = check_next_opt(argv, &i, argc))) {
				do_virus_check = false;
			}

		}
		else if (!st_cmp_cs_eq(NULLER(argv[i]), PLACER("-t", 2))) {

			if (!(tank_check_data_path = check_next_opt(argv, &i, argc))) {
				do_tank_check = false;
			}

		}
		else if (!st_cmp_cs_eq(NULLER(argv[i]), PLACER("-d", 2))) {

			if (!(dspam_check_data_path = check_next_opt(argv, &i, argc))) {
				do_dspam_check = false;
			}

		}
		else if (!st_cmp_cs_eq(NULLER(argv[i]), PLACER("-s", 2))) {
			do_spf_check = false;
			i++;
		}
		// See if it's an illegal parameter beginning with "-"
		else if (!mm_cmp_cs_eq(argv[i], "-", 1)) {
			check_display_usage(argv[0]);
		}
		// Otherwise it's the config file
		else if (i == (argc-1)) {
			snprintf(magma.config.file, MAGMA_FILEPATH_MAX, "%s", argv[i]);
			i++;
		}
		else {
			check_display_usage(argv[0]);
		}

	}

	return;
}
Пример #5
0
stringer_t * check_rand_sthread(void) {

	size_t len;
	uint64_t num = 0;
	stringer_t *buffer;

	if (!(buffer = st_alloc(RAND_CHECK_SIZE_MAX))) {
		return st_dupe(NULLER("Buffer allocation error."));
	}

	for (int_t i = 0; status() && i < RAND_CHECK_ITERATIONS; i++) {

		num |= rand_get_int8();
		num |= rand_get_int16();
		num |= rand_get_int32();
		num |= rand_get_int64();

		num |= rand_get_uint8();
		num |= rand_get_uint16();
		num |= rand_get_uint32();
		num |= rand_get_uint64();

		// Pick a random length.
		len = (rand() % (RAND_CHECK_SIZE_MAX - RAND_CHECK_SIZE_MIN)) + RAND_CHECK_SIZE_MIN;

		if (rand_write(PLACER(st_char_get(buffer), len)) != len) {
			st_cleanup(buffer);
			return st_dupe(NULLER("Unable to fill the buffer with random data."));
		}
	}

	st_cleanup(buffer);

	// This time through we use the choices function since it will allocate its own output buffer.
	for (int_t i = 0; status() && i < RAND_CHECK_ITERATIONS; i++) {

		// Pick a random length.
		len = (rand() % (RAND_CHECK_SIZE_MAX - RAND_CHECK_SIZE_MIN)) + RAND_CHECK_SIZE_MIN;

		if (!(buffer = rand_choices("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", len))) {
			return st_dupe(NULLER("Unable to fill the buffer with random data."));
		}
		st_free(buffer);
	}

	return NULL;
}
Пример #6
0
/**
 * @brief	Provide the SSL/TLS/DTLS version as a string constant.
 * @see		SSL_get_version()
 */
chr_t * tls_version(TLS *tls) {

	chr_t *version = NULL;
	SSL_CIPHER *cipher = NULL;

	if (!tls || !(cipher = SSL_get_current_cipher_d(tls)) || !(version = (chr_t *)SSL_get_version_d(tls))) {
		return NULL ;
	}

	return (st_cmp_cs_eq(NULLER(version), PLACER("TLSv1", 5)) ? version : "TLSv1.0");
 }
Пример #7
0
/**
 * @brief	Get a magma config key by name.
 * @param	name	a managed string with the name of the magma config option to be looked up.
 * @return	NULL on failure or a pointer to the found magma key object on success.
 */
magma_keys_t * config_key_lookup(stringer_t *name) {

	magma_keys_t *result = NULL;

	for (uint64_t i = 0; !result && name && i < sizeof(magma_keys) / sizeof(magma_keys_t); i++) {
		if (!st_cmp_ci_eq(NULLER(magma_keys[i].name), name)) {
			result = &magma_keys[i];
		}
	}

	return result;
}
Пример #8
0
bool_t check_hash_simple(void) {

	digest_t *digest;
	stringer_t *hash, *hex;
	chr_t *digest_list[] = {
		"MD4", "MD5", "SHA", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "RIPEMD160"
	}, *result_list[] = {
		"66f1f59819d52476f328839e34101d0f",
		"7215ee9c7d9dc229d2921a40e899ec5f",
		"bce965d4e985f27d988262331c0427909417cd90",
		"b858cb282617fb0956d960215c8e84d1ccf909c6",
		"ca17734c016e36b898af29c1aeb142e774abf4b70bac55ec98a27ba8",
		"36a9e7f1c95b82ffb99743e0c5c4ce95d83c9a430aac59f84ef3cbfab6145068",
		"588016eb10045dd85834d67d187d6b97858f38c58c690320c4a64e0c2f92eebd9f1bd74de256e8268815905159449566",
		"f90ddd77e400dfe6a3fcf479b00b1ee29e7015c5bb8cd70f5f15b4886cc339275ff553fc8a053f8ddc7324f45168cffaf81f8c3ac93996f6536eef38e5e40768",
		"ac53a3aea6835b5ec12054e12d41d392e9d57b72"
	};

	// Loop through and hash a single space using each digest method. Then check whether we got what we expected.
	for (uint64_t i = 0; status() && i < (sizeof(digest_list) / sizeof(chr_t *)); i++) {

		if (!(digest = digest_name(NULLER(digest_list[i]))) || !(hash = hash_digest(digest, PLACER(" ", 1), NULL))) {
			return false;
		}
		else if (!(hex = hex_encode_st(hash, NULL))) {
			st_free(hash);
			return false;
		}
		else if (st_cmp_cs_eq(hex, NULLER(result_list[i]) )) {
			st_free(hash);
			st_free(hex);
			return false;
		}

		st_free(hash);
		st_free(hex);
	}

	return true;
}
Пример #9
0
void check_rand_mthread_wrap(void) {

	stringer_t *result = NULL;

	if (!thread_start()) {
		log_error("Unable to setup the thread context.");
		pthread_exit(st_dupe(NULLER("Thread startup error.")));
		return;
	}

	result = check_rand_sthread();

	thread_stop();
	pthread_exit(result);
	return;
}
Пример #10
0
/**
 * @brief	Free all loaded magma configuration options.
 * @note	First all magma config keys will be freed, then the cache servers, relay servers, and magma servers.
 * @return	This function returns no value.
 */
void config_free(void) {

	for (uint64_t i = 0; i < sizeof(magma_keys) / sizeof(magma_keys_t); i++) {
		switch (magma_keys[i].norm.type) {

		case (M_TYPE_BLOCK):
			if (*((void **)(magma_keys[i].store))) {
				mm_free(*((void **)(magma_keys[i].store)));
			}
			break;
		case (M_TYPE_NULLER):
			if (*((char **)(magma_keys[i].store))) {
				ns_free(*((char **)(magma_keys[i].store)));
			}
			break;
		case (M_TYPE_STRINGER):

			// Intercept the blacklist config key.
			if (!st_cmp_cs_eq(NULLER(magma_keys[i].name), PLACER("magma.smtp.blacklist", 20))) {
				for (uint32_t j = 0; j < magma.smtp.blacklists.count; j++) {
					st_free(magma.smtp.blacklists.domain[j]);
				}
			}
			else if (*((stringer_t **)(magma_keys[i].store))) {
				st_free(*((stringer_t **)(magma_keys[i].store)));
			}
			break;
		default:
#ifdef MAGMA_PEDANTIC
			if (magma_keys[i].norm.type != M_TYPE_BOOLEAN && magma_keys[i].norm.type != M_TYPE_DOUBLE && magma_keys[i].norm.type != M_TYPE_FLOAT &&
					magma_keys[i].norm.type != M_TYPE_INT16 && magma_keys[i].norm.type != M_TYPE_INT32 && magma_keys[i].norm.type != M_TYPE_INT64 &&
					magma_keys[i].norm.type != M_TYPE_INT8 && magma_keys[i].norm.type != M_TYPE_UINT8 && magma_keys[i].norm.type != M_TYPE_UINT16 &&
					magma_keys[i].norm.type != M_TYPE_UINT32 && magma_keys[i].norm.type != M_TYPE_UINT64 && magma_keys[i].norm.type != M_TYPE_ENUM) {
				log_pedantic("Unexpected type. {type = %s = %u}", type(magma_keys[i].norm.type), magma_keys[i].norm.type);
			}
#endif
			break;
		}
	}

	cache_free();
	relay_free();
	servers_free();
	return;
}
Пример #11
0
bool_t log_start(void) {

	FILE *file_out, *file_err;
	chr_t *log_file = MEMORYBUF(1024);

	// File logging.
	if (magma.output.file && magma.output.path) {

		log_date = time_datestamp();

		if (snprintf(log_file, 1024, "%s%smagmad.%lu.log", magma.output.path, (*(ns_length_get(magma.output.path) + magma.output.path) == '/') ? "" : "/",
			log_date) >= 1024) {
			log_critical("Log file path exceeded available buffer. { file = %s%smagmad.%lu.log }", magma.output.path,
				(*(ns_length_get(magma.output.path) + magma.output.path) == '/') ? "" : "/", log_date);
			return false;
		}

		if (folder_exists(NULLER(magma.output.path), false)) {
			log_critical("The path configured to hold the output log files does not exist. { path = %s }", magma.output.path);
			return false;
		}

		if (!(file_out = freopen64(log_file, "a+", stdout))) {
			log_critical("Unable to open the error log, sticking with standard out. { file = %s }", log_file);
			return false;
		}

		if (!(file_err = freopen64(log_file, "a+", stderr))) {
			log_critical("Unable to open the error log, sticking with standard error. { file = %s }", log_file);
			fclose(file_out);
			return false;
		}

		stdout = file_out;
		stderr = file_err;
	}

	fclose(stdin);
	return true;
}
Пример #12
0
bool_t check_hash_sthread(chr_t *name) {

	stringer_t *hash;
	digest_t *digest;
	byte_t buffer[DIGEST_CHECK_SIZE];

	for (uint64_t i = 0; status() && i < DIGEST_CHECK_ITERATIONS; i++) {

		// Fill the buffer with random data and convert the buffer to encrypted.
		if (rand_write(PLACER(buffer, DIGEST_CHECK_SIZE)) != DIGEST_CHECK_SIZE) {
			return false;
		}
		//else if (!(digest = digest_name(NULLER(name))) || !(hash = hash_digest(digest, PLACER(buffer, DIGEST_CHECK_SIZE), NULL))) {
		else if (!(digest = digest_name(NULLER(name))) || !(hash = hash_digest(digest, PLACER(" ", 1), NULL))) {
			return false;
		}

		st_free(hash);
	}

	return true;
}
Пример #13
0
// QUESTION: Should -3 be returned for !array, etc. ?
int_t portal_parse_sections(json_t *array, uint32_t *sections) {

	uint64_t count;
	chr_t *current;
	int_t result = 1;

	if (!array || !json_is_array(array) || !sections) {
		return -1;
	}

	// Clear the output just in case something goes wrong.
	*sections = 0;

	if (!(count = json_array_size_d(array))) {
		return 0;
	}

	for (uint64_t i = 0; i < count && result == 1; i++) {

		if (!json_is_string(json_array_get_d(array, i)) || !(current = (chr_t *)json_string_value_d(json_array_get_d(array, i)))) {
			return -1;
		}

		if (!st_cmp_ci_eq(NULLER(current), PLACER("meta", 4))) *sections |= PORTAL_ENDPOINT_MESSAGE_META;
		else if (!st_cmp_ci_eq(NULLER(current), PLACER("source", 6))) *sections |= PORTAL_ENDPOINT_MESSAGE_SOURCE;
		else if (!st_cmp_ci_eq(NULLER(current), PLACER("security", 8))) *sections |= PORTAL_ENDPOINT_MESSAGE_SECURITY;
		else if (!st_cmp_ci_eq(NULLER(current), PLACER("server", 6))) *sections |= PORTAL_ENDPOINT_MESSAGE_SERVER;
		else if (!st_cmp_ci_eq(NULLER(current), PLACER("header", 6))) *sections |= PORTAL_ENDPOINT_MESSAGE_HEADER;
		else if (!st_cmp_ci_eq(NULLER(current), PLACER("body", 4))) *sections |= PORTAL_ENDPOINT_MESSAGE_BODY;
		else if (!st_cmp_ci_eq(NULLER(current), PLACER("attachments", 11))) *sections |= PORTAL_ENDPOINT_MESSAGE_ATTACHMENTS;
		else if (!st_cmp_ci_eq(NULLER(current), PLACER("info",4))) *sections |= PORTAL_ENDPOINT_MESSAGE_INFO;
		else if (result == 1) result = -2;
	}

	return result;
}
Пример #14
0
/**
 * @brief	Return the name of the TLS cipher suite assoicated with a connection.
 * @see		SSL_CIPHER_get_name()
 * @param 	tls the TLS connection being inspected.
 * @param	output	a managed string to receive the encoded output; if passed as NULL, an output buffer will be allocated
 *				which must be freed by the caller.
 * @return	a pointer to the result, or NULL if an error occurs.
 */
 stringer_t * tls_cipher(TLS *tls, stringer_t *output) {

	 SSL_CIPHER *cipher = NULL;
	 stringer_t *result = NULL;
	 chr_t *version = NULL, *name = NULL;

	 if (!(cipher = SSL_get_current_cipher_d(tls))) {
		 return NULL;
	 }
	 else if (!(version = (chr_t *)SSL_get_version_d(tls))) {
		 return NULL;
	 }
	 else if (!(name = (chr_t *)SSL_CIPHER_get_name_d(cipher))) {
		 return NULL;
	 }
	 else if (!(result = st_output(output, 128))) {
		 return NULL;
	 }

	 st_sprint(result, "version = %s / suite = %s", (st_cmp_cs_eq(NULLER(version), PLACER("TLSv1", 5)) ? version : "TLSv1.0"), name);

	 return result;
 }
Пример #15
0
/**
 * @brief	Return the contact/abuse page with a marked error indicator for the user in the event of a user submission error.
 * @param	branch		a null-terminated string containing the source  of the error: "Abuse" or "Contact"
 * @param	xpath		a null-terminated string containing the xpath of the element in the returned page that should be colored red.
 * @param	id			a null-terminated string containing the id of the error text <span> element to be added to the document.
 * @param	message		a null-terminated string containing the actual error message text to be displayed to the user.
 * @return	NULL on failure, or a pointer to the processed contact page with error message on success.
 */
http_page_t * contact_business_add_error(chr_t *branch, uchr_t *xpath, uchr_t *id, uchr_t *message) {

	http_page_t *page = NULL;
	xmlNodePtr node, error;
	xmlXPathObjectPtr xpath_obj;

	// We are here either for the contact or abuse page.
	if (!st_cmp_cs_eq(NULLER(branch), PLACER("Abuse", 5)) && !((page = http_page_get("contact/abuse")))) {
		return NULL;
	}
	else if (!page && !(page = http_page_get("contact/contact"))) {
		return NULL;
	}

	if ((xpath_obj = xml_xpath_eval(xpath, page->xpath_ctx)) && xpath_obj->nodesetval &&
		xpath_obj->nodesetval->nodeNr && xpath_obj->nodesetval->nodeTab[0]) {

		node = (xmlNodePtr)xpath_obj->nodesetval->nodeTab[0];

		// Make the field red.
		xml_node_set_property(node, (uchr_t *)"class", (uchr_t *)"red");

		// Add the error message.
		if ((error = xml_node_new((uchr_t *)"span"))) {
			xml_node_set_property(error, (uchr_t *)"id", id);
			xml_node_set_content(error, message);

			if (!(xml_node_add_sibling(node, error))) {
				xml_node_free(error);
			}

		}
	}

	return page;
}
Пример #16
0
/**
 * @brief	Set the value of a global config key.
 * @note	This function will also free the value of the global config key if it has already previously been set.
 * @param	setting		a pointer to the global key to have its value adjusted.
 * @param	value		a managed string containing the new key value, or if NULL, the key's default value will be used.
 * @return	true if the specified key's value was set successfully, or false on failure.
 */
bool_t config_value_set(magma_keys_t *setting, stringer_t *value) {

	bool_t result = true;

	/// LOW: Realtime blacklist domains are handled using custom code because we don't yet have a generic type to store lists.
	if (!st_cmp_cs_eq(NULLER(setting->name), PLACER("magma.smtp.blacklist", 20))) {

		// When the default values are assigned an empty string is passed in. Returning false then tricks the system into
		// thinking the default value is wrong, so we just return true to avoid the issue.
		if (st_empty(value)) {
			return true;
		}

		// Were using a fixed array, so if we run out of room we have to reject config.
		if (magma.smtp.blacklists.count >= MAGMA_BLACKLIST_INSTANCES) {
			log_critical("magma.smtp.blacklist is limited to %u %s and the configuration currently contains more than %u %s.",
				MAGMA_BLACKLIST_INSTANCES, MAGMA_BLACKLIST_INSTANCES == 1 ? "domain" : "domains", MAGMA_BLACKLIST_INSTANCES,
				MAGMA_BLACKLIST_INSTANCES == 1 ? "domain" : "domains");
			return false;
		}

		// Make sure the targeted array slot is empty, and the string passed to us has data in it. If so duplicate the value and
		// and store it in the array. If anything fails, return false.
		else if (magma.smtp.blacklists.domain[magma.smtp.blacklists.count] || !(magma.smtp.blacklists.domain[magma.smtp.blacklists.count] =
			st_dupe_opts(MANAGED_T | CONTIGUOUS | HEAP, value))) {
			return false;
		}

		// Track the number of blacklist domains we have.
		magma.smtp.blacklists.count++;

		// Return true so the switch statement below doesn't corrupt the array.
		return true;
	}
	else if (!st_cmp_cs_eq(NULLER(setting->name), NULLER("magma.smtp.bypass_addr"))) {

			// When the default values are assigned an empty string is passed in. Returning false then tricks the system into
			// thinking the default value is wrong, so we just return true to avoid the issue.
			if (st_empty(value)) {
				return true;
			}

			if (!smtp_add_bypass_entry(value)) {
				log_critical("Unable to add smtp bypass entry { entry = %s }", st_char_get(value));
				return false;
			}

			// Return true so the switch statement below doesn't corrupt the array.
			return true;
		}


	switch (setting->norm.type) {

	// Strings
	case (M_TYPE_NULLER):
		if (!ns_empty(*((char **)(setting->store)))) {
			ns_free(*((char **)(setting->store)));
			*((char **)(setting->store)) = NULL;
		}
		if (!st_empty(value))
			*((char **)(setting->store)) = ns_import(st_char_get(value), st_length_get(value));
		else if (!ns_empty(setting->norm.val.ns))
			*((char **)(setting->store)) = ns_dupe(setting->norm.val.ns);
		break;

	case (M_TYPE_STRINGER):
		if (!st_empty(*((stringer_t **)(setting->store)))) {
			st_free(*((stringer_t **)(setting->store)));
			*((stringer_t **)(setting->store)) = NULL;
		}
		if (!st_empty(value))
			*((stringer_t **)(setting->store)) = st_dupe_opts(MANAGED_T | CONTIGUOUS | HEAP, value);
		else if (!st_empty(setting->norm.val.st))
			*((stringer_t **)(setting->store)) = st_dupe_opts(MANAGED_T | CONTIGUOUS | HEAP, setting->norm.val.st);
		break;

		// Booleans
	case (M_TYPE_BOOLEAN):
		if (!st_empty(value)) {
			if (!st_cmp_ci_eq(value, CONSTANT("true")))
				*((bool_t *)(setting->store)) = true;
			else if (!st_cmp_ci_eq(value, CONSTANT("false")))
				*((bool_t *)(setting->store)) = false;
			else {
				log_critical("Invalid value for %s.", setting->name);
				result = false;
			}
		} else
			*((bool_t *)(setting->store)) = setting->norm.val.binary;
		break;

		// Integers
	case (M_TYPE_INT8):
		if (!st_empty(value)) {
			if (!int8_conv_st(value, (int8_t *)(setting->store))) {
				log_critical("Invalid value for %s.", setting->name);
				result = false;
			}
		} else
			*((int8_t *)(setting->store)) = setting->norm.val.i8;
		break;

	case (M_TYPE_INT16):
		if (!st_empty(value)) {
			if (!uint16_conv_st(value, (uint16_t *)(setting->store))) {
				log_critical("Invalid value for %s.", setting->name);
				result = false;
			}
		} else
			*((int16_t *)(setting->store)) = setting->norm.val.u16;
		break;

	case (M_TYPE_INT32):
		if (!st_empty(value)) {
			if (!int32_conv_st(value, (int32_t *)(setting->store))) {
				log_critical("Invalid value for %s.", setting->name);
				result = false;
			}
		} else
			*((int32_t *)(setting->store)) = setting->norm.val.i32;
		break;

	case (M_TYPE_INT64):
		if (!st_empty(value)) {
			if (!int64_conv_st(value, (int64_t *)(setting->store))) {
				log_critical("Invalid value for %s.", setting->name);
				result = false;
			}
		} else
			*((int64_t *)(setting->store)) = setting->norm.val.i64;
		break;

		// Unsigned Integers
	case (M_TYPE_UINT8):
		if (!st_empty(value)) {
			if (!uint8_conv_st(value, (uint8_t *)(setting->store))) {
				log_critical("Invalid value for %s.", setting->name);
				result = false;
			}
		} else
			*((uint8_t *)(setting->store)) = setting->norm.val.u8;
		break;

	case (M_TYPE_UINT16):
		if (!st_empty(value)) {
			if (!uint16_conv_st(value, (uint16_t *)(setting->store))) {
				log_critical("Invalid value for %s.", setting->name);
				result = false;
			}
		} else
			*((uint16_t *)(setting->store)) = setting->norm.val.u16;
		break;

	case (M_TYPE_UINT32):
		if (!st_empty(value)) {
			if (!uint32_conv_st(value, (uint32_t *)(setting->store))) {
				log_critical("Invalid value for %s.", setting->name);
				result = false;
			}
		} else
			*((uint32_t *)(setting->store)) = setting->norm.val.u32;
		break;

	case (M_TYPE_UINT64):
		if (!st_empty(value)) {
			if (!uint64_conv_st(value, (uint64_t *)(setting->store))) {
				log_critical("Invalid value for %s.", setting->name);
				result = false;
			}
		} else
			*((uint64_t *)(setting->store)) = setting->norm.val.u64;
		break;

	default:
		log_critical("The %s setting definition is using an invalid type.", setting->name);
		result = false;
		break;
	}
	return result;
}
Пример #17
0
/**
 * @brief	Send the contents of a user-submitted contact or abuse form to the magma-configured contact email address.
 * @param	con		the connection of the web client making the request.
 * @param	branch	a null-terminated string containing the destination of the contact form: either "Abuse" or "Contact".
 * @return	This function returns no value.
 */
void contact_business(connection_t *con, chr_t *branch) {

	stringer_t *composed, *ip, *daddr;
	http_data_t *name, *email, *message;
	bool_t is_contact;

	// A contact form submission by default
	if (!st_cmp_cs_eq(NULLER(branch), PLACER("Abuse", 5))) {
		is_contact = false;
		daddr = magma.admin.abuse;
	} else {
		is_contact = true;
		daddr = magma.admin.contact;
	}

	// One last sanity check, just in case.
	if (is_contact && !daddr) {
		contact_print_message(con, branch, "An unexpected error occurred while trying to process your request. This server does not have a contact address configured.");
		log_error("Contact form routine was reached but no contact address was configured.");
		return;
	}
	else if (!is_contact && !daddr) {
		contact_print_message(con, branch, "An unexpected error occurred while trying to process your request. This server does not have an abuse address configured.");
		log_error("Abuse form routine was reached but no abuse address was configured.");
		return;
	}

	// If either the name, email, or message fields are omitted from the post, spit out an error message.
	if (!(name = http_data_get(con, HTTP_DATA_POST, "your_name")) || !name->value) {
		contact_print_form(con, branch, contact_business_add_error(branch, (uchr_t *)"//xhtml:input[@id='your_name']", (uchr_t *)"your_name_msg", (uchr_t *)"Please enter your name."));
		return;
	}
	else if (!(email = http_data_get(con, HTTP_DATA_POST, "your_email")) || !email->value || !contact_business_valid_email(email->value)) {
		contact_print_form(con, branch, contact_business_add_error(branch,  (uchr_t *)"//xhtml:input[@id='your_email']",  (uchr_t *)"your_email_msg",  (uchr_t *)"A valid e-mail address is required."));
		return;
	}
	else if (!(message = http_data_get(con, HTTP_DATA_POST, "your_message")) || !message->value) {
		contact_print_form(con, branch, contact_business_add_error(branch,  (uchr_t *)"//xhtml:textarea[@id='your_message']",  (uchr_t *)"your_message_msg",  (uchr_t *)"Please enter your message."));
		return;
	}

	// Build the IP string.
	ip = con_addr_presentation(con, MANAGEDBUF(64));

	if ((composed = st_merge("nnnsnsnsnsnsnsnsn", "Subject: ", (is_contact ? "* Contact Form Submission *" : "*Abuse Form Submission*"),
		"\r\nFrom: ", magma.admin.contact, "\r\nTo: ", magma.admin.contact, "\r\nReply-To: ",
		email->value, "\r\n\r\nip = ", ip, "\r\nname = ", name->value, "\r\nemail = ", email->value, "\r\n------------\r\n\r\n ", message->value, "\r\n"))) {

		// Dotstuff the message. Just to prevent SMTP injection attacks.
		st_replace(&composed, PLACER("\n.",2), PLACER("\n..", 3));

		// Send the message.
		if (smtp_send_message(daddr, daddr, composed) != 1) {
			contact_print_message(con, branch, "An error occurred while trying to process your request. Please try again in a few minutes.");
			st_free(composed);
			return;
		}

		// Increment our abuse counters.
		contact_abuse_increment_history(con);
		st_free(composed);
	}

	contact_print_message(con, branch, "Your message has been submitted. We'll review your message-typically within one business day-and get back to you. However "
		"during certain busy periods our team can take up to three business days to respond.");

	return;
}
Пример #18
0
/**
 * @brief	Perform a series of system-wide sanity checks at process startup.
 * @note	This function ensures that the standard data types are their expected data sizes, and performs other
 * 			checks, such as data primitive maximum values.
 * @return	true if the system environment passed all checks and should function correctly, or false if any checks failed.
 */
bool_t sanity_check(void) {

	stringer_t *st;
	size_t sz[2] = { 0, 0 };
	int64_t i64[2] = { 0, 0 };
	ssize_t ssz[2] = { 0, 0 };
	uint64_t ui64[2] = { 0, 0 };

	// Make sure the standard types are what we expect.
	if (sizeof(char) != 1 || sizeof(short) != 2 || sizeof(int) != 4 || sizeof(long) != 8) {
		return false;
	}

	// Check on the standard integer sizes in use.
	if (sizeof(int8_t) != 1 || sizeof(int16_t) != 2 || sizeof(int32_t) != 4 || sizeof(int64_t) != 8) {
		return false;
	}

	if (sizeof(uint8_t) != 1 || sizeof(uint16_t) != 2 || sizeof(uint32_t) != 4 || sizeof(uint64_t) != 8) {
		return false;
	}

	// Check the system specific typedefs we use.
	if (sizeof(bool_t) != 1 || sizeof(time_t) != 8 || sizeof(size_t) != 8) {
		return false;
	}

	// Check on the different types of pointers.
	if (sizeof(char *) != 8 || sizeof(void *) != 8) {
		return false;
	}

	// Ensure the type aliases are properly sized.
	if (sizeof(byte_t) != 1 || sizeof(uchr_t) != 1 || sizeof(chr_t) != 1) {
		return false;
	}

	if (sizeof(float_t) != 4 || sizeof(double_t) != 8) {
		return false;
	}

	// That strings are properly formed and sized.
	if (sizeof(stringer_t) != 1 || sizeof(stringer_t *) != 8) {
		return false;
	}

	// That IP addresses are properly formed and sized.
	if (sizeof(octet_t) != 2 || sizeof(segment_t) != 4 || sizeof(struct in_addr) != 4 || sizeof(struct in6_addr) != 16) {
			return false;
		}


	// Should be the size of a size variable, plus a pointer.
	if (sizeof(placer_t) != 20 || sizeof(placer_t) != (sizeof(size_t) + sizeof(void *) + sizeof(uint32_t))) {
		return false;
	}

	// Setup the min/max values.
	sz[0] = SIZE_MAX + 1;
	sz[1] = SIZE_MAX;
	ssz[0] = (SIZE_MAX / 2) + 1;
	ssz[1] = (SIZE_MAX / 2);
	i64[0] = INT64_MIN;
	i64[1] = INT64_MAX;
	ui64[0] = UINT64_MAX + 1;
	ui64[1] = UINT64_MAX;

	// The functions used to convert character strings into size_t and ssize_t are aliases for uint64_t and int64_t. Aliases are also used by the serialization
	// functions. The following test uses the min/max values calculated above to ensure the aliases used remain accurate.
	if (sizeof(size_t) != sizeof(uint64_t) || sz[0] != ui64[0] || sz[1] != ui64[1] ||	sizeof(ssize_t) != sizeof(int64_t) || ssz[0] != i64[0] || ssz[1] != i64[1] ||
			sz[1] != SIZE_MAX || i64[0] != INT64_MIN || i64[1] != INT64_MAX || ui64[1] != UINT64_MAX) {
		return false;
	}

	// We are using a semaphore to block access to our connection pools,
	// so our max is limited by the semaphore max value.
	if (MAGMA_CORE_POOL_OBJECTS_LIMIT > SEM_VALUE_MAX) {
		return false;
	}

	// The pool counters are unsigned 32 bit ints, so make sure the max is below their limit.
	if (MAGMA_CORE_POOL_OBJECTS_LIMIT > UINT32_MAX || MAGMA_CORE_POOL_TIMEOUT_LIMIT > UINT32_MAX) {
		return false;
	}

	// This tuple must evaluate correctly or the comparison functions will not function correctly.
	if (((100 < 200) ? -1 : 100 > 200) != -1 || ((100 < 100) ? -1 : 100 > 100) != 0 || ((200 < 100) ? -1 : 200 > 100) != 1) {
		return false;
	}

	// The tank interface uses the memory that initially holds a the object heading to store the two size_t variables need for a compress_t block. If
	// the size of two size_t variables is greater than the length of of a record_t, the math being used to cause data to be written before the actual
	// starting address of the buffer. So to keep this from happening we have a sanity check in place.
	if ((sizeof(size_t) + sizeof(size_t)) > sizeof(record_t)) {
	 return false;
	}

	// We also need to make sure the stringer_t format doesn't change in a way that would break the implementation.
	if (!(st = st_alloc(1))) {
		return false;
	}	else if ((size_t)((st_data_get(st) + st_avail_get(st)) - (void *)(st)) != (sizeof(uint32_t) + sizeof(size_t) + sizeof(size_t) + sizeof(void *) + 1)) {
		st_free(st);
		return false;
	} else {
		st_free(st);
	}

	// We assume the select_domains query is the points to the beginning of the prepared statement structure. If the order is changed the code will need to be
	// updated or the statement variables won't be pointed at the correct SQL query. This affects the functions stmt_start(), stmt_rebuild(), and stmt_stop().
	if (st_cmp_cs_eq(NULLER(queries[0]), CONSTANT(SELECT_DOMAINS))) {
		return false;
	}

	return true;
}
Пример #19
0
#include "message.16.h"
#include "message.17.h"
#include "message.18.h"
#include "message.19.h"

#define DKIM_TEST_NONE 0x00000000
#define DKIM_TEST_VERIFY 0x00000001
#define DKIM_TEST_SIGNING 0x00000010

typedef struct {
	uint32_t flags;
	stringer_t *data;
} check_message_data_t;

check_message_data_t messages[] = {
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_1) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_2) },
	{ DKIM_TEST_NONE, NULLER(MESSAGE_3) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_4) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_5) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_6) },
	{ DKIM_TEST_NONE, NULLER(MESSAGE_7) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_8) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_9) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_10) },
	{ DKIM_TEST_NONE, NULLER(MESSAGE_11) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_12) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_13) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_14) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_15) },
	{ DKIM_TEST_SIGNING, NULLER(MESSAGE_16) },
Пример #20
0
/**
 * @brief	Log the contents of a magma configuration option.
 * @param	key		a pointer to the magma configuration key to be dumped.
 * @return	This function returns no value.
 */
void config_output_value(magma_keys_t *key) {

	switch (key->norm.type) {
	case (M_TYPE_NULLER):
		if (ns_empty(*((char **)(key->store))))
			log_info("%s = NULL", key->name);
		else
			log_info("%s = %s", key->name, *((char **)(key->store)));
		break;

	case (M_TYPE_STRINGER):
		// Intercept the blacklist config key->
		if (!st_cmp_cs_eq(NULLER(key->name), PLACER("magma.smtp.blacklist", 20))) {

			if (!magma.smtp.blacklists.count) {
				log_info("%s = NULL",key->name);
			}

			for (uint32_t j = 0; j < magma.smtp.blacklists.count; j++) {
				log_info("%s = %.*s",key->name, st_length_int(magma.smtp.blacklists.domain[j]), st_char_get(magma.smtp.blacklists.domain[j]));
			}
		}

		else if (st_empty(*((stringer_t **)(key->store))))
			log_info("%s = NULL", key->name);
		else
			log_info("%s = %.*s", key->name, st_length_int(*((stringer_t **)(key->store))), st_char_get(*((stringer_t **)(key->store))));
		break;

	case (M_TYPE_BOOLEAN):
		log_info("%s = %s", key->name, (*((bool_t *)(key->store)) ? "true" : "false"));
		break;

	case (M_TYPE_INT8):
		log_info("%s = %hhi", key->name, *((int8_t *)(key->store)));
		break;
	case (M_TYPE_INT16):
		log_info("%s = %hi", key->name, *((int16_t *)(key->store)));
		break;

	case (M_TYPE_INT32):
		log_info("%s = %i", key->name, *((int32_t *)(key->store)));
		break;

	case (M_TYPE_INT64):
		log_info("%s = %li", key->name, *((int64_t *)(key->store)));
		break;

	case (M_TYPE_UINT8):
		log_info("%s = %hhu", key->name, *((uint8_t *)(key->store)));
		break;
	case (M_TYPE_UINT16):
		log_info("%s = %hu", key->name, *((uint16_t *)(key->store)));
		break;
	case (M_TYPE_UINT32):
		log_info("%s = %u", key->name, *((uint32_t *)(key->store)));
		break;
	case (M_TYPE_UINT64):
		log_info("%s = %lu", key->name, *((uint64_t *)(key->store)));
		break;
	default:
		log_pedantic("Unexpected type. {type = %u}", key->norm.type);
		break;
	}

	return;
}
Пример #21
0
/**
 * @brief	Output a key name and value in a generic way.
 * @param	prefix		a pointer to a null-terminated string containing an optional prefix to be printed before the supplied key name.
 * @param	name		a pointer to a null-terminated string containing the name of the key being output.
 * @param	type		an M_TYPE value specifying the multi-type of the key value.
 * @param	val			a void pointer to the value of the specified key, which will be printed in accordance with the supplied multi-type.
 * @param	required	a boolean value specifying whether the specified key is a required configuration option.
 * @return	This function returns no value.
 */
void config_output_value_generic(chr_t *prefix, chr_t *name, M_TYPE type, void *val, bool_t required) {

	chr_t *reqstr = "";

	if (!prefix) {
		prefix = "";
	}

	if (required) {
		reqstr = "*";
	}

	switch (type) {
	case (M_TYPE_NULLER):
		if (ns_empty(*((char **)(val))))
			log_info("%s%s%s = NULL", prefix, name, reqstr);
		else
			log_info("%s%s%s = %s", prefix, name, reqstr, *((char **)(val)));
		break;

	case (M_TYPE_STRINGER):
		// Intercept the blacklist config key->
		if (!st_cmp_cs_eq(NULLER(name), PLACER("magma.smtp.blacklist", 20))) {

			if (!magma.smtp.blacklists.count) {
				log_info("%s%s%s = NULL", prefix, name, reqstr);
			}

			for (uint32_t j = 0; j < magma.smtp.blacklists.count; j++) {
				log_info("%s%s%s = %.*s", prefix, name, reqstr, st_length_int(magma.smtp.blacklists.domain[j]), st_char_get(magma.smtp.blacklists.domain[j]));
			}
		}

		else if (st_empty(*((stringer_t **)(val))))
			log_info("%s%s%s = NULL", prefix, name, reqstr);
		else
			log_info("%s%s%s = %.*s", prefix, name, reqstr, st_length_int(*((stringer_t **)(val))), st_char_get(*((stringer_t **)(val))));
		break;

	case (M_TYPE_ENUM):

			if (!st_cmp_cs_eq(NULLER(name), CONSTANT(".protocol"))) {
				if (*((M_PROTOCOL *)((char *)val)) == MOLTEN)
					log_info("%s%s%s = MOLTEN", prefix, name, reqstr);
				else if (*((M_PROTOCOL *)((char *)val)) == HTTP)
					log_info("%s%s%s = HTTP", prefix, name, reqstr);
				else if (*((M_PROTOCOL *)((char *)val)) == POP)
					log_info("%s%s%s = POP", prefix, name, reqstr);
				else if (*((M_PROTOCOL *)((char *)val)) == IMAP)
					log_info("%s%s%s = IMAP", prefix, name, reqstr);
				else if (*((M_PROTOCOL *)((char *)val)) == SMTP)
					log_info("%s%s%s = SMTP", prefix, name, reqstr);
				else if (*((M_PROTOCOL *)((char *)val)) == SUBMISSION)
					log_info("%s%s%s = SUBMISSION", prefix, name, reqstr);
				else if (*((M_PROTOCOL *)((char *)val)) == EMPTY)
						log_info("%s%s%s = EMPTY", prefix, name, reqstr);
				else
					log_info("%s%s%s = [UNKNOWN]", prefix, name, reqstr);
			} else if (!st_cmp_cs_eq(NULLER(name), CONSTANT(".network.type"))) {
				if (*((M_PORT *)((char *)val)) == TCP_PORT)
					log_info("%s%s%s = TCP", prefix, name, reqstr);
				else if (*((M_PORT *)((char *)val)) == SSL_PORT)
					log_info("%s%s%s = SSL", prefix, name, reqstr);
				else
					log_info("%s%s%s = [UNKNOWN]", prefix, name, reqstr);
			}
		break;

	case (M_TYPE_BOOLEAN):
		log_info("%s%s%s = %s", prefix, name, reqstr, (*((bool_t *)(val)) ? "true" : "false"));
		break;

	case (M_TYPE_INT8):
		log_info("%s%s%s = %hhi", prefix, name, reqstr, *((int8_t *)(val)));
		break;
	case (M_TYPE_INT16):
		log_info("%s%s%s = %hi", prefix, name, reqstr, *((int16_t *)(val)));
		break;

	case (M_TYPE_INT32):
		log_info("%s%s%s = %i", prefix, name, reqstr, *((int32_t *)(val)));
		break;

	case (M_TYPE_INT64):
		log_info("%s%s%s = %li", prefix, name, reqstr, *((int64_t *)(val)));
		break;

	case (M_TYPE_UINT8):
		log_info("%s%s%s = %hhu", prefix, name, reqstr, *((uint8_t *)(val)));
		break;
	case (M_TYPE_UINT16):
		log_info("%s%s%s = %hu", prefix, name, reqstr, *((uint16_t *)(val)));
		break;
	case (M_TYPE_UINT32):
		log_info("%s%s%s = %u", prefix, name, reqstr, *((uint32_t *)(val)));
		break;
	case (M_TYPE_UINT64):
		log_info("%s%s%s = %lu", prefix, name, reqstr, *((uint64_t *)(val)));
		break;
	default:
		log_pedantic("Unexpected type. {type = %u}", type);
		break;
	}

	return;
}
Пример #22
0
/**
 * @brief	Get smtp envelope data for an outbound message sent by a webmail client.
 * @param	from		a pointer to a managed string containing the sender's address.
 * @param	tos			a pointer to an inx holder containing a collection of managed strings with the email addresses specified in the To: header.
 * @param	ccs			a pointer to an inx holder containing a collection of managed strings with the email addresses specified in the CC: header.
 * @param	bccs		a pointer to an inx holder containing a collection of managed strings with the email addresses specified in the BCC: header.
 * @param	subject		a pointer to a managed string containing the text of the subject line.
 * @param	boundary	a pointer to a managed string containing a boundary string to be used in multipart messages.
 * @param	attached	if true, the envelope is to be created for a mail with attachments (type "multipart/mixed");
 * 						if false, only a single part will be sent for the main email body.
 * @return	NULL on failure or a pointer to a managed string containing the smtp envelope data that will be supplied to an smtp
 * 			relay server at the beginning of the DATA command.
 */
stringer_t * mail_mime_get_smtp_envelope(stringer_t *from, inx_t *tos, inx_t *ccs, inx_t *bccs, stringer_t *subject, stringer_t *boundary, bool_t attached) {

	stringer_t *result, *firsthead = NULL;
	stringer_t *str_to, *str_cc, *str_bcc;
	struct tm ltime;
	static const chr_t *date_format = "Date: %a, %d %b %Y %H:%M:%S %z";
	chr_t date_buffer[1024];
	time_t utime;

	if (!from || !tos || !ccs | !bccs || !subject) {
		log_pedantic("Could not build smtp envelope with incomplete information.");
		return NULL;
	}

	// Serialize the To, CC, and BCC data into separate strings.
	if (!(str_to = portal_smtp_merge_headers(tos, NULLER("To: "), NULLER("\r\n")))) {
		log_error("Could not construct To: header for smtp envelope.");
		return NULL;
	} else if (!(str_cc = portal_smtp_merge_headers(ccs, NULLER("CC: "), NULLER("\r\n")))) {
		log_error("Could not construct CC: header for smtp envelope.");
		st_free(str_to);
		return NULL;
	} else if (!(str_bcc = portal_smtp_merge_headers(bccs, NULLER("BCC: "), NULLER("\r\n")))) {
		log_error("Could not construct BCC: header for smtp envelope.");
		st_free(str_to);
		st_free(str_cc);
		return NULL;
	}

	// Add the current date/time to the outbound message.
	if (((utime = time(&utime)) == -1) || (localtime_r(&utime, &ltime) == NULL) || (strftime(date_buffer, sizeof(date_buffer), date_format, &ltime) <= 0)) {
		log_error("Could not build smtp envelope without current time.");
		st_free(str_to);
		st_free(str_cc);
		st_free(str_bcc);
		return NULL;
	}

	// If there are attachments, we are going to make a multipart message.
	if (attached) {

		if (!(firsthead = st_merge("nsn", "Content-Type: multipart/mixed; boundary=\"------------", boundary, "\"\r\n\r\nThis is a multi-part message in MIME format.\r\n"))) {
			log_error("Could not build multipart header for smtp envelope.");
			st_free(str_to);
			st_free(str_cc);
			st_free(str_bcc);
			return NULL;
		}

	}

	/*if (!(result = st_merge("nnsnsnsns", date_buffer, "\r\nFrom: ", from, "\r\nUser-Agent: lavaweb 1.0\r\nMIME-Version: 1.0\r\nTo: ",
			to, "\r\nSubject: ", subject, "\r\n", firsthead))) { */
	if (!(result = st_merge("nnsnsssnsns", date_buffer, "\r\nFrom: ", from, "\r\nUser-Agent: lavaweb 1.0\r\nMIME-Version: 1.0\r\n",
				str_to, str_cc, str_bcc, "Subject: ", subject, "\r\n", firsthead))) {
		log_error("Unable to allocate space for smtp envelope.");
		st_free(str_to);
		st_free(str_cc);
		st_free(str_bcc);
		st_cleanup(firsthead);
		return NULL;
	}

	st_free(str_to);
	st_free(str_cc);
	st_free(str_bcc);
	st_cleanup(firsthead);

	return result;
}
Пример #23
0
END_TEST

START_TEST (check_warehouse_domains_s)
{
	char *errmsg = NULL;
	bool_t outcome = true;

	log_unit("%-64.64s", "OBJECTS / WAREHOUSE / DOMAINS / SINGLE THREADED:");

	if (status() && (domain_wildcard(CONSTANT("lavabit.com")) != 0 || domain_dkim(CONSTANT("lavabit.com")) != 1 ||	domain_spf(CONSTANT("lavabit.com")) != 1 ||
		domain_wildcard(CONSTANT("mailshack.com")) != 0 || domain_dkim(CONSTANT("mailshack.com")) != 1 ||	domain_spf(CONSTANT("mailshack.com")) != 1 ||
		domain_wildcard(CONSTANT("nerdshack.com")) != 0 || domain_dkim(CONSTANT("nerdshack.com")) != 1 ||	domain_spf(CONSTANT("nerdshack.com")) != 1 ||
		domain_wildcard(CONSTANT("squeak-seo.com")) != 1 || domain_dkim(CONSTANT("squeak-seo.com")) != 0 ||	domain_spf(CONSTANT("squeak-seo.com")) != 1 ||
		domain_wildcard(CONSTANT("texasteenage.org")) != 1 || domain_dkim(CONSTANT("texasteenage.org")) != 0 ||	domain_spf(CONSTANT("texasteenage.org")) != 0 ||
		domain_wildcard(CONSTANT("ronweb.net")) != 1 || domain_dkim(CONSTANT("ronweb.net")) != 1 ||	domain_spf(CONSTANT("ronweb.net")) != 1 ||
		domain_wildcard(CONSTANT("slashdot.org")) != -1 || domain_dkim(CONSTANT("slashdot.org")) != -1 ||	domain_spf(CONSTANT("slashdot.org")) != -1 ||

		domain_wildcard(NULLER("lavabit.com")) != 0 || domain_dkim(NULLER("lavabit.com")) != 1 ||	domain_spf(NULLER("lavabit.com")) != 1 ||
		domain_wildcard(NULLER("mailshack.com")) != 0 || domain_dkim(NULLER("mailshack.com")) != 1 ||	domain_spf(NULLER("mailshack.com")) != 1 ||
		domain_wildcard(NULLER("nerdshack.com")) != 0 || domain_dkim(NULLER("nerdshack.com")) != 1 ||	domain_spf(NULLER("nerdshack.com")) != 1 ||
		domain_wildcard(NULLER("squeak-seo.com")) != 1 || domain_dkim(NULLER("squeak-seo.com")) != 0 ||	domain_spf(NULLER("squeak-seo.com")) != 1 ||
		domain_wildcard(NULLER("texasteenage.org")) != 1 || domain_dkim(NULLER("texasteenage.org")) != 0 ||	domain_spf(NULLER("texasteenage.org")) != 0 ||
		domain_wildcard(NULLER("ronweb.net")) != 1 || domain_dkim(NULLER("ronweb.net")) != 1 ||	domain_spf(NULLER("ronweb.net")) != 1 ||
		domain_wildcard(NULLER("slashdot.org")) != -1 || domain_dkim(NULLER("slashdot.org")) != -1 ||	domain_spf(NULLER("slashdot.org")) != -1 ||

		domain_wildcard(PLACER("lavabit.com", 11)) != 0 || domain_dkim(PLACER("lavabit.com", 11)) != 1 ||	domain_spf(PLACER("lavabit.com", 11)) != 1 ||
		domain_wildcard(PLACER("mailshack.com", 13)) != 0 || domain_dkim(PLACER("mailshack.com", 13)) != 1 ||	domain_spf(PLACER("mailshack.com", 13)) != 1 ||
		domain_wildcard(PLACER("nerdshack.com", 13)) != 0 || domain_dkim(PLACER("nerdshack.com", 13)) != 1 ||	domain_spf(PLACER("nerdshack.com", 13)) != 1 ||
		domain_wildcard(PLACER("squeak-seo.com", 14)) != 1 || domain_dkim(PLACER("squeak-seo.com", 14)) != 0 ||	domain_spf(PLACER("squeak-seo.com", 14)) != 1 ||
		domain_wildcard(PLACER("texasteenage.org", 16)) != 1 || domain_dkim(PLACER("texasteenage.org", 16)) != 0 ||	domain_spf(PLACER("texasteenage.org", 16)) != 0 ||
		domain_wildcard(PLACER("ronweb.net", 10)) != 1 || domain_dkim(PLACER("ronweb.net", 10)) != 1 ||	domain_spf(PLACER("ronweb.net", 10)) != 1 ||
		domain_wildcard(PLACER("slashdot.org", 12)) != -1 || domain_dkim(PLACER("slashdot.org", 12)) != -1 ||	domain_spf(PLACER("slashdot.org", 12)) != -1)) {
		errmsg = "Domain checks failed.";
		outcome = false;
	}

	outcome = errmsg ? false : true;
	log_unit("%10.10s\n", (outcome ? "PASSED" : status() ? "FAILED" : "SKIPPED"));
	fail_unless(outcome, errmsg);

}