예제 #1
0
파일: local.c 프로젝트: tioui/EiffelStudio
rt_shared void initstk(void)
{
	/* Initialize both the local stack and the hector stack. Those two stacks
	 * may have their context saved and restored in an Eiffel routine, so they
	 * need to be correctly initialized.
	 * In workbench mode, the debugger stack is also created here.
	 */

	EIF_GET_CONTEXT
#ifdef ISE_GC
	char **top;
#endif


#ifdef EIF_ASSERTIONS
#if defined(EIF_WINDOWS) && defined(_DEBUG)

	int tmpDbgFlag = 0;
	_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
	_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
	_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
	_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
	_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
	_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

	tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
	tmpDbgFlag |= _CRTDBG_DELAY_FREE_MEM_DF;
	tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
	tmpDbgFlag |= _CRTDBG_CHECK_ALWAYS_DF;
	_CrtSetDbgFlag(tmpDbgFlag);
#endif
#endif

#if defined(EIF_WINDOWS) && defined(_MSC_VER)
		/* This is to catch CRT raised exception when passing incorrect arguments to CRT routines. */
	_set_invalid_parameter_handler(eif_invalid_paramter_handler);
#endif

#ifdef ISE_GC
	top = st_alloc(&loc_set, eif_stack_chunk);
	if (top != (char **) 0)
		top = st_alloc(&hec_stack, eif_stack_chunk);

	if (top == (char **) 0)
		eif_panic(MTC "can't create runtime stacks");
#endif

#ifdef WORKBENCH
	initdb();				/* Initialize debugger stack */
#endif
}
예제 #2
0
파일: inf2.c 프로젝트: wei-wang-523/cascade
int main(int a, int b){
	st_t * st1, * st2;
	ASSUME(a> 0);
	ASSUME(b > 0);
	
	st1 = st_alloc(a,b);
	
	st2 = st_alloc(-b,-a);
	
	
	st_compact(st1,st2);
	return 1;
	
}
예제 #3
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;
}
예제 #4
0
/**
 * @brief	Decompress data using the bzip engine.
 * @param	compressed	a pointer to the head of the compressed data.
 * @return	NULL on failure, or a managed string containing the uncompressed data on success.
 */
stringer_t * decompress_bzip(compress_t *compressed) {

	int ret;
	void *bptr;
	uint64_t hash, rlen, blen;
	stringer_t *result = NULL;
	compress_head_t *head;

	if (!(head = (compress_head_t *)compressed)) {
		log_info("Invalid compression header. {compress_head = NULL}");
		return NULL;
	} else if (head->engine != COMPRESS_ENGINE_BZIP) {
		log_info("The buffer passed in was not compressed using the BZIP engine. {engine = %hhu}", head->engine);
		return NULL;
	} else if (!(bptr = compress_body_data(compressed)) || !(blen = head->length.compressed) || !(rlen = head->length.original) || head->hash.compressed != (hash = hash_adler32(bptr, blen))) {
		log_info("The compressed has been corrupted. {expected = %lu / input = %lu}", head->hash.compressed, hash);
		return NULL;
	} else if (!(result = st_alloc(head->length.original + 1))) {
		log_info("Could not allocate a block of %lu bytes for the uncompressed data.", head->length.original);
		return NULL;
	} else if ((ret = BZ2_bzBuffToBuffDecompress_d(st_data_get(result), (unsigned int *)&rlen, bptr, blen, 0, 0)) != BZ_OK) {
		log_info("Unable to decompress the buffer. {BZ2_bzBuffToBuffDecompress = %i}", ret);
		st_free(result);
		return NULL;
	} else if (head->length.original != rlen || head->hash.original != (hash = hash_adler32(st_data_get(result), rlen))) {
		log_info("The uncompressed data is corrupted. {input = %lu != %lu / hash = %lu != %lu}", head->length.original, rlen, head->hash.original, hash);
		st_free(result);
		return NULL;
	}

	st_length_set(result, rlen);
	return result;
}
예제 #5
0
/**
 * @brief	Serialize an unsigned 16-bit integer into a managed string.
 * @note	This function will reallocate the output managed string if necessary, and append the serialized data, updating the length field to reflect the changes.
 * @param	data	a pointer to the address of a managed string to receive the output, which will be allocated for the caller if NULL is passed.
 * @param	number	the value of the unsigned 16-bit integer to be serialized.
 * @return	true if the specified value was serialized and stored successfully, or false on failure.
 */
bool_t serialize_uint16(stringer_t **data, uint16_t number) {
	
	stringer_t *holder = NULL;
	size_t length = uint16_digits(number);

	// Make sure we have room to write the number.
	if (!data) {
		return false;
	}
	else if (!*data && (*data = st_alloc(1024)) == NULL) {
		return false;
	}
	else if (st_avail_get(*data) - st_length_get(*data) < (length+1) && (holder = st_realloc(*data, st_avail_get(*data) + 1024)) == NULL) {
		return false;
	}
	else if (holder) {
		*data = holder;
	}
	
	if (length != snprintf(st_char_get(*data) + st_length_get(*data), st_avail_get(*data) - st_length_get(*data), "%hu", number)) {
		return false;
	}
	
	*(st_char_get(*data) + st_length_get(*data) + length) = ';';
	st_length_set(*data, st_length_get(*data) + length + 1);
	
	return true;
}
예제 #6
0
파일: main.c 프로젝트: tioui/EiffelStudio
rt_public void failure(void)
{
	/* A fatal Eiffel exception has occurred. The stack of exceptions is dumped
	 * and the memory is cleaned up, if possible.
	 */

  	GTCX
  		/* When we arrive at this location, the Eiffel call stack is theoratically
		 * empty, but `loc_set' still points to the location where the last Eiffel
		 * call has been made. Since now `loc_set' records address of C local variable
		 * which are usually located on the C call stack. Any addition to the C call
		 * stack (like the call to `trapsig' below) will corrupt the information
		 * stored in `loc_set' since it will replace a location by another.
		 *
		 * To prevent this, we have to manually empty `loc_set'. It does not matter
		 * at this point that the GC forgets about all objects referenced through
		 * a local variable since all Eiffel calls have been executed.
		 * Doing so, enables a safe `reclaim' that will not traverse `loc_set'
		 * objects.
		 * We then create an empty `loc_set' as most of the run-time macros for stack
		 * management expect `loc_set' to have at least one chunk.
		 */
#ifdef ISE_GC
	st_reset (&loc_set);
	st_alloc (&loc_set, eif_stack_chunk);
#endif

	trapsig(emergency);					/* Weird signals are trapped */
	esfail(MTC_NOARG);							/* Dump the execution stack trace */

	reclaim();							/* Reclaim all the objects */
	exit(1);							/* Abnormal termination */

	/* NOTREACHED */
}
예제 #7
0
bool_t check_string_dupe(char *type, uint32_t check) {

	size_t len;
	stringer_t *s, *d;

	if (!(s = st_alloc(check, st_length_int(constant)))) {
		return false;
	}

	len = snprintf(st_char_get(s), st_length_int(constant) + 1, "%.*s", st_length_int(constant), st_char_get(constant));
	if (check & MAPPED_T || check & MANAGED_T) {
		st_length_set(s, len);
	}

	if (!(d = st_dupe(s))) {
		st_free(s);
		return false;
	}

	log_print("%28.28s = %.*s", type, st_length_int(d), st_char_get(d));

	if (memcmp(st_char_get(d), st_char_get(s), st_length_get(s))) {
		st_free(s);
		st_free(d);
		return false;
	}

	st_free(s);
	st_free(d);

	return true;
}
예제 #8
0
/**
 * @brief	Generate a MIME boundary string that is unique to a collection of content.
 * @param	parts	a pointer to an array of managed strings containing the MIME children data to be separated by the boundary.
 * @return	NULL on failure, or a pointer to a managed string containing the generated boundary on success.
 */
