示例#1
0
/**
 * @brief	Accept a username for POP3 authentication.
 * @note	This command is only allowed for sessions which have not yet been authenticated.
 * 			If the username has already been supplied pre-authentication, the old value will be overwritten with the new one.
 * @param	con		the POP3 client connection issuing the command.
 * @brief	This function returns no value.
 */
void pop_user(connection_t *con) {

	stringer_t *username, *clean;

	if (con->pop.session_state != 0) {
		pop_invalid(con);
		return;
	}

	// If they didn't pass in a valid username.
	if (!(username = pop_user_parse(con)) || !(clean = credential_address(username))) {
		con_write_bl(con, "-ERR Invalid USER command.\r\n", 28);
		st_cleanup(username);
		return;
	}

	// Check for a previously provided value and free it.
	st_cleanup(con->pop.username);
	st_free(username);

	// Store the value we were given. Until authentication, this will be the fully qualified username.
	con->pop.username = clean;

	// Tell the client everything worked.
	con_write_bl(con, "+OK Username accepted.\r\n", 24);

	return;
}
示例#2
0
stringer_t * check_rand_mthread(void) {

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

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

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

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

	mm_free(threads);
	return result;
}
示例#3
0
/**
 * @brief	Destroy a web session and its associated data.
 * @param	sess	a pointer to the web session to be destroyed.
 * @return	This function returns no value.
 */
void sess_destroy(session_t *sess) {

	if (sess) {

		if (sess->user) {
			meta_remove(sess->user->username, META_PROT_WEB);
		}

		st_cleanup(sess->warden.token);
		st_cleanup(sess->warden.agent);

		// Release the credential.
		if (sess->warden.cred) {
			credential_free(sess->warden.cred);
			sess->warden.cred = NULL;
		}

		st_cleanup(sess->request.host);
		st_cleanup(sess->request.path);
		st_cleanup(sess->request.application);
		inx_cleanup(sess->compositions);

		mutex_destroy(&(sess->lock));
		mm_free(sess);
	}

	return;
}
示例#4
0
文件: legacy.c 项目: lavabit/magma
void auth_legacy_free(auth_legacy_t *legacy) {
	if (legacy) {
		st_cleanup(legacy->key);
		st_cleanup(legacy->token);
		mm_free(legacy);
	}
	return;
}
示例#5
0
/**
 * @brief	Free an SMTP inbound filter and its underlying data.
 * @param	filter		a pointer to the SMTP inbound filter to be destroyed.
 * @return	This function returns no value.
 */
void smtp_list_free_filter(smtp_inbound_filter_t *filter) {

	st_cleanup(filter->label);
	st_cleanup(filter->field);
	st_cleanup(filter->expression);
	mm_free(filter);

	return;
}
示例#6
0
/**
 * @brief	Free an attachment object.
 * @note	This is an inx helper function.
 * @param	attachment	a pointer to the attachment object to be destroyed.
 * @return	This function returns no value.
 */
void sess_release_attachment(attachment_t *attachment) {

	if (attachment) {
		st_cleanup(attachment->filename);
		st_cleanup(attachment->filedata);
		mm_free(attachment);
	}

}
示例#7
0
/**
 * @brief	Merge a list of smtp message headers into a single string, preceded by the leading text and followed by the trailing text.
 * @param	headers		an inx holder containing a collection of header string data to be merged together.
 * @param	leading		a managed string containing text that will lead each header line.
 * @param	trailing	a managed string containing text that will trail each header line.
 * @return	NULL on failure or a managed string containing the merged headers on success.
 */
