#include #include #include #include #define SUCCESS 0 #define FAILURE 1 #define FALSE 0 #define TRUE 1 typedef struct get_data_node { char *variable; char *value; struct get_data_node *next; } get_data_node; char * html_escape_string (char *); get_data_node * retrieve_get_data (char *); get_data_node * add_get_data_to_list (get_data_node *, char *, char *); char * decode_url_string (char *); int main (int argc, char *argv[]) { get_data_node *get_data_list_head, *temp_get_data_element; char *safe_html_string; get_data_list_head = NULL; if (getenv("QUERY_STRING") != NULL) { get_data_list_head = retrieve_get_data (getenv("QUERY_STRING")); } printf ("Content-type: text/html\n\n"); temp_get_data_element = get_data_list_head; if (temp_get_data_element != NULL) { printf ("\n"); printf ("\n"); printf (" \n"); printf (" GET form data results\n"); printf (" \n"); printf (" \n"); printf ("

The following form data was received in a GET request:

\n"); printf (" \n"); printf (" \n"); printf (" \n"); printf (" \n"); printf (" \n"); while (temp_get_data_element != NULL) { if ((temp_get_data_element->variable != NULL) && (temp_get_data_element->value != NULL)) { printf (" \n"); safe_html_string = html_escape_string (temp_get_data_element->variable); if (safe_html_string != NULL) { printf (" \n", safe_html_string); free (safe_html_string); } else { printf (" \n"); } safe_html_string = html_escape_string (temp_get_data_element->value); if (safe_html_string != NULL) { printf (" \n", safe_html_string); free (safe_html_string); } else { printf (" \n"); } printf (" \n"); } temp_get_data_element = temp_get_data_element->next; } } else { printf ("\n"); printf ("\n"); printf (" \n"); printf (" New user registration\n"); printf (" \n"); printf (" \n"); printf (" \n"); printf ("

Username:

\n"); printf ("

Password:

\n"); printf ("

Confirm password:

\n"); printf ("