stringer_t * mail_mime_generate_boundary (array_t *parts) {

	stringer_t *result, *cmp;
	chr_t *ptr;
	size_t blen = 16;
	int_t rnd;

	if (!parts) {
		log_pedantic("Cannot generate mime boundary with empty input data.");
		return NULL;
	}

	if (!(result = st_alloc(blen))) {
		log_error("Unable to allocate space for boundary string.");
		return NULL;
	}

	// Keep generating boundary strings until one of them is unique... we don't expect collisions to happen that often.
	while (1) {
		srand(rand_get_uint64());
		ptr = st_char_get (result);

		// Generate blen's worth of random bytes, each being either a random digit or lowercase letter.
		for (size_t i = 0; i < blen; i++) {
			rnd = rand();

			if (rnd % 2) {
				*ptr++ = '0' + (rnd % 10);
			} else {
				*ptr ++ = 'a' + (rnd % 26);
			}

		}

		st_length_set(result, blen);

		// Now make sure it's not found in any of the parts.
		for (size_t i = 0; i < ar_length_get(parts); i++) {

			if (!(cmp = (stringer_t *) ar_field_ptr(parts, i))) {
				log_pedantic("Could not generate mime boundary for null content.");
				st_free(result);
				return NULL;
			}

			if (st_search_ci(cmp, result, NULL)) {
				continue;
			}

		}

		// If we made it this far, the boundary string was not found in any of the supplied content.
		break;
	}

	return result;
}
예제 #9
0
파일: hex.c 프로젝트: lavabit/magma
/**
 * @brief	Convert a hex string into a binary data blob.
 * @note	All hex strings should be composed of pairs of two hex characters representing individual bytes.
 * 			Invalid hex characters will simply be ignored during processing.
 * @param	h		a managed string containing the input hex string to be decoded.
 * @param	output	if not NULL, a pointer to a managed string to contain the decoded binary output; if NULL, a new string
 * 					will be allocated and returned to the caller.
 * @return	a pointer to a managed string containing the decoded output, or NULL on failure.
 */
stringer_t * hex_decode_st(stringer_t *h, stringer_t *output) {

	uint32_t opts = 0;
	uchr_t *p = NULL, *o, c = 0;
	size_t w = 0, len = 0, valid;
	stringer_t *result = NULL;

	if (output && !st_valid_destination((opts = *((uint32_t *)output)))) {
		log_pedantic("An output string was supplied but it does not represent a buffer capable of holding the output.");
		return NULL;
	}
	else if (st_empty_out(h, &p, &len) || !(valid = hex_count_st(h))) {
		log_pedantic("The input block does not appear to hold any data ready for decoding. {%slen = %zu}", p ? "" : "p = NULL / ", len);
		return NULL;
	}

	// Make sure the output buffer is large enough or if output was passed in as NULL we'll attempt the allocation of our own buffer.
	if ((result = output) && ((st_valid_avail(opts) && st_avail_get(output) < (valid / 2)) ||
			(!st_valid_avail(opts) && st_length_get(output) < (valid / 2)))) {
		log_pedantic("The output buffer supplied is not large enough to hold the result. {avail = %zu / required = %zu}",
				st_valid_avail(opts) ? st_avail_get(output) : st_length_get(output), valid / 2);
		return NULL;
	}
	else if (!output && !(result = st_alloc(valid / 2))) {
		log_pedantic("The output buffer memory allocation request failed. {requested = %zu}", (valid / 2));
		return NULL;
	}

	// Store the memory address where the output should be written.
	o = st_data_get(result);

	// Loop through the input buffer and translate valid characters into a binary octet.
	for (size_t i = 0; i < len; i++) {
		if (hex_valid_chr(*p)) {
			if (!c) {
				c = *p;
			}
			else {
				*o++ = hex_decode_chr(c, *p);
				c = 0;
				w++;
			}
		}
		p++;
	}

	// If an output buffer was supplied that is capable of tracking the data length, or a managed string buffer was allocated update the length param.
	if (!output || st_valid_tracked(opts)) {
		st_length_set(result, w);
	}

	return result;
}
예제 #10
0
// Check that we can't specify a length greater than the available buffer.
bool_t check_string_logic(uint32_t check) {

	stringer_t *s;

	if (!(s = st_alloc(check, 128)) || st_length_set(s, st_avail_get(s) * 2) != st_avail_get(s)) {
		if (s)
			st_free(s);
		return false;
	}

	st_free(s);
	return true;
}
예제 #11
0
파일: plugin.c 프로젝트: AriaAsuka/deadbeef
ddb_dsp_context_t*
st_open (void) {
    ddb_soundtouch_t *st = malloc (sizeof (ddb_soundtouch_t));
    DDB_INIT_DSP_CONTEXT (st,ddb_soundtouch_t,&plugin);
    st->st = st_alloc ();
    st->changed = 1;
    st->tempo = 0;
    st->rate = 0;
    st->pitch = 0;
    st->use_aa_filter = 0;
    st->aa_filter_length = 32;
    st->use_quickseek = 0;
    st->sequence_ms = 82;
    st->seekwindow_ms = 28;
    return (ddb_dsp_context_t *)st;
}
예제 #12
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;
}
예제 #13
0
파일: hex.c 프로젝트: lavabit/magma
/**
 * @brief	Convert a block of binary data into a hex string.
 * @param	b		a managed string containing the raw data to be encoded.
 * @param	output	if not NULL, a pointer to a managed string that will store the encoded output; if NULL, a new managed string will
 * 					be allocated and returned to the caller.
 * @return 	NULL on failure, or a pointer to a managed string containing the hex-encoded output on success.
 */