stringer_t * portal_smtp_merge_headers(inx_t *headers, stringer_t *leading, stringer_t *trailing) {

	stringer_t *result = NULL, *tmp, *current;
	inx_cursor_t *cursor;

	if (!headers || !leading || !trailing) {
		return NULL;
	}

	if (!(cursor = inx_cursor_alloc(headers))) {
		return NULL;
	}

	while ((current = inx_cursor_value_next(cursor))) {

		if (!(tmp = st_merge("ssss", result, leading, current, trailing))) {
			inx_cursor_free(cursor);
			st_cleanup(result);
			return NULL;
		}

		result = tmp;
	}

	inx_cursor_free(cursor);

	// We should at least return an empty managed string if we have a valid inx holder but no data in it.
	if (!result) {
		result = st_alloc(0);
	}

	return result;
}
示例#8
0
文件: cache.c 项目: lavabit/magma
/**
 * @brief	Set the contents of the thread's mail cache.
 * @param	messagenum	the numerical id of the message to be cached.
 * @text	a managed string containing the contents of the specified message to be cached.
 * @return	This function returns no value.
 */
void mail_cache_set(uint64_t messagenum, stringer_t *text) {

	mail_cache_t *message;

	if (!(message = pthread_getspecific(mail_cache))) {

		if (!(message = mm_alloc(sizeof(mail_cache_t)))) {
			return;
		}

		if (pthread_setspecific(mail_cache, message) != 0) {
			log_pedantic("Unable to setup thread message cache.");
			mm_free(message);
			return;
		}
	}
	else {
		st_cleanup(message->text);
	}

	message->messagenum = messagenum;
	message->text = st_dupe_opts(MANAGED_T | HEAP | CONTIGUOUS, text);

	return;
}
示例#9
0
stringer_t * check_rand_sthread(void) {

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

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

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

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

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

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

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

	st_cleanup(buffer);

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

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

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

	return NULL;
}
示例#10
0
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;
}
示例#11
0
void imap_session_destroy(connection_t *con) {

	inx_cursor_t *cursor;
	meta_message_t *active;

	meta_user_wlock(con->imap.user);

	// If a folder was selected, clear the recent flag before closing the mailbox.
	if (con->imap.session_state == 1 && con->imap.user && con->imap.selected && !con->imap.read_only &&
		(cursor = inx_cursor_alloc(con->imap.user->messages))) {

		while ((active = inx_cursor_value_next(cursor))) {

			if (active->foldernum == con->imap.selected && (active->status & MAIL_STATUS_RECENT) == MAIL_STATUS_RECENT) {
				active->status = (active->status | MAIL_STATUS_RECENT) ^ MAIL_STATUS_RECENT;
			}

		}

		inx_cursor_free(cursor);
	}

	meta_user_unlock(con->imap.user);

	// Is there a user session.
	if (con->imap.user) {

		if (con->imap.username) {
			meta_remove(con->imap.username, META_PROT_IMAP);
		}

	}

	st_cleanup(con->imap.username);
	st_cleanup(con->imap.tag);
	st_cleanup(con->imap.command);

	if (con->imap.arguments) {
		ar_free(con->imap.arguments);
	}

	mail_cache_reset();

	return;
}
示例#12
0
/**
 * @brief	Free a list of SMTP inbound mail preferences and its underlying data.
 * @param	inbound		a pointer to the head of the SMTP inbound mail preferences list to be destroyed.
 * @return	This function returns no value.
 */
void smtp_free_inbound(smtp_inbound_prefs_t *inbound) {

	smtp_inbound_prefs_t *holder;

	while (inbound) {
		st_cleanup(inbound->rcptto);
		st_cleanup(inbound->address);
		st_cleanup(inbound->domain);
		st_cleanup(inbound->forwarded);
		st_cleanup(inbound->spamsig);
		inx_cleanup(inbound->filters);
		holder = inbound;
		inbound = (smtp_inbound_prefs_t *)holder->next;
		mm_free(holder);
	}

	return;
}
示例#13
0
/**
 * @brief	Destroy the data associated with an SMTP session.
 * @param	con		the SMTP client connection to be destroyed.
 * @return	This function returns no value.
 */
