示例#1
0
bool_t check_tokyo_tank(check_tank_opt_t *opts) {

	inx_t *check_collection = NULL;

	if (!(check_collection = inx_alloc(M_INX_LINKED, &mm_free))) {
		return false;
	}

	else if (!check_tokyo_tank_load(tank_check_data_path, check_collection, opts)) {
		inx_free(check_collection);
		return false;
	}

	else if (!check_tokyo_tank_verify(check_collection)) {
		inx_free(check_collection);
		return false;
	}

	else if (TANK_CHECK_DATA_CLEANUP && !check_tokyo_tank_cleanup(check_collection)) {
		inx_free(check_collection);
		return false;
	}

	inx_free(check_collection);
	return true;
}
示例#2
0
文件: inx_check.c 项目: lavabit/magma
bool_t check_inx_append_mthread(MAGMA_INDEX inx_type, stringer_t *errmsg) {

	void *result;
	inx_t *inx = NULL;
	bool_t outcome = true;
	pthread_t *threads = NULL;

	if (status() && (!(inx = inx_alloc(inx_type | M_INX_LOCK_MANUAL, &ns_free)))) {
		st_sprint(errmsg, "An error occured during initial allocation in the inx check append multi-threaded test.");
		outcome = false;
	}
	else {

		if (!INX_CHECK_MTHREADS || !(threads = mm_alloc(sizeof(pthread_t) * INX_CHECK_MTHREADS))) {
			outcome = false;
		}
		else {

			for (uint64_t counter = 0; counter < INX_CHECK_MTHREADS; counter++) {
				if (thread_launch(threads + counter, &check_inx_append_mthread_test, inx)) {
					st_sprint(errmsg, "An error occured when launching a thread.");
					outcome = false;
				}
			}

			for (uint64_t counter = 0; counter < INX_CHECK_MTHREADS; counter++) {
				if (thread_result(*(threads + counter), &result) || !result || !*(bool_t *)result) {
					if (st_empty(errmsg)) st_sprint(errmsg, "One of the append check threads returned false.");
					outcome = false;
				}

				mm_cleanup(result);
			}

			mm_free(threads);
		}

		if (inx_count(inx) != 0 && st_empty(errmsg)) {
			st_sprint(errmsg, "The index was not properly cleared.");
			outcome = false;
		}

	}

	if (inx) {
		inx_cleanup(inx);
	}

	return outcome;
}
示例#3
0
文件: inx_check.c 项目: lavabit/magma
bool_t check_inx_append_sthread(MAGMA_INDEX inx_type, stringer_t *errmsg) {

	inx_t *inx = NULL;
	bool_t outcome = true;

	if (status() && (!(inx = inx_alloc(inx_type | M_INX_LOCK_MANUAL, &ns_free)))) {
		st_sprint(errmsg, "An error occured during initial allocation in the inx check append single-threaded test.");
		outcome = false;
	}
	else if(!check_inx_append_helper(inx)) {
		st_sprint(errmsg, "An error occured inside append test helper.");
		outcome = false;
	}

	if (outcome && inx_count(inx) != 0) {
		st_sprint(errmsg, "The index was not properly cleared.");
		outcome = false;
	}

	inx_cleanup(inx);
	return outcome;
}
示例#4
0
/**
 * @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;
}
示例#5
0
/**
 * @brief	Parse a json string array into a linked list of managed strings.
 * @param	json	a json object containing an array of strings.
 * @param	nout	if not NULL, an optional pointer to a size_t to receive the item count of the json string array.
 * @return	NULL on failure, or a pointer to an inx holder containing the specified json array contents as a collection of managed strings.
 */
inx_t * portal_parse_json_str_array (json_t *json, size_t *nout) {

	inx_t *result;
	stringer_t *istr;
	const chr_t *str;
	size_t count;
	multi_t key = { .type = M_TYPE_UINT64, .val.u64 = 0 };

	if (!json) {
		log_pedantic("Portal cannot parse null json array.");
		return NULL;
	// The json object must be an array.
	} else if (!json_is_array(json)) {
		log_pedantic("Portal cannot parse mistyped json array.");
		return NULL;
	} else if (!(result = inx_alloc(M_INX_LINKED, st_free))) {
		log_error("Portal could not allocate space to parse json array.");
		return NULL;
	}

	// If it's an empty array, return right away.
	if (!(count = json_array_size_d(json))) {

		if (nout) {
			*nout = 0;
		}

		return result;
	}

	// Before starting a SQL transaction check that all of the array values are positive integer values.
	for (size_t i = 0; i < count; i++) {

		if (!json_is_string(json_array_get_d(json, i))) {
			log_pedantic("Portal cannot parse json string array with non-string element.");
			inx_free(result);
			return NULL;
		}

		if (!(str = json_string_value_d(json_array_get_d(json, i)))) {
			log_pedantic("Portal encountered json string array with NULL element.");
			inx_free(result);
			return NULL;
		}

		if (!(istr = st_import(str, ns_length_get(str)))) {
			log_error("Portal could not import string from json array.");
			inx_free(result);
			return NULL;
		}

		key.val.u64 = i+1;

		if (!inx_insert(result, key, istr)) {
			log_error("Portal could not prepare data from json array.");
			inx_free(result);
			return NULL;
		}

	}

	if (nout) {
		*nout = count;
	}

	return result;
}

/**
 * @brief	Parse the context of a requested folder.
 * @note	If no context is specified, the "mail" context is assumed (PORTAL_ENDPOINT_CONTEXT_MAIL).
 * @param	context		a managed string containing the context (supported values are "mail", "contacts", "settings", and "help").
 * @return	PORTAL_ENDPOINT_CONTEXT_INVALID on failure, or the flag of the determined context on success.
 */
int_t portal_parse_context(stringer_t *context) {

	int_t result = PORTAL_ENDPOINT_CONTEXT_MAIL;

	if (!context) {
		return result;
	}

	// Parse the context.
	if (!st_cmp_ci_eq(context, PLACER("mail", 4))) {
		result = PORTAL_ENDPOINT_CONTEXT_MAIL;
	}
	else if (!st_cmp_ci_eq(context, PLACER("contacts", 8))) {
		result = PORTAL_ENDPOINT_CONTEXT_CONTACTS;
	}
	else if (!st_cmp_ci_eq(context, PLACER("settings", 8))) {
		result = PORTAL_ENDPOINT_CONTEXT_SETTINGS;
	}
	else if (!st_cmp_ci_eq(context, PLACER("help", 4))) {
		result = PORTAL_ENDPOINT_CONTEXT_HELP;
	}
	else {
		result = PORTAL_ENDPOINT_CONTEXT_INVALID;
	}

	return result;
}