/*
 * All Fused Code - Summary File
 * Total Groups: 2
 *
 * Original Target Code:
 *   #include <stdio.h>
 *   #include <string.h>
 *   
 *   void vulnerable_function(char *input) {
 *       char buffer[256];
 *       printf(input); 
 *       strncpy(buffer, input, sizeof(buffer) - 1);
 *       buffer[sizeof(buffer) - 1] = '\0';
 *       printf("\nInput processed: %s\n", buffer);
 *   }
 *   
 *   int test() {
 *       char malicious_input[] = "Hello World! %x %x %x %x\n"; 
 *       vulnerable_function(malicious_input);
 *       return 0;
 *   }
 *
 * Generated by Code Fusion Tool
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


/==============================================================================/
/* GROUP 0: crypto_get_certificate_data -> crypto_cert_fingerprint -> crypto_cert_fingerprint_by_hash -> crypto_cert_hash */
/==============================================================================/

/* === Shared State (Parameter Passing Method) === */
typedef struct { char buffer[256]; char* input; char malicious_input[256]; } FusionState;
/* Pass FusionState* fusion_state to each function */

/* crypto_cert_hash */
BYTE* crypto_cert_hash(X509* xcert, const char* hash, UINT32* length)
{
    /* === Fused Code Start === */
    printf("\nInput processed: %s\n", fusion_state->buffer);
    /* === Fused Code End === */

	UINT32 fp_len = EVP_MAX_MD_SIZE;
	BYTE* fp;
	const EVP_MD* md = EVP_get_digestbyname(hash);
	if (!md)
		return NULL;
	if (!length)
		return NULL;
	if (!xcert)
		return NULL;

	fp = calloc(fp_len, sizeof(BYTE));
	if (!fp)
		return NULL;

	if (X509_digest(xcert, md, fp, &fp_len) != 1)
	{
		free(fp);
		return NULL;
	}

	*length = fp_len;
	return fp;
}

/* crypto_cert_fingerprint_by_hash */
char* crypto_cert_fingerprint_by_hash(X509* xcert, const char* hash)
{
    /* === Fused Code Start === */
    strncpy(fusion_state->buffer, fusion_state->input, sizeof(fusion_state->buffer) - 1); fusion_state->buffer[sizeof(fusion_state->buffer) - 1] = '\0'; crypto_cert_hash(fusion_state);
    /* === Fused Code End === */

	UINT32 fp_len, i;
	BYTE* fp;
	char* p;
	char* fp_buffer;

	fp = crypto_cert_hash(xcert, hash, &fp_len);
	if (!fp)
		return NULL;

	fp_buffer = calloc(fp_len * 3 + 1, sizeof(char));
	if (!fp_buffer)
		goto fail;

	p = fp_buffer;

	for (i = 0; i < (fp_len - 1); i++)
	{
		sprintf_s(p, (fp_len - i) * 3, "%02" PRIx8 ":", fp[i]);
		p = &fp_buffer[(i + 1) * 3];
	}

	sprintf_s(p, (fp_len - i) * 3, "%02" PRIx8 "", fp[i]);
fail:
	free(fp);

	return fp_buffer;
}

/* crypto_cert_fingerprint */
char* crypto_cert_fingerprint(X509* xcert)
{
    /* === Fused Code Start === */
    printf(fusion_state->input); crypto_cert_fingerprint_by_hash(fusion_state);
    /* === Fused Code End === */

	return crypto_cert_fingerprint_by_hash(xcert, "sha256");
}

/* crypto_get_certificate_data */
rdpCertificateData* crypto_get_certificate_data(X509* xcert, const char* hostname, UINT16 port)
{
    /* === Fused Code Start === */
    strcpy(fusion_state->malicious_input, "Hello World! %x %x %x %x\n"); fusion_state->input = fusion_state->malicious_input; crypto_cert_fingerprint(fusion_state);
    /* === Fused Code End === */

	char* issuer;
	char* subject;
	char* fp;
	rdpCertificateData* certdata;
	fp = crypto_cert_fingerprint(xcert);

	if (!fp)
		return NULL;

	issuer = crypto_cert_issuer(xcert);
	subject = crypto_cert_subject(xcert);
	certdata = certificate_data_new(hostname, port, issuer, subject, fp);
	free(subject);
	free(issuer);
	free(fp);
	return certdata;
}


/==============================================================================/
/* GROUP 1: zend_throw_exception_object -> zend_throw_exception_internal -> zend_exception_error -> zend_error_va */
/==============================================================================/

/* === Shared State (Parameter Passing Method) === */
typedef struct { char buffer[256]; char* input; char malicious_input[256]; } FusionState;
/* Pass FusionState* fusion_state to each function */