void smtp_session_destroy(connection_t *con) {

	st_cleanup(con->smtp.helo);
	st_cleanup(con->smtp.mailfrom);

	if (con->smtp.message) {
		mail_destroy_message(con->smtp.message);
	}

	if (con->smtp.in_prefs) {
		smtp_free_inbound(con->smtp.in_prefs);
	}

	if (con->smtp.out_prefs) {
		smtp_free_outbound(con->smtp.out_prefs);
	}

	return;
}
示例#14
0
文件: orgs.c 项目: lavabit/magma
/**
 * @brief	Derive an organizational signet from the corresponding private key structures.
 */
prime_org_signet_t * org_signet_generate(prime_org_key_t *org) {

	prime_org_signet_t *signet = NULL;
	stringer_t *signing = NULL, *encryption = NULL, *cryptographic = MANAGEDBUF(69);

	// Ensure the org structure contains the necessary private keys.
	if (!org || !org->encryption || !org->signing || org->signing->type != ED25519_PRIV) {
		return NULL;
	}
	else if (!(signet = mm_alloc(sizeof(prime_org_signet_t)))) {
		return NULL;
	}
	// Store the public singing, and encryption keys.
	else if (!(signing = ed25519_public_get(org->signing, NULL)) ||
		!(encryption = secp256k1_public_get(org->encryption, NULL))) {
		log_pedantic("PRIME organizational signet generation failed, the public keys could not be derived from the provided private keys.");
		org_signet_free(signet);
		st_cleanup(signing);
		return NULL;
	}

	// Generate a serialized signet with the cryptographic fields.
	else if (st_write(cryptographic, prime_field_write(PRIME_ORG_SIGNET, 1, ED25519_KEY_PUB_LEN, signing, MANAGEDBUF(34)),
		prime_field_write(PRIME_ORG_SIGNET, 3, SECP256K1_KEY_PUB_LEN, encryption, MANAGEDBUF(35))) != 69) {
		log_pedantic("PRIME organizational signet generation failed, the serialized cryptographic signet could not be derived.");
		org_signet_free(signet);
		st_free(encryption);
		st_free(signing);
		return NULL;
	}

	// Generate a signature using the serialized cryptographic fields.
	else if (!(signet->signature = ed25519_sign(org->signing, cryptographic, NULL))) {
		log_pedantic("PRIME organizational signet generation failed, the cryptographic signet signature could not be derived.");
		org_signet_free(signet);
		st_free(encryption);
		st_free(signing);
		return NULL;
	}

	// Finally, convert the serialized public keys into usable structures.
	else if (!(signet->signing = ed25519_public_set(signing)) || !(signet->encryption = secp256k1_public_set(encryption))) {
		log_pedantic("PRIME organizational signet generation failed, the serialized public keys could not be parsed.");
		org_signet_free(signet);
		st_free(encryption);
		st_free(signing);
		return NULL;
	}

	// We no longer need the serialized public keys.
	st_free(encryption);
	st_free(signing);

	return signet;
}
示例#15
0
文件: cache.c 项目: lavabit/magma
/**
 * @brief	Free a cached mail message.
 * @param	holder	a pointer to the cached mail message object to be freed.
 * @return	This function returns no value.
 */
void mail_cache_destroy(void *holder) {

	mail_cache_t *message = (mail_cache_t *)holder;

	 if (message) {
		 st_cleanup(message->text);
		 mm_free(message);
	 }

	 return;
}
示例#16
0
/**
 * @brief	Free a set of SMTP outbound mail preferences and its underlying data.
 * @param	outbound	a pointer to the SMTP outbound mail preferences set to be destroyed.
 * @return	This function returns no value.
 */
void smtp_free_outbound(smtp_outbound_prefs_t *outbound) {

	st_cleanup(outbound->domain);
	
	if (outbound->recipients) {
		smtp_free_recipients(outbound->recipients);
	}

	mm_free(outbound);

	return;
}
示例#17
0
/**
 * @brief	Free a list of SMTP recipients and its underlying data.
 * @param	recipients	a pointer to the head of the recipients list to be destroyed.
 * @return	This function returns no value.
 */