stringer_t * hex_encode_st(stringer_t *b, stringer_t *output) {

	size_t len = 0;
	uint32_t opts = 0;
	uchr_t *p = NULL, *o;
	stringer_t *result = NULL;

	if (output && !st_valid_destination((opts = *((uint32_t *)output)))) {
		log_pedantic("An output string was supplied but it does not represent a buffer capable of holding the output.");
		return NULL;
	}
	else if (st_empty_out(b, &p, &len)) {
		log_pedantic("The input block does not appear to hold any data ready for encoding. {%slen = %zu}", p ? "" : "p = NULL / ", len);
		return NULL;
	}

	// Make sure the output buffer is large enough or if output was passed in as NULL we'll attempt the allocation of our own buffer.
	if ((result = output) && ((st_valid_avail(opts) && st_avail_get(output) < (len * 2)) ||
			(!st_valid_avail(opts) && st_length_get(output) < (len * 2)))) {
		log_pedantic("The output buffer supplied is not large enough to hold the result. {avail = %zu / required = %zu}",
				st_valid_avail(opts) ? st_avail_get(output) : st_length_get(output), len * 2);
		return NULL;
	}
	else if (!output && !(result = st_alloc(len * 2))) {
		log_pedantic("The output buffer memory allocation request failed. {requested = %zu}", len * 2);
		return NULL;
	}

	// Store the memory address where the output should be written.
	o = st_data_get(result);

	// Loop through the input buffer and write character pairs to the result string data buffer.
	for (size_t i = 0; i < len; i++) {
		hex_encode_chr(*p, o);
		o += 2;
		p += 1;
	}

	// If an output buffer was supplied that is capable of tracking the data length, or a managed string buffer was allocated update the length param.
	if (!output || st_valid_tracked(opts)) {
		st_length_set(result, len * 2);
	}

	return result;
}
예제 #14
0
/**
 * @brief	Allocate and initialize a new network buffer for a connection, if it is not already associated with one.
 * @note	A network buffer of size magma.system.network_buffer bytes will be allocated for the connection if one does not exist.
 * @return	true if the connection object has been associated with a network buffer or false on failure.
 */
bool_t con_init_network_buffer(connection_t *con) {

	if (!con) {
		return false;
	}
	else if (con->network.buffer) {
		return true;
	}

	if (!(con->network.buffer = st_alloc(magma.system.network_buffer))) {
		log_info("Unable to allocate a network buffer of %u bytes.", magma.system.network_buffer);
		return false;
	}

	con->network.line = pl_null();

	return true;
}
예제 #15
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;
}
예제 #16
0
int
st_asn1_allocate_context(st_asn1_context* pContext) {
  void* p;
  int len;

  len = st_asn1_get_context_size();
  if (len < 0)
    return 0;

  p = st_alloc(len);
  if (p == NULL)
    return 0;

  if (st_asn1_allocate_context_ext(pContext, p, len))
    ((unsigned char*)p)[0] = 1; /* Set allocated flag */
  else
    st_free(p);

  return 1;
}
예제 #17
0
rt_public void eif_extend_object_id_stack (EIF_INTEGER nb_chunks)
	/* extends of `nb_chunks the size of `object_id_stack' */
{
#ifdef ISE_GC
	RT_GET_CONTEXT
	struct stack *st = &object_id_stack;
	char **top;
	struct stchunk * current;
	char **end;

	EIF_OBJECT_ID_LOCK;
	if (st->st_top == (char **) 0) {
		top = st_alloc(st, eif_stack_chunk);	/* Create stack */
		if (top == (char **) 0) {
			EIF_OBJECT_ID_UNLOCK;
			eraise ("Couldn't allocate object id stack", EN_MEM);
		}
				/* No memory */
		st->st_top = top; /* Update new top */
	} 
	current = st->st_cur;	/* save previous current stchunk */
	top = st->st_top;		/* save previous top of stack */
	end = st->st_end;		/*save previous st_end of stack */ 
	SIGBLOCK;		/* Critical section */
	while (--nb_chunks) {
		if (-1 == st_extend(st, eif_stack_chunk)) {
			EIF_OBJECT_ID_UNLOCK;
			eraise ("Couldn't allocate object id stack", EN_MEM);
		}
	}	
	st->st_cur = current;	/* keep previous Current */
	st->st_top = top;		/* keep previous top */
	st->st_end = end;
	
	SIGRESUME;		/* End of critical section */

	EIF_OBJECT_ID_UNLOCK;
#endif
}
예제 #18
0
파일: smap.c 프로젝트: ifzz/libsrt
sm_t *sm_alloc(const enum eSM_Type t, const size_t n)
{
	struct STConf f;
	smf_setup(t, &f);
	return (sm_t *)st_alloc(&f, n);
}
예제 #19
0
struct yasm *yasm_alloc(const char *pttfile)
{
	char *tmp;
	size_t n;
	struct yasm *y;

	if (bug_on(!pttfile))
		return NULL;

	y = calloc(1, sizeof(*y));
	if (!y)
		return NULL;

	y->fl = fl_alloc();
	if (!y->fl)
		goto error;

	y->st_asm = st_alloc();
	if (!y->st_asm)
		goto error;

	y->fileroot = duplicate_str(pttfile);
	if (!y->fileroot)
		goto error;

	y->pttfile = duplicate_str(pttfile);
	if (!y->pttfile)
		goto error;

	tmp = strrchr(y->fileroot, '.');
	if (tmp)
		*tmp = '\0';

	tmp = strrchr(y->fileroot, path_separator);
	if (tmp) {
		tmp += 1;
		memmove(y->fileroot, tmp, strlen(tmp)+1);
	}

	y->binfile = malloc(strlen(y->fileroot)+strlen(bin_suffix)+1);
	if (!y->binfile)
		goto error;

	y->lstfile = malloc(strlen(y->fileroot)+strlen(lst_suffix)+1);
	if (!y->lstfile)
		goto error;

	n = strlen(y->fileroot);

	strcpy(y->binfile, y->fileroot);
	strcpy(y->binfile+n, bin_suffix);
	strcpy(y->lstfile, y->fileroot);
	strcpy(y->lstfile+n, lst_suffix);

	y->l = l_alloc();
	if (!y->l)
		goto error;

	return y;

error:
	yasm_free(y);
	return 0;
}
예제 #20
0
/**
 * @brief	Extract the contents of a quoted string and advance the position of the parser stream.
 * @note	This function scans a string beginning with '"' for a terminating '"', returning an error if \r or \n is encountered first.
 * 			It is also able to handle escaped characters.
 * 			The supplied start and length pointers will be updated to reflect the input stream if the quoted string is parsed successfully.
 * @param	output	the address of a managed string that will receive a copy of the quoted string's contents on success, or NULL on failure or if it is zero length.
 * @param	start	the address of a pointer to the start of the buffer to be parsed (beginning with \"), that will also be updated to
 * 					point to the next argument in the sequence on success.
 * @param	length	a pointer to a size_t variable that contains the length of the string to be parsed, and which will be updated to reflect
 * 					the length of the remainder of the input string that follows the parsed quoted string.
 * @return	-1 on general error or if an enclosing pair of double quotes was not found, or 1 if the supplied quoted string was valid.
 */
