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; }
/** * @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; }
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; }
/* 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; }
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; }
/** * @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"); }
/** * @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; }
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; }
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; }
/** * @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; }
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; }
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; }
// 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; }
/** * @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; }
/** * @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; }
/** * @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; }
/** * @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; }
/** * @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; }
#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) },
/** * @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; }
/** * @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; }
/** * @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, <ime) == NULL) || (strftime(date_buffer, sizeof(date_buffer), date_format, <ime) <= 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; }
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); }