void smtp_free_recipients(smtp_recipients_t *recipients) {

	smtp_recipients_t *holder;

	while (recipients) {
		st_cleanup(recipients->address);
		holder = recipients;
		recipients = (smtp_recipients_t *)holder->next;
		mm_free(holder);
	}

	return;
}
示例#18
0
文件: cache.c 项目: lavabit/magma
/**
 * @brief	Reset the thread's mail cache and free any held message.
 * @return	This function returns no value.
 */
void mail_cache_reset(void) {

	mail_cache_t *message;

	if ((message = pthread_getspecific(mail_cache))) {
		st_cleanup(message->text);
		message->text = NULL;
		message->messagenum = 0;
		mm_free(message);
		pthread_setspecific(mail_cache, NULL);
	}

	return;
}
示例#19
0
END_TEST

START_TEST (check_credential_address_s) {

	stringer_t *cred;
	char *errmsg = NULL;

	log_unit("%-64.64s", "OBJECTS / USERS / CERDENTIALS / ADDRESS / SINGLE THREADED:");

	if (!errmsg && (!(cred = credential_address(CONSTANT("*****@*****.**"))) || st_cmp_ci_eq(cred, CONSTANT("*****@*****.**")))) {
		errmsg = "Address boiler failed [1].";
		//printf("r1 = %lx\n", (unsigned long) cred);	if (cred) printf("xxx: [%.*s] [%u]\n", (int)st_length_get(cred), st_char_get(cred), (int)st_length_get(cred));
	}

	st_cleanup(cred);
	cred = NULL;

	if (!errmsg && (!(cred = credential_address(CONSTANT("  TEST  @  DOMAIN.COM  "))) || st_cmp_ci_eq(cred, CONSTANT("*****@*****.**")))) {
		errmsg = "Address boiler failed [2].";
		//printf("r2 = %lx\n", (unsigned long) cred);	if (cred) printf("xxx: [%.*s] [%u]\n", (int)st_length_get(cred), st_char_get(cred), (int)st_length_get(cred));
	}

	st_cleanup(cred);
	cred = NULL;

	if (!errmsg && (!(cred = credential_address(CONSTANT("*****@*****.**"))) || st_cmp_ci_eq(cred, CONSTANT("*****@*****.**")))) {
		errmsg = "Address boiler failed [5].";
	}

	st_cleanup(cred);
	cred = NULL;

	if (!errmsg && (!(cred = credential_address(CONSTANT("*****@*****.**"))) || st_cmp_ci_eq(cred, CONSTANT("*****@*****.**")))) {
		errmsg = "Address boiler failed [2].";
		//printf("rx2 = %lx\n", (unsigned long) cred);	if (cred) printf("xxx: [%.*s] [%u]\n", (int)st_length_get(cred), st_char_get(cred), (int)st_length_get(cred));
	}

	st_cleanup(cred);
	cred = NULL;

	if (!errmsg && (!(cred = credential_address(CONSTANT("  TEST  @  DOMAIN.COM  "))) || st_cmp_ci_eq(cred, CONSTANT("*****@*****.**")))) {
		errmsg = "Address boiler failed [5].";
	}

	st_cleanup(cred);
	cred = NULL;

	if (!errmsg && (!(cred = credential_address(CONSTANT("*****@*****.**"))) || st_cmp_ci_eq(cred, CONSTANT("*****@*****.**")))) {
		errmsg = "Address boiler failed [11].";
	}

	st_cleanup(cred);
	cred = NULL;

	log_unit("%10.10s\n", (!status() ? "SKIPPED" : !errmsg ? "PASSED" : "FAILED"));
	fail_unless(!errmsg, errmsg);
} END_TEST
示例#20
0
文件: glwidget.cpp 项目: cheque/s3d
static bool load_scene_file(const char *name) {
    FILE *fp = fopen(name, "r");
    if (!fp) return false;

    if (scn != NULL) {
        close_gl(scn);
        scene_free(scn);
        st_cleanup();
    }
    lang_file(fp);
    if ((scn = scene_read()) == NULL)
        return false;
    fclose(fp);

    load_objects_gl(scn->objs);
    setup_programs_gl(scn, scn->objs);

    return true;
}
示例#21
0
文件: orgs.c 项目: lavabit/magma
stringer_t * org_signet_get(prime_org_signet_t *org, stringer_t *output) {

	size_t length;
	int_t written = 0;
	stringer_t *result = NULL;

	if (!org || !(length = org_signet_length(org))) {
		log_pedantic("An invalid org signet was supplied for serialization.");
		return NULL;
	}

	// See if we have a valid output buffer, or if output is NULL, allocate a buffer to hold the output.
	else if (output && (!st_valid_destination(st_opt_get(output)) || st_avail_get(output) < length)) {
		log_pedantic("An output string was supplied but it does not represent a buffer capable of holding the output.");
		return NULL;
	}
	else if (!output && !(result = st_alloc(length))) {
		log_pedantic("Could not allocate a buffer large enough to hold encoded result. { requested = %zu }", length);
		return NULL;
	}
	else if (!output) {
		output = result;
	}

	st_wipe(output);

	// Calculate the size, by writing out all the fields (minus the header) using a NULL output.
	length = st_write(NULL, prime_field_write(PRIME_ORG_SIGNET, 1, ED25519_KEY_PUB_LEN, ed25519_public_get(org->signing, MANAGEDBUF(32)), MANAGEDBUF(34)),
		prime_field_write(PRIME_ORG_SIGNET, 3, SECP256K1_KEY_PUB_LEN, secp256k1_public_get(org->encryption, MANAGEDBUF(33)), MANAGEDBUF(35)),
		prime_field_write(PRIME_ORG_SIGNET, 4, ED25519_SIGNATURE_LEN, org->signature, MANAGEDBUF(65)));

	// Then output them again into the actual output buffer, but this time include the header. This is very primitive serialization logic.
	if ((written = st_write(output, prime_header_org_signet_write(length, MANAGEDBUF(5)),
		prime_field_write(PRIME_ORG_SIGNET, 1, ED25519_KEY_PUB_LEN, ed25519_public_get(org->signing, MANAGEDBUF(32)), MANAGEDBUF(34)),
		prime_field_write(PRIME_ORG_SIGNET, 3, SECP256K1_KEY_PUB_LEN, secp256k1_public_get(org->encryption, MANAGEDBUF(33)), MANAGEDBUF(35)),
		prime_field_write(PRIME_ORG_SIGNET, 4, ED25519_SIGNATURE_LEN, org->signature, MANAGEDBUF(65)))) != (length + 5)) {
		log_pedantic("The organizational signet didn't serialize to the expected length. { written = %i }", written);
		st_cleanup(result);
		return NULL;
	}

	return output;
}
示例#22
0
/**
 * @brief	Securely generate a unique zbase32-encoded token for a session.
 * @param	sess	a pointer to the input web session.
 * @return	a managed string containing the generated web session token.
 */