int_t imap_parse_qstring(stringer_t **output, chr_t **start, size_t *length) {

	chr_t *writer;
	chr_t *holder;
	size_t left;
	int_t escape = 0;
	stringer_t *result;

	// Get setup.
	holder = *start;
	left = *length;
	*output = NULL;

	// Skip the opening quote.
	if (*holder != '"' || !left) {
		return -1;
	}
	else {
		holder++;
		left--;
	}

	// Advance until we have a break character. Technically holder should be less than 127, but because were using a signed char, greater values are below NULL.
	while (left && *holder > '\0' && *holder != '\r' && *holder != '\n' && (escape == 1 || *holder != '"')) {

		if (escape == 0 && *holder == '\\') {
			escape = 1;
		}
		else if (escape != 0) {
			escape = 0;
		}

		holder++;
		left--;
	}

	// Check for valid data.
	if (*holder != '"') {
		return -1;
	}
	// Check for empty quoted strings. We return 1, but we also return a NULL pointer.
	if ((*start) + 1 == holder) {

		// Advance to the next argument.
		if (left) {
			holder++;
			left--;
		}

		// There should be a space before the next argument.
		if (left && *holder == ' ') {
			holder++;
			left--;
		}

		// Update
		*start = holder;
		*length = left;
		return 1;
	}

	// Allocate a buffer for the output.
	if (!(result = st_alloc(holder - *start))) {
		log_pedantic("Unable to allocate a buffer for the quoted string.");
		return -1;
	}

	// Get setup for the copy.
	writer = st_char_get(result);
	holder = *start;
	left = *length;

	// Skip the open quote again.
	holder++;
	left--;

	// Advance until we have a break character. Technically holder should be less than 127, but because were using a signed char, greater values are below NULL.
	while (left && *holder > '\0' && *holder != '\r' && *holder != '\n' && (escape == 1 || *holder != '"')) {

		if (escape == 0 && *holder == '\\') {
			escape = 1;
		}
		else if (escape != 0) {
			escape = 0;
		}

		// Copy unless we have the escape character.
		if (!escape) {
			*writer = *holder;
			writer++;
		}

		holder++;
		left--;
	}

	st_length_set(result, writer - (chr_t *)st_char_get(result));

	// Advance to the next argument.
	if (left) {
		holder++;
		left--;
	}

	// There should be a space before the next argument.
	if (left && *holder == ' ') {
		holder++;
		left--;
	}

	// Update
	*start = holder;
	*length = left;
	*output = result;

	return 1;
}
예제 #21
0
파일: qp.c 프로젝트: lavabit/magma
/**
 * @brief	Perform QP (quoted-printable) decoding of a string.
 * @param	s	the managed string containing data to be decoded.
 * @return	a pointer to a managed string containing the 8-bit decoded output, or NULL on failure.
 */
