bool_t check_bitwise_determinism(void) { stringer_t *a = NULL, *b = NULL, *res1 = NULL, *res2 = NULL; unsigned char a_buf[] = {0x00, 0x33, 0x80, 0x04, 0x20}; unsigned char b_buf[] = {0x11, 0xCC, 0x78, 0x4B, 0x1E}; a = PLACER(a_buf, 5); b = PLACER(b_buf, 5); if(!(res1 = st_xor(a, b, NULL)) || !(res2 = st_xor(a, b, NULL))) { st_cleanup(res1, res2); return false; } else if(st_cmp_cs_eq(res1, res2)) { st_cleanup(res1, res2); return false; } st_cleanup(res1, res2); res1 = res2 = NULL; if(!(res1 = st_and(a, b, NULL)) || !(res2 = st_and(a, b, NULL))) { st_cleanup(res1, res2); return false; } else if(st_cmp_cs_eq(res1, res2)) { st_cleanup(res1, res2); return false; } st_cleanup(res1, res2); res1 = res2 = NULL; if(!(res1 = st_or(a, b, NULL)) || !(res2 = st_or(a, b, NULL))) { st_cleanup(res1, res2); return false; } else if(st_cmp_cs_eq(res1, res2)) { st_cleanup(res1, res2); return false; } st_cleanup(res1, res2); res1 = res2 = NULL; if(!(res1 = st_not(a, NULL)) || !(res2 = st_not(a, NULL))) { st_cleanup(res1, res2); return false; } else if(st_cmp_cs_eq(res1, res2)) { st_cleanup(res1, res2); return false; } st_cleanup(res1, res2); 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; }
bool_t check_encoding_zbase32(void) { stringer_t *zb32, *binary; byte_t buffer[ZBASE32_CHECK_SIZE]; for (uint64_t i = 0; status() && i < ZBASE32_CHECK_ITERATIONS; i++) { // Fill the buffer with random data and convert the buffer to hex. if (rand_write(PLACER(buffer, ZBASE32_CHECK_SIZE)) != ZBASE32_CHECK_SIZE) { return false; } else if (!(zb32 = zbase32_encode(PLACER(buffer, ZBASE32_CHECK_SIZE)))) { return false; } //log_pedantic("zb32 = %.*s", st_length_int(zb32), st_char_get(zb32)); // Convert the buffer back to binary and compare it with the original array. if (!(binary = zbase32_decode(zb32))) { st_free(zb32); return false; } else if (st_cmp_cs_eq(binary, PLACER(buffer, ZBASE32_CHECK_SIZE))) { st_free(binary); st_free(zb32); return false; } st_free(binary); st_free(zb32); } return true; }
bool_t check_encoding_qp(void) { stringer_t *qp, *binary; byte_t buffer[QP_CHECK_SIZE]; for (uint64_t i = 0; status() && i < QP_CHECK_ITERATIONS; i++) { // Fill the buffer with random data and convert the buffer to hex. if (rand_write(PLACER(buffer, QP_CHECK_SIZE)) != QP_CHECK_SIZE) { return false; } else if (!(qp = qp_encode(PLACER(buffer, QP_CHECK_SIZE)))) { return false; } //log_pedantic("qp = %.*s", st_length_int(qp), st_char_get(qp)); // Convert the buffer back to binary and compare it with the original array. if (!(binary = qp_decode(qp))) { st_free(qp); return false; } else if (st_cmp_cs_eq(binary, PLACER(buffer, QP_CHECK_SIZE))) { st_free(binary); st_free(qp); return false; } st_free(binary); st_free(qp); } return true; }
bool_t check_bitwise_simple(void) { stringer_t *a, *b, *outcome, *check; unsigned char a_buf[] = {0x00, 0xFF, 0x88, 0x44, 0x22}; unsigned char b_buf[] = {0x11, 0x33, 0xF0, 0x0F, 0x3C}; unsigned char xor_buf[] = {0x11, 0xCC, 0x78, 0x4B, 0x1E}; unsigned char and_buf[] = {0x00, 0x33, 0x80, 0x04, 0x20}; unsigned char or_buf[] = {0x11, 0xFF, 0xF8, 0x4F, 0x3E}; unsigned char nota_buf[] = {0xFF, 0x00, 0x77, 0xBB, 0xDD}; a = PLACER(a_buf, 5); b = PLACER(b_buf, 5); check = PLACER(xor_buf, 5); if(!(outcome = st_xor(a, b, NULL)) || st_cmp_cs_eq(outcome, check)) { st_cleanup(outcome); return false; } check = PLACER(and_buf, 5); st_free(outcome); if(!(outcome = st_and(a, b, NULL)) || st_cmp_cs_eq(outcome, check)) { st_cleanup(outcome); return false; } check = PLACER(or_buf, 5); st_free(outcome); if(!(outcome = st_or(a, b, NULL)) || st_cmp_cs_eq(outcome, check)) { st_cleanup(outcome); return false; } check = PLACER(nota_buf, 5); st_free(outcome); if(!(outcome = st_not(a, NULL)) || st_cmp_cs_eq(outcome,check)) { st_cleanup(outcome); return false; } st_free(outcome); return true; }
/** * @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"); }
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; }
} END_TEST START_TEST (check_credential_auth_creation_s) { credential_t *cred; char *errmsg = NULL; log_unit("%-64.64s", "OBJECTS / USERS / CREDENTIALS / AUTH CREATION / SINGLE THREADED:"); if (!(cred = credential_alloc_auth(CONSTANT("ladar"), CONSTANT("test")))) { errmsg = "Credential creation failed."; } else if (st_cmp_cs_eq(cred->auth.password, CONSTANT("46c3c0f5c777aacbdb0c25b14d6889b98efa62fa0ae551ec067d7aa126392805e3e3a2ce07d36" \ "df7e715e24f35c88105fff5a9eebff0532f990644cf07a4751f"))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); cred = NULL; } if (!errmsg && !(cred = credential_alloc_auth(CONSTANT("*****@*****.**"), CONSTANT("test")))) { errmsg = "Credential creation failed."; } else if (!errmsg && st_cmp_cs_eq(cred->auth.password, CONSTANT("46c3c0f5c777aacbdb0c25b14d6889b98efa62fa0ae551ec067d7aa126392805e3e3a2ce07d36" \ "df7e715e24f35c88105fff5a9eebff0532f990644cf07a4751f"))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); } log_unit("%10.10s\n", (!status() ? "SKIPPED" : !errmsg ? "PASSED" : "FAILED")); fail_unless(!errmsg, errmsg); } END_TEST
/** * @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 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; }
END_TEST START_TEST(check_parser_header) { dmime_common_headers_t *header1, *header2; int res = 0; size_t outsize; unsigned char *formatted; header1 = dime_prsr_headers_create(); header1->headers[HEADER_TYPE_DATE] = st_import("11:34:12 AM March 12, 2004", 26); header1->headers[HEADER_TYPE_TO] = st_import("*****@*****.**", 13); header1->headers[HEADER_TYPE_CC] = st_import("*****@*****.**", 16); header1->headers[HEADER_TYPE_FROM] = st_import("*****@*****.**", 22); header1->headers[HEADER_TYPE_ORGANIZATION] = st_import("Cool people organization", 24); header1->headers[HEADER_TYPE_SUBJECT] = st_import("here's stuff", 12); formatted = dime_prsr_headers_format(header1, &outsize); ck_assert_msg(formatted != NULL, "Failed to format common headers.\n"); header2 = dime_prsr_headers_parse(formatted, outsize); ck_assert_msg(header2 != NULL, "Failed to parse common headers.\n"); res = st_cmp_cs_eq(header1->headers[HEADER_TYPE_DATE], header2->headers[HEADER_TYPE_DATE]); ck_assert_msg(res == 0, "Date header was corrupted.\n"); res = st_cmp_cs_eq(header1->headers[HEADER_TYPE_TO], header2->headers[HEADER_TYPE_TO]); ck_assert_msg(res == 0, "To header was corrupted.\n"); res = st_cmp_cs_eq(header1->headers[HEADER_TYPE_CC], header2->headers[HEADER_TYPE_CC]); ck_assert_msg(res == 0, "CC header was corrupted.\n"); res = st_cmp_cs_eq(header1->headers[HEADER_TYPE_FROM], header2->headers[HEADER_TYPE_FROM]); ck_assert_msg(res == 0, "From header was corrupted.\n"); res = st_cmp_cs_eq(header1->headers[HEADER_TYPE_ORGANIZATION], header2->headers[HEADER_TYPE_ORGANIZATION]); ck_assert_msg(res == 0, "Organization header was corrupted.\n"); res = st_cmp_cs_eq(header1->headers[HEADER_TYPE_SUBJECT], header2->headers[HEADER_TYPE_SUBJECT]); ck_assert_msg(res == 0, "Subject header was corrupted.\n"); dime_prsr_headers_destroy(header1); dime_prsr_headers_destroy(header2); free(formatted); fprintf(stderr, "DMIME common header parsing complete.\n"); }
bool_t check_encoding_url(void) { bool_t result = true; stringer_t *url, *binary; byte_t buffer[URL_CHECK_SIZE]; for (uint64_t i = 0; status() && result && i < URL_CHECK_ITERATIONS; i++) { // Fill the buffer with random data and convert the buffer to hex. if (rand_write(PLACER(buffer, URL_CHECK_SIZE)) != URL_CHECK_SIZE) { return false; } else if (!(url = url_encode(PLACER(buffer, URL_CHECK_SIZE)))) { return false; } else if (!url_valid_st(url)) { return false; } // Convert the buffer back to binary and compare it with the original array. if (!(binary = url_decode(url))) { st_free(url); return false; } else if (st_cmp_cs_eq(binary, PLACER(buffer, URL_CHECK_SIZE))) { result = false; } //log_pedantic("%-15.15s = %.*s", "plain", URL_CHECK_SIZE, buffer); //log_pedantic("%-15.15s = %.*s", "url", st_length_int(url), st_char_get(url)); //log_pedantic("%-15.15s = %.*s", "decoded", st_length_int(binary), st_char_get(binary)); st_free(binary); st_free(url); } 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 Create a new session for a given web connection. * @note The session stores the following data points: remote IP address, request path, application name, the specified http hostname, * the remote client's user agent string, the server's host number, a unique session id, the server's current timestamp, a randomly- * generated session key for authentication, and an encrypted token for the session returned to the user as a cookie. * @param con a pointer to the connection underlying the web session. * @param path a pointer to a managed string containing the pathname of the generating request (should be "/portal/camel"). * @param application a pointer to a managed string containing the name of the parent application of the session (should be "portal"). * @return NULL on failure or a pointer to a newly allocated session object for the specified connection. */ session_t *sess_create(connection_t *con, stringer_t *path, stringer_t *application) { session_t *output; multi_t key = { .type = M_TYPE_UINT64, .val.u64 = 0 }; if (!(output = mm_alloc(sizeof(session_t)))) { log_pedantic("Unable to allocate %zu bytes for a session context.", sizeof(session_t)); return NULL; } else if (pthread_mutex_init(&(output->lock), NULL) != 0) { log_pedantic("Unable to initialize reference lock for new user session."); mm_free(output); return NULL; } else if (!(output->compositions = inx_alloc(M_INX_LINKED, &sess_release_composition))) { log_pedantic("Unable to allocate space for user session's compositions."); mm_free(output); return NULL; } if (!(ip_copy(&(output->warden.ip), con_addr(con, MEMORYBUF(64)))) || (path && !(output->request.path = st_dupe_opts(MANAGED_T | HEAP | CONTIGUOUS, path))) || (application && !(output->request.application = st_dupe_opts(MANAGED_T | HEAP | CONTIGUOUS, application))) || (con->http.host && !(output->request.host = st_dupe_opts(MANAGED_T | HEAP | CONTIGUOUS, con->http.host))) || (con->http.agent && !(output->warden.agent = st_dupe_opts(MANAGED_T | HEAP | CONTIGUOUS, con->http.agent))) || !(output->warden.host = magma.host.number) || !(key.val.u64 = output->warden.number = sess_number()) || !(output->warden.stamp = time(NULL)) || !(output->warden.key = sess_key()) || !(output->warden.token = sess_token(output))) { log_pedantic("Unable to initialize the session warden context."); sess_destroy(output); return NULL; } output->request.httponly = true; output->request.secure = (con_secure(con) == 1 ? true : false); sess_ref_add(output); if (inx_insert(objects.sessions, key, output) != 1) { log_pedantic("Unable to insert the session into the global context."); sess_ref_dec(output); sess_destroy(output); return NULL; } return output; } /** * @brief Try to retrieve the session associated with a client connection's supplied cookie. * @param con a pointer to the connection object sending the cookie. * @param application a managed string containing the application associated with the session. * @param path a managed string containing the path associated with the session. * @param token the encrypted user token retrieved from the supplied http cookie. * @return 1 if the cookie was found and valid, or one of the following values on failure: * 0 = Session not found. * -1 = Server error. * -2 = Invalid token. * -3 = Security violation / incorrect user-agent. * -4 = Security violation / incorrect session key. * -5 = Security violation / incorrect source address. * -6 = Session terminated by logout. * -7 = Session timed out. */ int_t sess_get(connection_t *con, stringer_t *application, stringer_t *path, stringer_t *token) { uint64_t *numbers; scramble_t *scramble; stringer_t *binary, *encrypted; multi_t key = { .type = M_TYPE_UINT64, .val.u64 = 0 }; int_t result = 1; /// Most session attributes need simple equality comparison, except for timeout checking. Make sure not to validate against a stale session that should have already timed out (which will have to be determined dynamically). encrypted = zbase32_decode(token); scramble = scramble_import(encrypted); binary = scramble_decrypt(magma.secure.sessions, scramble); st_cleanup(encrypted); if (!binary) { return 0; } numbers = st_data_get(binary); // QUESTION: Is this necessary? doesn't inx_find() lock the inx? inx_lock_read(objects.sessions); key.val.u64 = *(numbers + 2); if ((con->http.session = inx_find(objects.sessions, key))) { sess_ref_add(con->http.session); } inx_unlock(objects.sessions); st_free(binary); // Return if we didn't find the session or user. if (!con->http.session || !con->http.session->user) { return 0; } // We need to do full validation against the cookie and associated session. // First, the cookie. if ((*numbers != con->http.session->warden.host) || (*(numbers + 1) != con->http.session->warden.stamp) || (*(numbers + 2) != con->http.session->warden.number)) { log_error("Received mismatched cookie for authenticated session { user = %s }", st_char_get(con->http.session->user->username)); result = -2; } else if (*(numbers + 3) != con->http.session->warden.key) { log_error("Cookie contained an incorrect session key { user = %s }", st_char_get(con->http.session->user->username)); result = -4; } else if (st_cmp_cs_eq(application, con->http.session->request.application)) { log_error("Cookie did not match session's application { user = %s }", st_char_get(con->http.session->user->username)); result = -2; } else if (st_cmp_cs_eq(path, con->http.session->request.path)) { log_error("Cookie did not match session's path { user = %s }", st_char_get(con->http.session->user->username)); result = -2; } else if (st_cmp_cs_eq(con->http.agent, con->http.session->warden.agent)) { log_error("Cookie contained a mismatched user agent { user = %s }", st_char_get(con->http.session->user->username)); result = -3; } else if (con->http.session->request.secure != (con_secure(con) ? 1 : 0)) { log_error("Cookie was submitted from a mismatched transport layer { user = %s }", st_char_get(con->http.session->user->username)); result = -5; } else if (!ip_address_equal(&(con->http.session->warden.ip), (ip_t *)con_addr(con, MEMORYBUF(64)))) { log_error("Cookie was submitted from a mismatched IP address { user = %s }", st_char_get(con->http.session->user->username)); result = -5; } // Finally, do comparisons to see that we haven't timed out. /* Did we expire? */ if (magma.http.session_timeout <= (time(NULL) - con->http.session->warden.stamp)) { log_pedantic("User submitted expired or invalidated cookie; marking for deletion { user = %s }", st_char_get(con->http.session->user->username)); result = -7; } // QUESTION: This destruction needs a second look. if (result < 0) { if (!inx_delete(objects.sessions, key)) { log_pedantic("Unexpected error occurred attempting to delete expired cookie { user = %s }", st_char_get(con->http.session->user->username)); } sess_ref_dec(con->http.session); //sess_destroy(con->http.session); con->http.session = NULL; } // Otherwise, if the last session status update is more than 10 minutes ago, check now to see if things are current. // QUESTION: Why is it 600 here and 120 elsewhere? else if ((time(NULL) - sess_refresh_stamp(con->http.session)) > 600) { sess_update(con->http.session); } return result; }
} END_TEST START_TEST (check_credential_mail_creation_s) { credential_t *cred; char *errmsg = NULL; log_unit("%-64.64s", "OBJECTS / USERS / CREDENTIALS / MAIL CREATION / SINGLE THREADED:"); if ((cred = credential_alloc_mail(CONSTANT("ladar")))) { errmsg = "Credential creation should have failed but didn't."; } if (cred) { credential_free(cred); cred = NULL; } if ((cred = credential_alloc_mail(CONSTANT("ladar@")))) { errmsg = "Credential creation should have failed but didn't."; } if (cred) { credential_free(cred); cred = NULL; } if ((cred = credential_alloc_mail(CONSTANT("@lavabit.com")))) { errmsg = "Credential creation should have failed but didn't."; } if (cred) { credential_free(cred); cred = NULL; } if (!errmsg && !(cred = credential_alloc_mail(CONSTANT("*****@*****.**")))) { errmsg = "Credential creation failed."; } else if (!errmsg && (st_cmp_cs_eq(cred->mail.address, CONSTANT("*****@*****.**")) || st_cmp_cs_eq(cred->mail.domain, CONSTANT("lavabit.com")))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); } if (!errmsg && !(cred = credential_alloc_mail(CONSTANT("*****@*****.**")))) { errmsg = "Credential creation failed."; } else if (!errmsg && (st_cmp_cs_eq(cred->mail.address, CONSTANT("*****@*****.**")) || st_cmp_cs_eq(cred->mail.domain, CONSTANT("lavabit.com")))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); } if (!errmsg && !(cred = credential_alloc_mail(CONSTANT("*****@*****.**")))) { errmsg = "Credential creation failed."; } else if (!errmsg && (st_cmp_cs_eq(cred->mail.address, CONSTANT("*****@*****.**")) || st_cmp_cs_eq(cred->mail.domain, CONSTANT("nerdshack.com")))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); } if (!errmsg && !(cred = credential_alloc_mail(CONSTANT("*****@*****.**")))) { errmsg = "Credential creation failed."; } else if (!errmsg && (st_cmp_cs_eq(cred->mail.address, CONSTANT("*****@*****.**")) || st_cmp_cs_eq(cred->mail.domain, CONSTANT("nerdshack.com")))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); } if (!errmsg && !(cred = credential_alloc_mail(CONSTANT("*****@*****.**")))) { errmsg = "Credential creation failed."; } else if (!errmsg && (st_cmp_cs_eq(cred->mail.address, CONSTANT("*****@*****.**")) || st_cmp_cs_eq(cred->mail.domain, CONSTANT("mailshack.com")))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); } if (!errmsg && !(cred = credential_alloc_mail(CONSTANT("*****@*****.**")))) { errmsg = "Credential creation failed."; } else if (!errmsg && (st_cmp_cs_eq(cred->mail.address, CONSTANT("*****@*****.**")) || st_cmp_cs_eq(cred->mail.domain, CONSTANT("mailshack.com")))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); } if (!errmsg && !(cred = credential_alloc_mail(CONSTANT("*****@*****.**")))) { errmsg = "Credential creation failed."; } else if (!errmsg && (st_cmp_cs_eq(cred->mail.address, CONSTANT("*****@*****.**")) || st_cmp_cs_eq(cred->mail.domain, CONSTANT("domain.com")))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); } if (!errmsg && !(cred = credential_alloc_mail(CONSTANT("*****@*****.**")))) { errmsg = "Credential creation failed."; } else if (!errmsg && (st_cmp_cs_eq(cred->mail.address, CONSTANT("*****@*****.**")) || st_cmp_cs_eq(cred->mail.domain, CONSTANT("domain.com")))) { errmsg = "The credential password hash doesn't match the expected value."; } if (cred) { credential_free(cred); } log_unit("%10.10s\n", (!status() ? "SKIPPED" : !errmsg ? "PASSED" : "FAILED")); fail_unless(!errmsg, errmsg); } END_TEST
/** * @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 Lookup user and return their meta user object. * * @note If the user is not found in the local session cache, the session will be constructed using the database, and then cached. * * @param usernum the numeric identifier for the user account. * @param username the official username stored in the database. * @param salt the user specific salt value. * @param master the user account's master encryption key which will be used to unlock the private storage key. * @param verification the verification token. * @param protocol a set of protocol specifying the protocol used by the calling function. Values can be META_PROT_NONE, * META_PROT_SMTP, META_PROT_POP, META_PROT_IMAP, META_PROT_WEB, or META_PROT_GENERIC. * @param get a set of protocol specifying the data to be retrieved (META_GET_NONE, META_GET_MESSAGES, * META_GET_FOLDERS, or META_GET_CONTACTS) * @param output the address of a meta user object that will store a pointer to the result of the lookup. * * @return -1 on error, 0 on success, 1 for an authentication issue. */ int_t meta_get(uint64_t usernum, stringer_t *username, stringer_t *salt, stringer_t *master, stringer_t *verification, META_PROTOCOL protocol, META_GET get, meta_user_t **output) { int_t state; meta_user_t *user = NULL; // If the auth structure is empty, or the usernum is invalid, return an error immediately. if (!usernum || !st_populated(username, master, verification)) { log_pedantic("Invalid parameters were used to get the meta data object."); return -1; } // Pull the user context using the usernum, or add an empty context if it doesn't exist. if (!(user = meta_inx_find(usernum, protocol))) { log_pedantic("Could not find an existing user object, nor could we create one."); return -1; } meta_user_wlock(user); // Pull the user information. if ((state = meta_update_user(user, META_LOCKED)) < 0) { meta_user_unlock(user); meta_inx_remove(usernum, protocol); return state; } // The auth_t object should have checked the verification token already, but we check here just to be sure. else if (st_empty(user->verification) || st_cmp_cs_eq(verification, user->verification)) { meta_user_unlock(user); meta_inx_remove(usernum, protocol); return 1; } // Are we supposed to get the realm keys. if ((get & META_GET_KEYS) && meta_update_realms(user, salt, master, META_LOCKED) < 0) { meta_user_unlock(user); meta_inx_remove(usernum, protocol); return -1; } // Are we supposed to get the mailbox keys. if ((get & META_GET_KEYS) && meta_update_keys(user, META_LOCKED) < 0) { // If key decryption fails, then the master key is likely invalid, so we need to ensure we don't cache an invalid // realm key as a result. st_cleanup(user->realm.mail); user->realm.mail = NULL; meta_user_unlock(user); meta_inx_remove(usernum, protocol); return -1; } // Are we supposed to get the mailbox aliases. if ((get & META_GET_ALIASES) && meta_update_aliases(user, META_LOCKED) < 0) { meta_user_unlock(user); meta_inx_remove(usernum, protocol); return -1; } // Are we supposed to get the messages. if ((get & META_GET_MESSAGES) && meta_messages_update(user, META_LOCKED) < 0) { meta_user_unlock(user); meta_inx_remove(usernum, protocol); return -1; } if ((get & META_GET_FOLDERS) && meta_update_message_folders(user, META_LOCKED) < 0) { meta_user_unlock(user); meta_inx_remove(usernum, protocol); return -1; } // Are we supposed to update the folders. if ((get & META_GET_FOLDERS) && meta_update_folders(user, META_LOCKED) < 0) { meta_user_unlock(user); meta_inx_remove(usernum, protocol); return -1; } // Are we supposed to update the folders. if ((get & META_GET_CONTACTS) && meta_update_contacts(user, META_LOCKED) < 0) { meta_user_unlock(user); meta_inx_remove(usernum, protocol); return -1; } *output = user; meta_user_unlock(user); return 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; }
/** * @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 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; }
/** * @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; }