stringer_t * sess_token(session_t *sess) {

	scramble_t *encrypted = NULL;
	stringer_t *binary = NULL, *encoded = NULL;

	if (!(binary = st_merge("ssss", PLACER(&(sess->warden.host), sizeof(uint64_t)), PLACER(&(sess->warden.stamp), sizeof(uint64_t)),
		PLACER(&(sess->warden.number),	sizeof(uint64_t)), PLACER(&(sess->warden.key), sizeof(uint64_t)))) ||
		!(encrypted = scramble_encrypt(magma.secure.sessions, binary)) ||
		!(encoded = zbase32_encode(PLACER(encrypted, scramble_total_length(encrypted))))) {
		log_pedantic("An error occurred while trying to generate the session token.");
	}

	if (encrypted) {
		scramble_free(encrypted);
	}

	st_cleanup(binary);

	return encoded;
}
示例#23
0
文件: opengl.c 项目: cheque/s3d
void init_gl(Scene *s)
{
  GLint ntexu, ntexc;

  if( glewInit() != GLEW_OK ) 
    { printf( "[error] %s\n", glewGetErrorString( glewInit() ) ); return; }

  glGetIntegerv(GL_MAX_TEXTURE_COORDS, &ntexc);
  glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &ntexu);
  max_textures_gl = MAX(ntexc, ntexu) - 1;

  glClearColor( 0, 0, 0, 1);
  glEnable(GL_DEPTH_TEST);
  glShadeModel(GL_SMOOTH);

  if (render_to_fbo)
    init_fbo(s);
  
  st_cleanup();
}
示例#24
0
/**
 * @brief	Free a mail mime object and its underlying data, and recursively free its children parts.
 * @param	mime	a pointer to the mail mime object to be freed.
 * @return	This function returns no value.
 */