stringer_t * qp_decode(stringer_t *s) {

	uchr_t *p, *o;
	stringer_t *output;
	size_t len, written = 0;

	if (st_empty_out(s, &p, &len)) {
		log_pedantic("An empty string was passed in for decoding.");
		return NULL;
	}

	// Allocate one byte for printable characters and three bytes for non-printable characters.
	if (!(output = st_alloc(len))) {
		log_pedantic("Could not allocate a buffer large enough to hold decoded result. {requested = %zu}", len);
		return NULL;
	}

	// Get setup.
	o = st_data_get(output);

#ifdef MAGMA_PEDANTIC
	// In pedantic mode we perform an extra check to make sure the loop doesn't loop past zero.
	while (len && len <= st_length_get(s)) {
#else
	while (len) {
#endif

		// Advance past the trigger.
		if (*p == '=') {

			len--;
			p++;

			// Valid hex pair.
			if (len >= 2 && hex_valid_chr(*p) && hex_valid_chr(*(p + 1))) {
				*o++ = hex_decode_chr(*p, *(p + 1));
				written++;
				len -= 2;
				p += 2;
			}
			// Soft line breaks are signaled by a line break following an equal sign.
			else if (len >= 2 && *p == '\r' && *(p + 1) == '\n') {
				len -= 2;
				p += 2;
			}
			else if (len >= 1 && *p == '\n') {
				len--;
				p++;
			}
			// Equal signs which aren't followed by a valid hex pair or a line break are illegal, but if the character is printable
			// we can let through the original sequence.
			else if (len >= 1 && ((*p >= '!' && *p <= '<') || (*p >= '>' && *p <= '~'))) {
				*o++ = '=';
				*o++ = *p++;
				written += 2;
				len--;
			}
			// Characters outside the printable range are simply skipped.
			else if (len >= 1) {
				len--;
				p++;
			}
		}
		// Let through any characters found inside this range.
		else if ((*p >= '!' && *p <= '<') || (*p >= '>' && *p <= '~')) {
			*o++ = *p++;
			written++;
			len--;
		}
		// Characters outside the range above should have been encoded. Any that weren't should be skipped.
		else {
			len--;
			p++;
		}

	}

	// We allocated a default string buffer, which means the length is tracked so we need to set the data length.
	st_length_set(output, written);
	return output;
}
예제 #22
0
/**
 * @brief	Extract the contents of a literal string and advance the position of the parser stream.
 * @note	This function expects as input a string beginning with '{' and followed by a numerical string, an optional '+', and a closing '}'.
 	 	 	After reading in the numerical size parameter, it then attempts to read in that many bytes of input from the network stream.
 * @param	con		the client IMAP connection passing the literal string as input to the server.
 * @param	output	the address of a managed string that will receive a copy of the literal string's contents on success, or NULL on failure or if it is zero length.
 * @param	start	the address of a pointer to the start of the buffer to be parsed (beginning with '{'), that will also be updated to
 * 					point to the next argument in the sequence on success.
 * @param	length	a pointer to a size_t variable that contains the length of the string to be parsed, and that will be updated to reflect
 * 					the length of the remainder of the input string that follows the parsed literal string.
 * @return	-1 on general or parse error or if an enclosing pair of double quotes was not found, or 1 if the supplied quoted string was valid.
 */
int_t imap_parse_literal(connection_t *con, stringer_t **output, chr_t **start, size_t *length) {

	chr_t *holder;
	int_t plus = 0;
	stringer_t *result;
	size_t characters, left;
	ssize_t nread;
	uint64_t literal, number;

	// Get setup.
	holder = *start;
	left = *length;
	*output = NULL;

	// Skip the opening bracket.
	if (*holder != '{' || !left) {
		return -1;
	}
	else {
		holder++;
		left--;
	}

	// Advance until we have a break character.
	while (left && *holder >= '0' && *holder <= '9') {
		holder++;
		left--;
	}

	// Store the length.
	characters = holder - *start - 1;

	if (left && *holder == '+') {
		plus = 1;
		holder++;
		left--;
	}

	if (*holder != '}' || !characters) {
		return -1;
	}

	// Convert to a number. Make sure the number is positive.
	if (!uint64_conv_bl(*start + 1, characters, &number)) {
		return -1;
	}

	literal = (size_t)number;

	// If the number is larger than 128 megabytes, then reject it.
	if (!plus && number > 134217728) {
		return -1;
	}
	// They client is already transmitting, so read the entire file, then reject it.
	else if (number > 134217728) {

		while (number > 0) {

			// Read the data.
			if ((nread = con_read(con)) <= 0) {
				log_pedantic("The connection was dropped while reading the literal.");
				return -1;
			}

			// Deal with signedness problem.
			characters = nread;

			if (number > (uint64_t)characters) {
				number -= characters;
			}
			else {

				// If we have any extra characters in the buffer, move them to the beginning.
				if ((uint64_t)characters > number) {
					mm_move(st_char_get(con->network.buffer), st_char_get(con->network.buffer) + number, characters - number);
					st_length_set(con->network.buffer, characters - number);
					con->network.line = line_pl_st(con->network.buffer, 0);
				}
				else {
					st_length_set(con->network.buffer, 0);
					con->network.line = pl_null();
				}

				// Make sure we have a full line.
				if (pl_empty(con->network.line) && con_read_line(con, true) <= 0) {
					log_pedantic("The connection was dropped while reading the literal.");
					return -1;
				}

				number = 0;
			}

		}

		return -1;
	}

	// If this is not a plus literal, output the proceed statement.
	if (!plus) {
		con_write_bl(con, "+ GO\r\n", 6);
	}

	// Handle the special case of a zero length literal.
	if (literal == 0) {

		// Read the next line.
		if (con_read_line(con, true) <= 0) {
			log_pedantic("The connection was dropped while reading the literal.");
			return -1;
		}

		*start = st_char_get(con->network.buffer);
		*length = pl_length_get(con->network.line);

		// There should be a space before the next argument.
		if (*length && **start == ' ') {
			(*start)++;
			(*length)--;
		}

		return 1;
	}

	// Allocate a stringer for the buffer.
	if (!(result = st_alloc(literal))) {
		log_pedantic("Unable to allocate a buffer of %lu bytes for the literal argument.", literal);
		return -1;
	}

	// So we know how many more characters to read.
	left = literal;

	// Where we put the data.
	holder = st_char_get(result);

	// Keep looping until we run out of data.
	while (left) {

		// Read the data.
		if ((nread = con_read(con)) <= 0) {
			log_pedantic("The connection was dropped while reading the literal.");
			st_free(result);
			return -1;
		}

		characters = nread;

		// If we have a buffer, copy the data into the buffer.
		mm_copy(holder, st_char_get(con->network.buffer), (left > characters) ? characters : left);

		if (left > characters) {
			holder += characters;
			left -= characters;
		}
		else {
		 	st_length_set(result, literal);

			// If we have any extra characters in the buffer, move them to the beginning.
			if (characters > left) {
				mm_move(st_char_get(con->network.buffer), st_char_get(con->network.buffer) + left, characters - left);
				st_length_set(con->network.buffer, characters - left);
				con->network.line = line_pl_st(con->network.buffer, 0);
			}
			else {
					st_length_set(con->network.buffer, 0);
					con->network.line = pl_null();
			}

			// Make sure we have a full line.
			if (pl_empty(con->network.line) && con_read_line(con, true) <= 0) {
				log_pedantic("The connection was dropped while reading the literal.");
				st_free(result);
				return -1;
			}
			left = 0;
		}
	}

	*start = st_char_get(con->network.buffer);
	*length = pl_length_get(con->network.line);

	// There should be a space before the next argument.
	if (*length && **start == ' ') {
		(*start)++;
		(*length)--;
	}

	if (result != NULL) {
		*output = result;
	}
	else {
		return -1;
	}

	return 1;
}
예제 #23
0
파일: replace.c 프로젝트: lavabit/magma
 // LOW: Function could use some serious cleanup; NEED TO TEST THIS IN UNIT TESTS
int_t st_replace(stringer_t **target, stringer_t *pattern, stringer_t *replacement) {

	stringer_t *output;
	uchr_t *tptr, *optr, *rptr, *pptr;
	size_t hits = 0, tlen, plen, rlen, olen;

	// replacement can be blank but it can't be null
	if (!target || st_empty_out(*target, &tptr, &tlen) || st_empty_out(pattern, &pptr, &plen) ||
			(st_empty_out(replacement, &rptr, &rlen) && !st_char_get(replacement))) {
		log_pedantic("Sanity check failed. Passed a NULL pointer.");
		return -1;
	}

	// Check to make sure the target is big enough to hold the pattern.
	if (tlen < plen) {
//		log_pedantic("The target isn't long enough to contain the pattern.");
		return 0;
	}

	// Increment through the entire target and find out how many times the pattern is present.
	for (size_t i = 0; i <= (tlen - plen); i++) {
		if (!st_cmp_cs_starts(PLACER(tptr++, tlen - i), pattern)) {
			hits++;
			i += plen - 1;
			tptr += plen - 1;
		}
	}

	//  Did we get any hits? Or if the output length would be zero, return.
	// QUESTION: Should 2nd part of conditional ever be necessary? tlen - (plen * hits) can't be less than zero,
	//           and hits has to be positive. So the expression will always evaluate positive.
	// QUESTION: Shouldn't we allow the output length to be zero?
	/*if (!hits || !(olen = tlen - (plen * hits) + (rlen * hits))) {
		return hits;
	}*/

	if (!hits) {
		return 0;
	}

	olen = tlen - (plen * hits) + (rlen * hits);

	// If our new string is now empty we truncate the original target and return it.
	if (!olen) {
		*((char *)(st_data_get(*target))) = 0;
		st_length_set(*target, 0);
		return hits;
	}

	// Allocate a new stringer.
	if (!(output = st_alloc(olen))) {
		log_pedantic("Could not allocate %zu bytes for the new string.", olen);
		// QUESTION: -3?
		return -3;
	}

	// Setup.
	tptr = st_data_get(*target);
	optr = st_data_get(output);

	// Increment through the entire target and copy the bytes.
	for (size_t i = 0; i <= tlen; i++) {
		if (i <= (tlen - plen) && !st_cmp_cs_starts(PLACER(tptr, tlen - i), pattern)) {
			i += plen - 1;
			tptr += plen;
			for (size_t j = 0; j < rlen; j++) {
				*optr++ = *(rptr + j);
			}
		}
		else {
			*optr++ = *tptr++;
		}
	}

	if (st_valid_free(*((uint32_t *)(*target)))) {
		st_free(*target);
	}

	st_length_set(output, olen);
	*target = output;
	return hits;
}
예제 #24
0
rt_public void evpush(va_alist)
#endif
{
    /* Push on the local variable stack the number of values indicated
     * by the first (int) argument. If all the values cannot successively
     * be pushed, we attempt to use the secure arena which should have been
     * pre-allocated for that purpose (we can't really call the GC before all
     * the locals have been pushed).
     */

    EIF_GET_CONTEXT
    int n;				/* Number of elements to be pushed */
    char **top;			/* The current top of the stack */
#ifdef EIF_WINDOWS
    va_list ap;			/* The variable argument list */
#else
    va_list ap;			/* The variable argument list */
#endif
    int i;				/* Number of slots until end of chunk */
    struct stack *stk;	/* The local stack pointer */

#ifndef I_STDARG
    va_start(ap);
    n = va_arg(ap, int);
#else
    va_start (ap, count);
    n = count;		/* First argument is the number of items */
#endif

    /* This function is going to be called many many times, so it has to be
     * as mostly efficient as possible. Hence, the call to epush() which should
     * take place has been inlined. This also enables us to take advantage of
     * the secure arena at low costs--RAM.
     */

    stk = &loc_stack;		/* Load pointer in register for faster access */
    top = stk->st_top;		/* Current top of stack */

    /* Create a new stack if none has been already allocated. If allocation
     * fails, we don't bother trying with the urgent memory stock: we must be
     * at the beginning of the process's lifetime and we are already out of
     * memory--RAM.
     */

    if (top == (char **) 0) {				/* No stack yet? */
        top = st_alloc(stk, eif_stack_chunk);	/* Create one */
        if (top == (char **) 0)				/* Cannot allocate stack */
            enomem(MTC_NOARG);						/* Critical exception */
    }

    /* Attempt an optimization: if there is enough room until the end of the
     * current stack chunk, then we're able to do our job very efficiently.
     */

    i = stk->st_end - top;					/* # of slots until the end */
    if (i >= n) {							/* Enough room to do it once?*/
        while (n--)							/* Yes! Do it the fast way */
            *top++ = va_arg(ap, char *);	/* Push local address on stack */
        stk->st_top = top;					/* Update stack's top */
        va_end(ap);					/* End processing of argument list */
        return;						/* All done */
    }

    /* We have to do it manually. Stack extension is done as needed. If it is
     * not possible to push a value on the stack, a critical "Out of memory"
     * exception is raised. We also need to protect against signals.
     */

    SIGBLOCK;		/* Entering critical section */

    while (n > 0) {
        while (i-- > 0 && n-- > 0)			/* Note the double & */
            *top++ = va_arg(ap, char *);	/* Push local address on stack */
        if (n > 0) {						/* Reached end of chunk */
            if (stk->st_cur == stk->st_tl) {	/* Last chunk */
                if (-1 == extend(&loc_stack)) {	/* Cannot extend stack at all */
                    va_end(ap);					/* End processing of list */
                    enomem(MTC_NOARG);					/* Critical exception */
                }
                top = stk->st_top;				/* Update new top */
            } else {							/* Go to next chunk */
                struct stchunk *c;	/* New current chunk */
                c = stk->st_cur = stk->st_cur->sk_next;
                top = stk->st_top = c->sk_arena;
                stk->st_end = c->sk_end;
            }
            i = stk->st_end - top;				/* # of slots until the end */
        }
    }

    stk->st_top = top;		/* Ensure top is up-to-date */
    va_end(ap);				/* End processing of argument list */

    SIGRESUME;				/* Leaving critical section */
}
예제 #25
0
/**
 * @brief	Build a spam text signature for insertion into a message body.
 * @param	server				the server object of the web server where the teacher application is hosted.
 * @param	type				MESSAGE_TYPE_HTML to generate an html-based signature, or any other value for plain text.
 * @param	content_encoding	if MESSAGE_ENCODING_QUOTED_PRINTABLE, set the encoding type to qp.
 * @param	signum				the spam signature number referenced by the teacher url.
 * @param	sigkey				the spam signature key for client verification in the teacher app.
 * @param	disposition			if 0, the message disposition is "innocent"; otherwise, the disposition specifies "spam".
 * @return	NULL on failure, or a newly allocated managed string containing the desired mail signature on success.
 */
stringer_t * mail_build_signature(server_t *server, int_t content_type, int_t content_encoding, uint64_t signum, uint64_t sigkey, int_t disposition) {

	size_t length;
	stringer_t *holder;
	stringer_t *result = NULL;
	stringer_t *spam_text = NULL;
	static const chr_t *line = "\r\n____________________________________________________________________________________\r\n";

	// Build the spam signature.
	if (signum && sigkey) {
		// This is the format for spam signatures.
		if (content_type == MESSAGE_TYPE_HTML) {
			holder = st_merge("nnnnnsnsn", "\r\n<div style='display: block; text-transform: none; text-indent: 0px; letter-spacing: normal; "
					"line-height: normal; text-align: left; white-space: normal; height: auto; visibility: visible; border-bottom: 1px solid black; border-collapse: collapse; "
					"width: 50em; font-size: 12px; color: black; font-family: sans-serif; padding: 0px 0px 4px 0px; clear: both; font-weight: normal;"
					"text-decoration: none; background: white; ", "margin: 20px 2px 10px 2px; border-top: 1px solid black;",
					"'>\r\n\tUse the link below to report this message as ", !disposition ? "spam" : "innocent",
					".<br />\r\n\t<a style='font-size: 12px; font-family: sans-serif; color: blue; background: white; text-decoration: underline; font-weight: normal;' href='https://",
					server->domain, "/apps/teacher?sig=%lu&amp;key=%lu'>https://", server->domain, "/apps/teacher?sig=%lu&amp;key=%lu</a>\r\n</div>\r\n");
		}
		else {
			holder = st_merge("nnsn", "Use the link below to report this message as ", !disposition ? "spam.\r\nhttps://" : "innocent.\r\nhttps://",
				server->domain, "/apps/teacher?sig=%lu&amp;key=%lu");
		}

		if (!holder) {
			log_pedantic("Unable to build the spam signature.");
			return NULL;
		}

		// How big is the signature with the numbers inserted.
		length = st_length_get(holder) + uint64_digits(signum) + uint64_digits(sigkey) + uint64_digits(signum) + uint64_digits(sigkey);

		if (!(spam_text = st_alloc(length))) {
			log_pedantic("Unable to build the spam signature.");
			st_free(holder);
			return NULL;
		}

		// Print the spam signature text.
		if (content_type == MESSAGE_TYPE_HTML) {
			length = st_sprint(spam_text, st_char_get(holder), signum, sigkey, signum, sigkey);
		}
		else {
			length = st_sprint(spam_text, st_char_get(holder), signum, sigkey);
		}

		st_free(holder);

		if (!length) {
			log_pedantic("Unable to build the spam signature.");
			st_free(spam_text);
			return NULL;
		}

	}

	// Error check.
	if (!spam_text) {
		log_pedantic("Could not build the signature.");
		return NULL;
	}

	// Build the output signature.
	if (content_type == MESSAGE_TYPE_HTML) {
		result = spam_text;
		spam_text = NULL;
	}
	else {
		result = st_merge("nnsn", line, (spam_text == NULL) ? "" : line, spam_text, line);
	}

	if (!result) {
		log_pedantic("An error occurred while attempting to merge the signature.");
	}

	// Cleanup.
	st_cleanup(spam_text);

	// Check for quoted printable encodings.
	if (content_encoding == MESSAGE_ENCODING_QUOTED_PRINTABLE) {
		holder = qp_encode(result);

		if (holder && result) {
			st_free(result);
			result = holder;
		}

	}

	return result;
}
예제 #26
0
/**
 * @brief	Extract an html tag from a data buffer, searching backwards.
 * @warning	Remember that this function takes the end and not the start of a buffer!
 * @note	The extracted tag contains the enclosing brackets and only printable characters (no whitespace).
 * @param	stream	the end of a data buffer containing the html data to be parsed.
 * @param	length	the size, in bytes, of the data buffer to be parsed.
 * @return	NULL on failure, or a managed string containing the printable contents of the nearest html tag on success.
 */
stringer_t * mail_extract_tag(chr_t *stream, size_t length) {

	chr_t *holder;
	size_t amount = 0;
	stringer_t *tag;

	if (*stream != '>') {
		return NULL;
	}

	// How long is this tag.
	while (length && *stream != '<') {
		length--;
		stream--;
		amount++;
	}

	// Did we hit the end of the stream or did we hit the beginning of the tag.
	if (!length) {
		return NULL;
	}
	else {
		amount++;
	}

	// Allocate a buffer.
	if (!(tag = st_alloc(amount))) {
		log_pedantic("Unable to allocate a stringer of %zu bytes to hold the HTML tag.", amount);
		return NULL;
	}

	// Get setup.
	length = 0;
	holder = st_char_get(tag);

	// QUESTION: Without folding whitespace?? Without any whitespace!
	// This returns the tag without folding whitespace.
	while (amount) {

		if (*stream <= '~' && *stream >= '!') {
			*holder = *stream;
			stream++;
			holder++;
			length++;
		}
		else {
			stream++;
		}

		amount--;
	}

	// This should never happen.
	if (!length) {
		st_free(tag);
		return NULL;
	}

	st_length_set(tag, length);

	return tag;
}
예제 #27
0
/**
 * @brief	Encode data in a human readable way, for debugging purposes.
 * @note	All printable ASCII data will be displayed as-is; all other characters will be shown as formatted hex pairs.
 * @param	input	a pointer to a managed string containing the data to be formatted.
 * @param	maxlen	the maximum number of bytes to be displayed. If more characters are available, an ellipsis will be shown in the middle of the string
 *                      to represent the abridged data, with only the leading and trailing characters returned as part of the display string.
 * @return	NULL on failure, or a pointer to a newly allocated managed string containing the encoded debug data on success.
 */
stringer_t *hex_encode_st_debug(stringer_t *input, size_t maxlen) {

	stringer_t *result;
	uchr_t *iptr;
	chr_t *rptr, *rstart;
	size_t total, pass_len;

	// Not the most efficient, but this is mostly for internal debugging purposes anyhow
	total = (maxlen * 4) + 16;

	if (!(result = st_alloc(total))) {
		log_error("Unable to allocate space for debug string.");
		return NULL;
	}

	rstart = rptr = st_char_get(result);
	iptr = st_uchar_get(input);
	*rptr++ = '[';

	if (maxlen >= st_length_get(input)) {
		pass_len = st_length_get(input);
	} else {
		pass_len = maxlen / 2;
	}

	// First pass happens regardless.
	for (size_t i = 0; i < pass_len; i++) {

		if (chr_printable(*iptr) || (*iptr == '\r') || (*iptr == '\n') || (*iptr == '\t')) {
			*rptr++ = (chr_t)*iptr++;
		} else {
			*rptr++ = '\\';
			*rptr++ = 'x';
			hex_encode_chr(*iptr++, (uchr_t *)rptr);
			rptr += 2;
		}

	}

	// Second pass only if there's another round.
	if (pass_len != st_length_get(input)) {
		*rptr++ = ' ';
		*rptr++ = '.';
		*rptr++ = '.';
		*rptr++ = '.';
		*rptr++ = ' ';
		iptr = st_uchar_get(input) + st_length_get(input) - (maxlen / 2);

		for (size_t i = 0; i < pass_len; i++) {

			if (chr_printable(*iptr) || (*iptr == '\r') || (*iptr == '\n') || (*iptr == '\t')) {
				*rptr++ = (chr_t)*iptr++;
			} else {
				*rptr++ = '\\';
				*rptr++ = 'x';
				hex_encode_chr(*iptr++, (uchr_t *)rptr);
				rptr += 2;
			}

		}
	}

	*rptr++ = ']';
	*rptr = 0;

	st_length_set(result, (size_t)(rptr - rstart));
	return result;
}
예제 #28
0
/**
 * @brief	Decode a URL-encoded string into its original representation.
 * @param	s       a managed string containing the UR componentL to be decoded.
 * @return	NULL on failure, or a freshly allocated managed string containing the original data represented by the URL-encoded input on success.
 */
stringer_t *url_decode(stringer_t *s) {

	uchr_t *p, *o;
	stringer_t *output;
	size_t len, written = 0;

	if (st_empty_out(s, &p, &len)) {
		log_pedantic("An empty string was passed in for decoding.");
		return NULL;
	}

	// Allocate one byte for printable characters and three bytes for non-printable characters.
	if (!(output = st_alloc(len))) {
		log_pedantic("Could not allocate a buffer large enough to hold decoded result. {requested = %zu}", len);
		return NULL;
	}

	// Get setup.
	o = st_data_get(output);


#ifdef MAGMA_PEDANTIC
	// In pedantic mode we perform an extra check to make sure the loop doesn't loop past zero.
	while (len && len <= st_length_get(s)) {
#else
	while (len) {
#endif

		// Advance past the trigger.
		if (*p == '%') {

			len--;
			p++;

			// Valid hex pair.
			if (len >= 2 && hex_valid_chr(*p) && hex_valid_chr(*(p + 1))) {
				*o++ = hex_decode_chr(*p, *(p + 1));
				written++;
				len -= 2;
				p += 2;
			}
			// Percent signs that aren't followed by a valid hex pair are invalid, but in the interest of compatibility we'll simply let
			// those characters through.
			else if (len >= 1) {
				*o++ = '%';
				*o++ = *p++;
				written += 2;
				len--;
			}
		}
		// Characters not prefixed by a percent sign are simply copied into the output buffer.
		else {
			*o++ = *p++;
			written++;
			len--;
		}

	}

	// We allocated a default string buffer, which means the length is tracked so we need to set the data length.
	st_length_set(output, written);
	return output;
}
예제 #29
0
파일: legacy.c 프로젝트: lavabit/magma
/**
 * @brief	Calculates the legacy symmetric encryption key and authentication token.
 * @param	username	a managed string holding the sanitzed username.
 * @param	password	a managed string holding the plain text user password.
 * @return	an auth_legacy_t structure is returned upon success, and NULL upon failure.
 **/
auth_legacy_t * auth_legacy(stringer_t *username, stringer_t *password) {

	auth_legacy_t *legacy = NULL;
	stringer_t *input = NULL, *intermediate = MANAGEDBUF(64);

	// Make sure all three required inputs are valid pointers and hold at least one character.
	if (st_empty(username) || st_empty(password) || st_empty(magma.secure.salt)) {
		log_error("A variable needed to calculate the legacy authentication and encryption values was invalid.");
		return NULL;
	}
	else if (!(legacy = auth_legacy_alloc())) {
		log_error("We were unable to allocate a buffer to hold the legacy hash values.");
		return NULL;
	}

	// Combine the three inputs into a single buffer.
	else if (!(input = st_merge("sss", username, magma.secure.salt, password))) {
		log_error("Unable to combine the three input values needed to calculate the legacy authentication and encryption values.");
		auth_legacy_free(legacy);
		return NULL;
	}

	// Hash the inputs together and we'll get the legacy symmetric encryption key.
	else if (!(legacy->key = st_alloc_opts(MANAGED_T | CONTIGUOUS | SECURE, 64)) || !(hash_sha512(input, legacy->key))) {
		log_error("Unable to calculate the legacy hash values.");
		auth_legacy_free(legacy);
		st_free(input);
		return NULL;
	}

	// Free and reuse the holder variable.
	st_free(input);

	// Prepare the inputs for the intermediary hash.
	if (!(input = st_merge("ss", password, legacy->key))) {
		log_error("Failed to merge the legacy authentication inputs for the intermediate hash round.");
		auth_legacy_free(legacy);
		return NULL;
	}

	// Hash the password with the output of the first round. Note that if the hash function returns NULL and overwrites
	// the intermediate string pointer, the buffer will be freed automatically because it was allocated off the stack.
	else if (!(hash_sha512(input, intermediate))) {
		log_error("Unable to calculate the legacy hash values.");
		auth_legacy_free(legacy);
		st_free(input);
		return NULL;
	}

	// Free and reuse the holder variable.
	st_free(input);

	// Prepare the inputs for the intermediary hash.
	if (!(input = st_merge("ss", password, intermediate))) {
		log_error("Failed to merge the legacy authentication inputs for the final hash round.");
		auth_legacy_free(legacy);
		return NULL;
	}

	// Hash the inputs together and we'll get the legacy authentication token.
	if (!(legacy->token = st_alloc(64)) || !(hash_sha512(input, legacy->token))) {
		log_error("Failed to merge the legacy authentication inputs for the final hash round.");
		auth_legacy_free(legacy);
		st_free(input);
		return NULL;
	}

	// Free the inputs.
	st_free(input);

	// And return success.
	return legacy;
}
예제 #30
0
파일: hash.c 프로젝트: lavabit/magma
stringer_t * hash_digest(digest_t *digest, stringer_t *s, stringer_t *output) {

	int_t olen;
	uint_t rlen;
	uint32_t opts = 0;
	EVP_MD_CTX ctx;
	stringer_t *result = NULL;

	// Ensure a digest pointer was passed in and that we can retrieve the output length.
	if (!digest || (olen = EVP_MD_size_d((const EVP_MD *)digest)) <= 0) {
		log_pedantic("The hash algorithm is missing or invalid.");
		return NULL;
	}
	else if (output && !st_valid_destination((opts = *((uint32_t *)output)))) {
		log_pedantic("An output string was supplied but it does not represent a buffer capable of holding a result.");
		return NULL;
	}
	else if (st_empty(s)) {
		log_pedantic("The input string does not appear to have any data ready for encoding. {%slen = %zu}", s ? "" : "s = NULL / ",	s ? st_length_get(s) : 0);
		return NULL;
	}

	// Make sure the output buffer is large enough or if output was passed in as NULL we'll attempt the allocation of our own buffer.
	else if ((result = output) && ((st_valid_avail(opts) && st_avail_get(output) < olen) || (!st_valid_avail(opts) && st_length_get(output) < olen))) {
		log_pedantic("The output buffer supplied is not large enough to hold the result. {avail = %zu / required = %i}",
				st_valid_avail(opts) ? st_avail_get(output) : st_length_get(output), olen);
		return NULL;
	}
	else if (!output && !(result = st_alloc(olen))) {
		log_pedantic("The output buffer memory allocation request failed. {requested = %i}", olen);
		return NULL;
	}

	// Initialize the context.
	EVP_MD_CTX_init_d(&ctx);
	rlen = olen;

	// Setup the digest algorithm.
	if (EVP_DigestInit_ex_d(&ctx, (const EVP_MD *)digest, NULL) != 1) {
		log_pedantic("An error occurred while trying to initialize the hash context. {%s}",	ssl_error_string(MEMORYBUF(256), 256));
		EVP_MD_CTX_cleanup_d(&ctx);
		if (!output) {
			st_free(result);
		}
		return NULL;
	}

	// Process the input data.
	else if (EVP_DigestUpdate_d(&ctx, st_data_get(s), st_length_get(s)) != 1) {
		log_pedantic("An error occurred while trying to process the input data. {%s}", ssl_error_string(MEMORYBUF(256), 256));
		EVP_MD_CTX_cleanup_d(&ctx);
		if (!output) {
			st_free(result);
		}
		return NULL;
	}

	// Retrieve the hash output.
	else if (EVP_DigestFinal_d(&ctx, st_data_get(result), &rlen) != 1) {
		log_pedantic("An error occurred while trying to retrieve the hash result. {%s}", ssl_error_string(MEMORYBUF(256), 256));
		EVP_MD_CTX_cleanup_d(&ctx);
		if (!output) {
			st_free(result);
		}
		return NULL;
	}

	// Cleanup.
	EVP_MD_CTX_cleanup_d(&ctx);

	if (!output || st_valid_tracked(opts)) {
		st_length_set(result, rlen);
	}
	return result;
}