\n"); printf (" \n"); printf (" \n"); printf ("\n"); } while (get_data_list_head != NULL) { temp_get_data_element = get_data_list_head; get_data_list_head = get_data_list_head->next; free (temp_get_data_element); } exit (SUCCESS); } char * html_escape_string (char *input_string) { char *web_safe_output_string, *byte, temp_string[10]; uint64_t output_string_length; web_safe_output_string = NULL; if (input_string != NULL) { output_string_length = 0; byte = input_string; while (*byte != '\0') { if ((*byte == '"') || (*byte =='\'') || (*byte == '&') || (*byte == '<') || (*byte == '>')) { output_string_length = output_string_length + 5; } else { if ((*byte >= 127) && (*byte <= 255)) { output_string_length = output_string_length + 6; } else { output_string_length++; } } byte++; } if (output_string_length > 0) { web_safe_output_string = malloc(sizeof(char) * (output_string_length + 1)); if (web_safe_output_string != NULL) { *web_safe_output_string = '\0'; byte = input_string; while (*byte != '\0') { if ((*byte == '"') || (*byte =='\'') || (*byte == '&') || (*byte == '<') || (*byte == '>') || ((*byte >= 127) && (*byte <= 255))) { sprintf (temp_string, "&#%d;", *byte); } else { temp_string[0] = *byte; temp_string[1] = '\0'; } strcat (web_safe_output_string, temp_string); byte++; } } } } return web_safe_output_string; } get_data_node * retrieve_get_data (char *raw_get_data) { char *raw_variable, *variable, *raw_value, *value, byte; uint64_t bytes_read, get_data_length, string_length_variable, string_length_value, begin, end, i, j, string_length; get_data_node *get_data_list_head; int state, valid_get_data; get_data_list_head = NULL; get_data_length = strlen(raw_get_data); if (get_data_length > 0) { // // get data comes in as a continuous string of variable=value pairs like this: // session_id=123&command=search&query=this+is+my+search // // The next step is to parse this string for syntax errors. This is to prevent possible attacks from malicious users! valid_get_data = FALSE; state = 0; bytes_read = 0; while (bytes_read < get_data_length) { byte = raw_get_data[bytes_read]; switch (state) { case 0: if (byte != '=') { state = 1; } else { state = 3; } break; case 1: if (byte == '=') { state = 2; } break; case 2: if (byte == '&') { state = 0; } break; case 3: break; } bytes_read++; } if (state == 2) { valid_get_data = TRUE; } // // Ok, now that the get data has been verified to be syntactically correct, parse once more to separate and store the variable/value pairs in // a linked list data structure if (valid_get_data) { state = 0; bytes_read = 0; while (bytes_read < get_data_length) { byte = raw_get_data[bytes_read]; switch (state) { case 0: begin = bytes_read; end = 0; state = 1; break; case 1: if (byte == '=') { end = bytes_read - 1; string_length = end - begin + 1; raw_variable = (char *) malloc (sizeof(char) * (string_length + 1)); if (raw_variable != NULL) { i = 0; j = begin; while (i < string_length) { raw_variable[i] = raw_get_data[j]; i++; j++; } raw_variable[i] = '\0'; variable = decode_url_string (raw_variable); free (raw_variable); raw_variable = NULL; } state = 2; } break; case 2: if (byte != '&') { begin = bytes_read; state = 3; } else { value = NULL; get_data_list_head = add_get_data_to_list (get_data_list_head, variable, value); state = 0; } break; case 3: if (byte == '&') { end = bytes_read - 1; string_length = end - begin + 1; raw_value = (char *) malloc (sizeof(char) * string_length + 1); if (raw_value != NULL) { i = 0; j = begin; while (i < string_length) { raw_value[i] = raw_get_data[j]; i++; j++; } raw_value[i] = '\0'; value = decode_url_string (raw_value); get_data_list_head = add_get_data_to_list (get_data_list_head, variable, value); free (raw_value); raw_value = NULL; state = 0; } } break; } bytes_read++; if ((state == 3) && (bytes_read == get_data_length)) { end = bytes_read - 1; string_length = end - begin + 1; raw_value = (char *) malloc (sizeof(char) * (string_length + 1)); if (raw_value != NULL) { i = 0; j = begin; while (i < string_length) { raw_value[i] = raw_get_data[j]; i++; j++; } raw_value[i] = '\0'; value = decode_url_string (raw_value); get_data_list_head = add_get_data_to_list (get_data_list_head, variable, value); free (raw_value); raw_value = NULL; } } } } } return get_data_list_head; } get_data_node * add_get_data_to_list (get_data_node *get_data_list_head, char *variable, char *value) { get_data_node *new_get_data_element, *temp_get_data_element; new_get_data_element = (get_data_node *) malloc(sizeof(get_data_node)); if (new_get_data_element != NULL) { new_get_data_element->variable = variable; new_get_data_element->value = value; new_get_data_element->next = NULL; } if (get_data_list_head == NULL) { get_data_list_head = new_get_data_element; } else { temp_get_data_element = get_data_list_head; while (temp_get_data_element->next != NULL) { temp_get_data_element = temp_get_data_element->next; } temp_get_data_element->next = new_get_data_element; } return get_data_list_head; } char * decode_url_string (char *url_encoded_string) { char *output_string, *temp_output_string, *byte; uint64_t output_string_length; unsigned int state; output_string = NULL; if (url_encoded_string != NULL) { state = 0; byte = url_encoded_string; output_string_length = 0; while (*byte != '\0') { switch (state) { case 0: if (*byte == '%') { state = 1; } output_string_length++; break; case 1: if (((*byte >= 'a') && (*byte <= 'f')) || ((*byte >= 'A') && (*byte <= 'F')) || ((*byte >= '0') && (*byte <= '9'))) { state = 2; } else { state = 3; } break; case 2: if (((*byte >= 'a') && (*byte <= 'f')) || ((*byte >= 'A') && (*byte <= 'F')) || ((*byte >= '0') && (*byte <= '9'))) { state = 0; } else { state = 3; } break; case 3: break; } byte++; } if ((state == 0) && (output_string_length > 0)) { output_string = (unsigned char *) malloc (sizeof(unsigned char) * (output_string_length + 1)); if (output_string != NULL) { byte = url_encoded_string; temp_output_string = output_string; while (*byte != '\0') { switch (state) { case 0: if (*byte == '+') { *temp_output_string = ' '; temp_output_string++; } else { if (*byte != '%') { *temp_output_string = *byte; temp_output_string++; } else { state = 1; } } break; case 1: if ((*byte >= 'a') && (*byte <= 'f')) { *temp_output_string = *byte - 'a' + 10; state = 2; } else { if ((*byte >= 'A') && (*byte <= 'F')) { *temp_output_string = *byte - 'A' + 10; state = 2; } else { if ((*byte >= '0') && (*byte <= '9')) { *temp_output_string = *byte - '0'; state = 2; } else { state = 3; } } } break; case 2: if ((*byte >= 'a') && (*byte <= 'f')) { *temp_output_string = *temp_output_string * 16 + *byte - 'a' + 10; temp_output_string++; state = 0; } else { if ((*byte >= 'A') && (*byte <= 'F')) { *temp_output_string = *temp_output_string * 16 + *byte - 'A' + 10; temp_output_string++; state = 0; } else { if ((*byte >= '0') && (*byte <= '9')) { *temp_output_string = *temp_output_string * 16 + *byte - '0'; temp_output_string++; state = 0; } else { state = 3; } } } case 3: break; } byte++; } *temp_output_string = '\0'; } } } return output_string; }
VARIABLEVALUE
%s %s