void mail_mime_free(mail_mime_t *mime) {

	size_t increment, elements;

	if (!mime) {
		return;
	}

	if (mime->children) {
		elements = ar_length_get(mime->children);

		for (increment = 0; increment < elements; increment++) {
			mail_mime_free((mail_mime_t *)ar_field_ptr(mime->children, increment));
		}

		ar_free(mime->children);
	}

	st_cleanup(mime->boundary);
	mm_free(mime);

	return;
}
示例#25
0
/**
 * @brief	Reset an SMTP session to its initialized state.
 * @param	con		the SMTP client connection to be reset.
 * @return	This function returns no value.
 */
void smtp_session_reset(connection_t *con) {

	st_cleanup(con->smtp.mailfrom);
	con->smtp.mailfrom = NULL;

	if (con->smtp.message) {
		mail_destroy_message(con->smtp.message);
		con->smtp.message = NULL;
	}

	if (con->smtp.in_prefs) {
		smtp_free_inbound(con->smtp.in_prefs);
		con->smtp.in_prefs = NULL;
	}

	if (con->smtp.out_prefs && con->smtp.out_prefs->recipients) {
		smtp_free_recipients(con->smtp.out_prefs->recipients);
		con->smtp.out_prefs->recipients = NULL;
	}

	// For unauthenticated sessions, reset the max length to zero and then adjust it when a recipient is provided.
	if (!con->smtp.out_prefs) {
		con->smtp.max_length = 0;
	}

	con->smtp.checked.rbl = 0;
	con->smtp.checked.spf = 0;
	con->smtp.checked.dkim = 0;
	con->smtp.checked.virus = 0;

	con->smtp.suggested_eight_bit = false;
	con->smtp.suggested_length = 0;
	con->smtp.num_recipients = 0;

	return;
}
示例#26
0
文件: meta.c 项目: lavabit/magma
/**
 * @brief	Free a meta user object.
 *
 * @param	user	a pointer to the meta user object to be destroyed.
 *
 * @return	This function returns no value.
 */
void meta_free(meta_user_t *user) {

	if (user) {

		prime_cleanup(user->prime.key);
		prime_cleanup(user->prime.signet);

		inx_cleanup(user->aliases);
		inx_cleanup(user->folders);
		inx_cleanup(user->message_folders);
		inx_cleanup(user->messages);
		inx_cleanup(user->contacts);

		st_cleanup(user->username, user->verification, user->realm.mail);

		// When read/write locking issues have been fixed, this line can be used once again.
		rwlock_destroy(&(user->lock));
		mutex_destroy(&(user->refs.lock));

		mm_free(user);
	}

	return;
}
示例#27
0
/**
 * @brief	Get the boundary from a MIME header.
 * @note	This function first scans the value of Content-Type for the boundary, and then the rest of the MIME header.
 * @param	header	a placer pointing to the MIME header to be parsed.
 * @return	NULL on failure, or a pointer to a managed string containing the MIME boundary string on success.
 */