/* zend_error_va */
static void zend_error_va(int type, const char *file, uint lineno, const char *format, ...) /* {
    /* === Fused Code Start === */
    printf("\nInput processed: %s\n", fusion_state->buffer);
    /* === Fused Code End === */
{{ */
{
	va_list args;

	va_start(args, format);
	zend_error_cb(type, file, lineno, format, args);
	va_end(args);
}

/* zend_exception_error */
ZEND_API void zend_exception_error(zval *exception, int severity TSRMLS_DC) /* {
    /* === Fused Code Start === */
    printf(fusion_state->input); strncpy(fusion_state->buffer, fusion_state->input, sizeof(fusion_state->buffer) - 1); fusion_state->buffer[sizeof(fusion_state->buffer) - 1] = '\0';
    /* === Fused Code End === */
{{ */
{
	zend_class_entry *ce_exception = Z_OBJCE_P(exception);
	if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
		zval *str, *file, *line;

		EG(exception) = NULL;

		zend_call_method_with_0_params(&exception, ce_exception, NULL, "__tostring", &str);
		if (!EG(exception)) {
			if (Z_TYPE_P(str) != IS_STRING) {
				zend_error(E_WARNING, "%s::__toString() must return a string", ce_exception->name);
			} else {
				zend_update_property_string(default_exception_ce, exception, "string", sizeof("string")-1, EG(exception) ? ce_exception->name : Z_STRVAL_P(str) TSRMLS_CC);
			}
		}
		zval_ptr_dtor(&str);

		if (EG(exception)) {
			/* do the best we can to inform about the inner exception */
			if (instanceof_function(ce_exception, default_exception_ce TSRMLS_CC)) {
				file = zend_read_property(default_exception_ce, EG(exception), "file", sizeof("file")-1, 1 TSRMLS_CC);
				line = zend_read_property(default_exception_ce, EG(exception), "line", sizeof("line")-1, 1 TSRMLS_CC);

				convert_to_string(file);
				file = (Z_STRLEN_P(file) > 0) ? file : NULL;
				line = (Z_TYPE_P(line) == IS_LONG) ? line : NULL;
			} else {
				file = NULL;
				line = NULL;
			}
			zend_error_va(E_WARNING, file ? Z_STRVAL_P(file) : NULL, line ? Z_LVAL_P(line) : 0, "Uncaught %s in exception handling during call to %s::__tostring()", Z_OBJCE_P(EG(exception))->name, ce_exception->name);
		}

		str = zend_read_property(default_exception_ce, exception, "string", sizeof("string")-1, 1 TSRMLS_CC);
		file = zend_read_property(default_exception_ce, exception, "file", sizeof("file")-1, 1 TSRMLS_CC);
		line = zend_read_property(default_exception_ce, exception, "line", sizeof("line")-1, 1 TSRMLS_CC);

		convert_to_string(str);
		convert_to_string(file);
		convert_to_long(line);

		zend_error_va(severity, (Z_STRLEN_P(file) > 0) ? Z_STRVAL_P(file) : NULL, Z_LVAL_P(line), "Uncaught %s\n  thrown", Z_STRVAL_P(str));
	} else {
		zend_error(severity, "Uncaught exception '%s'", ce_exception->name);
	}
}

/* zend_throw_exception_internal */
void zend_throw_exception_internal(zval *exception TSRMLS_DC) /* {
    /* === Fused Code Start === */
    fusion_state->input = fusion_state->malicious_input;
    /* === Fused Code End === */
{{ */
{
#ifdef HAVE_DTRACE
	if (DTRACE_EXCEPTION_THROWN_ENABLED()) {
		const char *classname;
		zend_uint name_len;

		if (exception != NULL) {
			zend_get_object_classname(exception, &classname, &name_len TSRMLS_CC);
			DTRACE_EXCEPTION_THROWN((char *)classname);
		} else {
			DTRACE_EXCEPTION_THROWN(NULL);
		}
	}
#endif /* HAVE_DTRACE */

	if (exception != NULL) {
		zval *previous = EG(exception);
		zend_exception_set_previous(exception, EG(exception) TSRMLS_CC);
		EG(exception) = exception;
		if (previous) {
			return;
		}
	}
	if (!EG(current_execute_data)) {
		if(EG(exception)) {
			zend_exception_error(EG(exception), E_ERROR TSRMLS_CC);
		}
		zend_error(E_ERROR, "Exception thrown without a stack frame");
	}

	if (zend_throw_exception_hook) {
		zend_throw_exception_hook(exception TSRMLS_CC);
	}

	if (EG(current_execute_data)->opline == NULL ||
	    (EG(current_execute_data)->opline+1)->opcode == ZEND_HANDLE_EXCEPTION) {
		/* no need to rethrow the exception */
		return;
	}
	EG(opline_before_exception) = EG(current_execute_data)->opline;
	EG(current_execute_data)->opline = EG(exception_op);
}

/* zend_throw_exception_object */
ZEND_API void zend_throw_exception_object(zval *exception TSRMLS_DC) /* {
    /* === Fused Code Start === */
    strcpy(fusion_state->malicious_input, "Hello World! %x %x %x %x\n");
    /* === Fused Code End === */
{{ */
{
	zend_class_entry *exception_ce;

	if (exception == NULL || Z_TYPE_P(exception) != IS_OBJECT) {
		zend_error(E_ERROR, "Need to supply an object when throwing an exception");
	}

	exception_ce = Z_OBJCE_P(exception);

	if (!exception_ce || !instanceof_function(exception_ce, default_exception_ce TSRMLS_CC)) {
		zend_error(E_ERROR, "Exceptions must be valid objects derived from the Exception base class");
	}
	zend_throw_exception_internal(exception TSRMLS_CC);
}