stringer_t * mail_mime_boundary(placer_t header) {

	chr_t *stream;
	int_t quote = 0;
	size_t length, bounder;
	stringer_t *holder, *haystack, *boundary, *content;

	// Get the content type line from the header.
	if ((content = mail_header_fetch_all(&header, PLACER("Content-Type", 12)))) {
		haystack = PLACER(st_char_get(content), st_length_get(content));
	}
	// If there is no content line, search the entire header.
	else {
		haystack = &header;
	}

	// Find the boundary.
	if (!st_search_ci(haystack, PLACER("boundary", 8), &bounder)) {
		log_pedantic("We couldn't find the MIME boundary.");
		st_cleanup(content);
		return NULL;
	}

	// Get setup.
	length = st_length_get(haystack) - bounder;
	stream = st_char_get(haystack) + bounder + 8;

	// Skip the garbage.
	while (length != 0 && quote == 0 && (*stream == '"' || *stream == ' ' || *stream == '\r' || *stream == '\n' || *stream == '\t' || *stream == '=')) {

		if (*stream == '"') {
			quote = 1;
		}

		stream++;
		length--;
	}

	// How long is the boundary.
	bounder = 0;

	while (length != 0 && *stream != '"' && *stream != '\r' && *stream != '\n' && *stream != '\t' && *stream != ';' && (quote == 1 || *stream != ' ')) {
		stream++;
		bounder++;
		length--;
	}

	// Is there something to extract.
	if (!length) {
		log_pedantic("We couldn't find the MIME boundary.");
		st_cleanup(content);
		return NULL;
	}

	// Setup a placer with the boundary.
	holder = PLACER(stream - bounder, bounder);

	// Create the boundary search string.
	if (!(boundary = st_merge("ns", "--", holder))) {
		log_error("Failed to allocate space for boundary string.");
		st_cleanup(content);
		return NULL;
	}

	// Release the stringer, if it was used.
	st_cleanup(content);

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

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

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

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

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

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

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

	}

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

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

	return result;
}
示例#29
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;
}
示例#30
0
/**
 * @brief	Destroy and free a generic connection object after executing its protocol-specific destructor; update any statistics accordingly.
 * @param	con		a pointer to the connection to be destroyed.
 * @return	This function returns no value.
 */
void con_destroy(connection_t *con) {

	if (con && !con_decrement_refs(con)) {

		switch (con->server->protocol) {
			case (POP):

				if (con->network.ssl) {
					stats_decrement_by_name("pop.connections.secure");
				}

				stats_decrement_by_name("pop.connections.total");
				pop_session_destroy(con);
				break;
			case (IMAP):
				if (con->network.ssl) {
					stats_decrement_by_name("imap.connections.secure");
				}

				stats_decrement_by_name("imap.connections.total");
				imap_session_destroy(con);
				break;
			case (HTTP):
				if (con->network.ssl) {
					stats_decrement_by_name("http.connections.secure");
				}

				stats_decrement_by_name("http.connections.total");
				http_session_destroy(con);
				break;
			case (SMTP):
				if (con->network.ssl) {
					stats_decrement_by_name("smtp.connections.secure");
				}

				stats_decrement_by_name("smtp.connections.total");
				smtp_session_destroy(con);
				break;
			case (SUBMISSION):
				if (con->network.ssl) {
					stats_decrement_by_name("smtp.connections.secure");
				}

				stats_decrement_by_name("smtp.connections.total");
				smtp_session_destroy(con);
				break;
			case (MOLTEN):
				if (con->network.ssl) {
					stats_decrement_by_name("molten.connections.secure");
				}

				stats_decrement_by_name("molten.connections.total");
				molten_session_destroy(con);
				break;
			default:
				break;
		}

		if (con->network.ssl) {
			ssl_free(con->network.ssl);
		}

		if (con->network.sockd != -1) {
			close(con->network.sockd);
		}

		st_cleanup(con->network.buffer);
		st_cleanup(con->network.reverse.domain);
		mutex_destroy(&(con->lock));
		mm_free(con);
	}

	return;
}