char *str_uri_path(char *str_request) { char *str_return = NULL; // if the request is not long enough to have a URI then abort ERROR_CHECK(strlen(str_request) >= 5, "request too short to parse;"); // find uri start character char *ptr_uri; if (strncmp(str_request, "GET ", 4) == 0 ) { ptr_uri = str_request + 4; } else if (strncmp(str_request, "HEAD ", 5) == 0 || strncmp(str_request, "POST ", 5) == 0) { ptr_uri = str_request + 5; } else { ERROR("unknown request type"); } // return just the Request-URI char *ptr_uri_end = strstr(ptr_uri, " "); int int_uri_len = (int)(ptr_uri_end - ptr_uri); DEBUG("int_uri_len: %i", int_uri_len); ERROR_SALLOC(str_return, int_uri_len + 1); memcpy(str_return, ptr_uri, int_uri_len); str_return[int_uri_len] = '\0'; return str_return; error: SFREE(str_return); return NULL; }
char *aes_decrypt(char *str_ciphertext_base64, int *ptr_int_ciphertext_length) { DEFINE_VAR_ALL(str_ciphertext); char *str_return = NULL; //base64 //printf("test1>%d<\n", *ciphertext_len); str_ciphertext = b64decode(str_ciphertext_base64, ptr_int_ciphertext_length); //printf("str_ciphertext: %s\n", str_ciphertext); //initialize set_aes_key_iv(); AES_KEY AESkey; ERROR_SALLOC(str_return, *ptr_int_ciphertext_length + 1); memset(str_return, 0, *ptr_int_ciphertext_length); //printf("test2>%d<\n", *ptr_int_ciphertext_length); //encrypt AES_set_decrypt_key((const unsigned char *) str_global_aes_key, 256, &AESkey); AES_cbc_encrypt((const unsigned char *)str_ciphertext, (unsigned char *)str_return, *ptr_int_ciphertext_length, &AESkey, (unsigned char *)str_global_aes_iv, AES_DECRYPT); //aes_crypt_cbc(&aes, AES_DECRYPT, *ciphertext_len, (unsigned char *)iv, (unsigned char *)str_ciphertext, (unsigned char *)str_return); //printf("test3>%d<\n", *ciphertext_len); SFREE_ALL(); return str_return; error: SFREE_ALL(); SFREE_PWORD(str_return); return NULL; }
char *str_cookie(char *str_request, char *str_cookie_name) { char *str_return = NULL; DEFINE_VAR_ALL(str_full_cookie); DEBUG("str_cookie 1"); ERROR_CAT_CSTR(str_full_cookie, str_cookie_name, "="); DEBUG("str_cookie 2"); // find the cookie char *ptr_cookie = strstr(str_request, "Cookie:"); WARN_CHECK(ptr_cookie != NULL, "no cookie found"); ptr_cookie = strstr(ptr_cookie, str_full_cookie); WARN_CHECK(ptr_cookie != NULL, "no cookie found"); ptr_cookie = ptr_cookie + strlen(str_full_cookie); // advance cursor past "postage=" SFREE(str_full_cookie); DEBUG("str_cookie 3"); // get cookie length char *ptr_cookie_end_return = strstr(ptr_cookie, "\r\n"); char *ptr_cookie_end_semi = strstr(ptr_cookie, ";"); int int_cookie_len; DEBUG("str_cookie 4"); if (ptr_cookie_end_return == NULL && ptr_cookie_end_semi == NULL) { int_cookie_len = strlen(ptr_cookie); } else if (ptr_cookie_end_return != NULL && ptr_cookie_end_semi == NULL) { int_cookie_len = ptr_cookie_end_return - ptr_cookie; } else if (ptr_cookie_end_return == NULL && ptr_cookie_end_semi != NULL) { int_cookie_len = ptr_cookie_end_semi - ptr_cookie; } else { int_cookie_len = (ptr_cookie_end_return < ptr_cookie_end_semi) ? ptr_cookie_end_return - ptr_cookie : ptr_cookie_end_semi - ptr_cookie; } DEBUG("str_cookie 5"); // return just the postage cookie ERROR_SALLOC(str_return, int_cookie_len + 1); memcpy(str_return, ptr_cookie, int_cookie_len); str_return[int_cookie_len] = '\0'; DEBUG("str_cookie 6"); SFREE_PWORD_ALL(); return str_return; error: SFREE_PWORD_ALL(); SFREE_PWORD(str_return); return NULL; }
char *aes_encrypt(char *str_plaintext, int *ptr_int_plaintext_length) { DEFINE_VAR_ALL(str_output); char *str_return = NULL; //initialize set_aes_key_iv(); AES_KEY AESkey; //int int_new_length = *ptr_int_plaintext_length; *ptr_int_plaintext_length = ((*ptr_int_plaintext_length + AES_BLOCK_SIZE) / AES_BLOCK_SIZE) * AES_BLOCK_SIZE; int int_aes_length = *ptr_int_plaintext_length; //*ptr_int_plaintext_length = (*ptr_int_plaintext_length) - ((*ptr_int_plaintext_length) % 16) + 16; ERROR_SALLOC(str_output, int_aes_length + 1); memset(str_output, 0, int_aes_length); AES_set_encrypt_key((const unsigned char *) str_global_aes_key, 256, &AESkey); AES_cbc_encrypt((const unsigned char *)str_plaintext, (unsigned char *)str_output, int_aes_length, &AESkey, (unsigned char *)str_global_aes_iv, AES_ENCRYPT); /* AES_cbc_encrypt((const unsigned char *)str_plaintext, (unsigned char *)str_output, int_new_length, &AESkey, (unsigned char *)str_global_aes_iv, AES_ENCRYPT); */ //int int_original_length = int_new_length; //int_new_length = (int_new_length & 0xFFFFFFF0) + ((int_new_length & 0x0F) ? 16 : 0); //*(str_output + int_new_length) = (int_new_length - int_original_length); //printf("str_output: %s\n", str_output); //encrypt //aes_setkey_enc(&aes, (unsigned char *)key, 256); //aes_crypt_cbc(&aes, AES_ENCRYPT, *plaintext_len, (unsigned char *)iv, (unsigned char *)plaintext, (unsigned char *)str_output); //base64 str_return = b64encode(str_output, ptr_int_plaintext_length); SFREE_ALL(); return str_return; error: SFREE_ALL(); SFREE_PWORD(str_return); return NULL; }
char *request_header(char *str_request, char *str_name) { char *str_return = NULL; DEFINE_VAR_ALL(str_full_name); ERROR_CAT_CSTR(str_full_name, str_name, ": "); // find the cookie char *ptr_header = strstr(str_request, str_full_name); WARN_CHECK(ptr_header != NULL, "no %s found", str_name); ptr_header = ptr_header + strlen(str_full_name); // advance cursor past "referer: " // get cookie length char *ptr_header_end_return = strstr(ptr_header, "\r\n"); int int_header_len; if (ptr_header_end_return == NULL) { ptr_header_end_return = strstr(ptr_header, "\r"); if (ptr_header_end_return == NULL) { ptr_header_end_return = strstr(ptr_header, "\n"); if (ptr_header_end_return == NULL) { int_header_len = strlen(ptr_header); } else { int_header_len = ptr_header_end_return - ptr_header; } } else { int_header_len = ptr_header_end_return - ptr_header; } } else { int_header_len = ptr_header_end_return - ptr_header; } // return just the host ERROR_SALLOC(str_return, int_header_len + 1); memcpy(str_return, ptr_header, int_header_len); str_return[int_header_len] = '\0'; SFREE_ALL(); return str_return; error: SFREE_ALL(); SFREE(str_return); return NULL; }
//take a file list and convert it into json //int_remove_length is the number of characters to remove from each line //useful if your list is like: // /path/to/file1 // /path/to/file2 //and you want it like: // file1 // file2 char *file_list_to_json (char *str_content, int int_remove_length) { char *str_return = NULL; char *str_temp = NULL; char *str_temp_json = NULL; ERROR_NORESPONSE("int_remove_length: %d", int_remove_length); ERROR_CAT_CSTR(str_return, ""); char *ptr_content = str_content + int_remove_length + 1; // + 1 means remove / if (*(ptr_content - 1) == '\n') { //if we are at a newline, //then the first line must be the full length to remove, so skip that line ptr_content = ptr_content + int_remove_length + 1; // + 1 means remove \n } int int_length; int int_done = 1; char *ptr_end_content = str_content + strlen(str_content); while (int_done > 0) { if (ptr_content <= ptr_end_content && strchr(ptr_content, '\n') != 0) { int_length = (strchr(ptr_content, '\n') - ptr_content); if (int_length > 0) { ERROR_SALLOC(str_temp, int_length + 1); memcpy(str_temp, ptr_content, int_length); str_temp[int_length] = 0; str_temp_json = jsonify(str_temp); SFREE(str_temp); if (strlen(str_return) > 0) { ERROR_CAT_APPEND(str_return, ",", str_temp_json); } else { ERROR_CAT_APPEND(str_return, str_temp_json); } ERROR_NORESPONSE(">%s|%s|%s<", str_return, str_temp_json, ptr_content); SFREE(str_temp_json); } ptr_content = strchr(ptr_content, '\n') + int_remove_length + 1 + 1; // + 1 means remove \n // + 1 means remove / } else { int_done = 0; } } return str_return; error: SFREE(str_temp); SFREE(str_temp_json); SFREE(str_return); return NULL; }
// Check path environment variable for a program char *where_is_program(char *str_program_name) { DEFINE_VAR_ALL(str_PATH, str_PATH2); char *str_return = NULL; ERROR_CAT_CSTR(str_PATH, getenv("PATH")); char *ptr_PATH = str_PATH; char *ptr_PATH_end = str_PATH + strlen(str_PATH); int int_next_colon; while (ptr_PATH < ptr_PATH_end) { //DEBUG("%s", ptr_PATH); int_next_colon = strcspn(ptr_PATH, ":"); ERROR_SALLOC(str_PATH2, int_next_colon + 2); memcpy(str_PATH2, ptr_PATH, int_next_colon); str_PATH2[int_next_colon] = '/'; str_PATH2[int_next_colon + 1] = '\0'; //DEBUG("%s", str_ptr_PATH); str_return = canonical(str_PATH2, str_program_name, "read_dir_or_file"); //"read_file"); SFREE(str_PATH2); if (str_return != NULL) { SFREE_ALL(); return str_return; } //DEBUG("%i", int_next_colon); ptr_PATH += int_next_colon + 1; } WARN("Could not find program: %s", str_program_name); //ERROR("Could not find program: %s", str_program_name); error: SFREE_ALL(); SFREE(str_return); return NULL; }
sun_upload *get_sun_upload(char *str_request, int int_request_length) { sun_upload *sun_return = NULL; DEFINE_VAR_ALL(str_boundary, str_full_boundary, str_name, str_file_content); ////GET BOUNDARY //get boundary length char *ptr_boundary = strstr(str_request, "Content-Type: multipart/form-data; boundary=") + 44; ERROR_CHECK(ptr_boundary != NULL, "No Boundary"); int int_boundary_carriage = strchr(ptr_boundary, '\r') - ptr_boundary; int int_boundary_newline = strchr(ptr_boundary, '\n') - ptr_boundary; int int_boundary_length = int_boundary_carriage < int_boundary_newline ? int_boundary_carriage : int_boundary_newline; //copy boundary ERROR_SALLOC(str_boundary, int_boundary_length + 1); memcpy(str_boundary, ptr_boundary, int_boundary_length); str_boundary[int_boundary_length] = '\0'; ERROR_CAT_CSTR(str_full_boundary, "--", str_boundary); DEBUG(">BOUNDARY|%s<", str_boundary); SFREE(str_boundary); ////GET FILE NAME //get file name char *ptr_name = bstrstr(str_request, int_request_length, "Content-Disposition: form-data; name=\"file_name\"", 48); ERROR_CHECK(ptr_name != NULL, "No Content Disposition for File Name, (Maybe there is no file name?)"); ptr_name = ptr_name + 48; char *ptr_name_dos = strstr(ptr_name, "\r\n\r\n"); char *ptr_name_unix = strstr(ptr_name, "\n\n"); char *ptr_name_mac = strstr(ptr_name, "\r\r"); ptr_name = ptr_name_dos > ptr_name_unix ? ptr_name_dos + 4 : ptr_name_dos > ptr_name_mac ? ptr_name_dos + 4 : ptr_name_unix > ptr_name_mac ? ptr_name_unix + 2 : ptr_name_mac + 2; //copy file name int int_name_carriage = strchr(ptr_name, '\r') - ptr_name; int int_name_newline = strchr(ptr_name, '\n') - ptr_name; int int_name_boundary = strstr(ptr_name, str_full_boundary) - ptr_name; int int_name_length = int_name_carriage < int_name_newline ? int_name_carriage : int_name_carriage < int_name_boundary ? int_name_carriage : int_name_boundary < int_name_carriage ? int_name_boundary : int_name_boundary; ERROR_SALLOC(str_name, int_name_length + 1); memcpy(str_name, ptr_name, int_name_length); str_name[int_name_length] = '\0'; DEBUG(">FILE NAME|%s<", str_name); ////GET FILE //get file content DEBUG("str_request: %20.20s", str_request); char *ptr_file_content = bstrstr(str_request, int_request_length, "Content-Disposition: form-data; name=\"file_content\"", 51); ERROR_CHECK(ptr_file_content != NULL, "No Content Disposition for File Content, (Maybe there is no file content?)"); ptr_file_content = ptr_file_content + 51; DEBUG("str_request + int_request_length d: %d", str_request + int_request_length); DEBUG("ptr_file_content: %20.20s", ptr_file_content); char *ptr_file_content_dos = strstr(ptr_file_content, "\r\n\r\n"); char *ptr_file_content_unix = strstr(ptr_file_content, "\n\n"); char *ptr_file_content_mac = strstr(ptr_file_content, "\r\r"); ptr_file_content = ptr_file_content_dos > ptr_file_content_unix ? ptr_file_content_dos + 4 : ptr_file_content_dos > ptr_file_content_mac ? ptr_file_content_dos + 4 : ptr_file_content_unix > ptr_file_content_mac ? ptr_file_content_unix + 2 : ptr_file_content_mac + 2; //copy file content int int_file_content_length = bstrstr(ptr_file_content, (str_request + int_request_length) - ptr_file_content, str_full_boundary, int_boundary_length + 2) - ptr_file_content; ERROR_SALLOC(str_file_content, int_file_content_length + 1); memcpy(str_file_content, ptr_file_content, int_file_content_length); str_file_content[int_file_content_length] = '\0'; DEBUG(">FILE CONTENT|%s<", str_file_content); DEBUG(">FILE CONTENT LENGTH|%i<", int_file_content_length); ////RETURN ERROR_SALLOC(sun_return, sizeof(sun_upload)); SFREE(str_full_boundary); sun_return->str_name = str_name; str_name = NULL; sun_return->str_file_content = str_file_content; str_file_content = NULL; sun_return->int_file_content_length = int_file_content_length; SFREE_ALL(); return sun_return; error: SFREE_ALL(); SFREE(sun_return); return NULL; }
// safe system execute function int s_exec(char *str_user_environment, int args, ...) { NOTICE("EXEC.C"); // to use: umask(002); // if you plan on creating a file or copying a file then set the default perms. // int int_test = sunny_exec("", "/usr/local/pgsql/bin/pg_ctl", "-D", "/opt/3comets/data", "stop"); // int int_test = sunny_exec("", "/bin/echo", "test1"); // printf( "%i: ", int_test ); // 1 = error, -1 = parent // #### secure execute of programs ### pid_t pid; int status; pid_t ret; // set errno to "Success" in case caller functions have errors in them errno = 0; // fork causes the existing program to split into two identical processes. pid = fork(); ERROR_CHECK(pid != -1, "Fork error."); if (pid != 0) { // pid = -1 means wait for all children, while((ret = waitpid(-1, &status, WUNTRACED)) > 0) { DEBUG("ret: %d", ret); if (errno != EINTR) { break; } } /*while ((ret = waitpid(pid, &status, 0)) == -1) { DEBUG("ret: %d", ret); if (errno != EINTR) { break; } }*/ // keep this code in case you have problems if (ret != -1 && errno != 0 && (!WIFEXITED(status) || !WEXITSTATUS(status)) && errno != 10) { ERROR("Child has unexpected status. errno: %d (%s)", errno, strerror(errno)); } INFO("EXEC.C END"); DEBUG("TEST1>%d|%d<", status, WEXITSTATUS(status)); return WEXITSTATUS(status); error: DEBUG("TEST2"); return -1; } else { DEBUG("global_csock: %i", global_csock); if (global_csock > -1) { DEBUG("close(global_csock): %i", global_csock); close(global_csock); } // the first item is our program executable // assemble a nice array of all our args with a null element at the end va_list ap; va_list bp; int i; int len = 0; // arr_args[0] is the program path // arr_args[1] is the program name // arr_args[2-args] are the arguments to the program int lengths[args+1]; int prog_len; // put args[0] len here int prog_name_len = 0; // allocate prog and an array large enough for everything va_start(ap, args); va_copy(bp, ap); // powerpc can't do two va_starts. use va_copy instead. // fill prog char *prog = va_arg( ap, char *); prog_len = strlen(prog) + 1; // get program name length from path for (i = 0; i < prog_len; i = i + 1) { if ( strncmp( "/", prog + i, 1 ) == 0) { prog_name_len = prog_len - (i+1); } } ERROR_CHECK(prog_name_len > 0, "First arg must be a complete path, e.g. /bin/touch. You tried '%s'.", prog); lengths[0] = prog_name_len; // get the rest of the lengths for (i = 1; i < args; i = i + 1) { len = strlen(va_arg (ap, char *)) + 1; lengths[i] = len; } va_end( ap ); // set up arr_args char * arr_args[args+1]; for (i = 0; i < args; i = i + 1) { ERROR_SALLOC(arr_args[i], lengths[i]); } // get prog name from path char *prog_name = (char *)((prog + prog_len) - prog_name_len); len = strlen(prog_name) + 1; memcpy( arr_args[0], prog_name, len-1 ); arr_args[0][len-1] = '\0'; // we don't need the path again so run va_arg once to pass it. va_arg(bp, char *); for (i = 1; i < args; i = i + 1) { memcpy(arr_args[i], va_arg (bp, char *), lengths[i] - 1); arr_args[i][lengths[i]-1] = '\0'; } va_end(bp); // add a null element to the array arr_args[args] = (char*)salloc(1); arr_args[args] = 0; // WRONG: arr_args[args][0] = '\0'; char *pathbuf; size_t n; if (clearenv() != 0) { ERROR_NORESPONSE("Command clearenv failed. Exiting."); exit(1); } n = confstr(_CS_PATH, NULL, 0); if (n == 0) { ERROR_NORESPONSE("Command confstr not available. Exiting."); exit(1); } if ((pathbuf = salloc(n)) == NULL) { ERROR_NORESPONSE("Command salloc errored. Exiting."); exit(1); } if (confstr(_CS_PATH, pathbuf, n) == 0) { ERROR_NORESPONSE("Command confstr errored. Exiting."); exit(1); } if (setenv("PATH", pathbuf, 1) == -1) { ERROR_NORESPONSE("Command setenv PATH errored. Exiting."); exit(1); } SFREE(pathbuf);//void, no test if (setenv("IFS", " \t\n", 1) == -1) { ERROR_NORESPONSE("Command setenv IFS errored. Exiting."); exit(1); } // environment is sanitized //https://www.securecoding.cert.org/confluence/display/seccode/ENV03-C.+Sanitize+the+environment+when+invoking+external+programs char *ptr_user_environment = str_user_environment; char *ptr_end_user_environment = str_user_environment + strlen(str_user_environment); char str_name[255]; char str_value[255]; int int_length; while (ptr_user_environment < ptr_end_user_environment) { DEBUG(">%s<", ptr_user_environment); //get name //search for next comma, colon, or null byte int_length = strcspn(ptr_user_environment, "&="); memcpy(str_name, ptr_user_environment, int_length); str_name[int_length] = '\0'; ptr_user_environment = ptr_user_environment + int_length + 1; //get value //search for next comma, colon, or null byte int_length = strcspn(ptr_user_environment, "&="); memcpy(str_value, ptr_user_environment, int_length); str_value[int_length] = '\0'; ptr_user_environment = ptr_user_environment + int_length + 1; //use name and value DEBUG(">%s|%s<", str_name, str_value); char *temp = uri_to_cstr(str_value, strlen(str_value)); setenv(str_name, temp, 1); SFREE(temp); } DEBUG(">%s|%i<", prog, args); for (i = 0; i < args; i += 1) { DEBUG(">%i|%s<", i, arr_args[i]); } int int_status = execv( prog, arr_args ); ptr_user_environment = str_user_environment; while (ptr_user_environment < ptr_end_user_environment) { DEBUG(">%s<", ptr_user_environment); //get name //search for next comma, colon, or null byte int_length = strcspn(ptr_user_environment, "&="); memcpy(str_name, ptr_user_environment, int_length); str_name[int_length] = '\0'; ptr_user_environment = ptr_user_environment + int_length + 1; //get value //search for next comma, colon, or null byte int_length = strcspn(ptr_user_environment, "&="); memcpy(str_value, ptr_user_environment, int_length); str_value[int_length] = '\0'; ptr_user_environment = ptr_user_environment + int_length + 1; //use name and value DEBUG(">%s|%s<", str_name, str_value); unsetenv(str_name); } //DEBUG("%s %s %s %s %s", prog, arr_args[0], arr_args[1], arr_args[2], arr_args[3]); if (int_status == -1) { ERROR_NORESPONSE("Error executing '%s' %d (%s)\n", prog, errno, strerror(errno)); for (i = 0; i < args; i = i + 1) { SFREE(arr_args[i]); } SFREE(arr_args[args]); _exit(127); } ERROR_NORESPONSE("Error in sunny_exec: '%s'\n", prog); for (i = 0; i < args; i = i + 1) { SFREE(arr_args[i]); } SFREE(arr_args[args]); // This process terminates. The calling (parent) process will now continue. // we only return a value if there was an error. (errno will be set) // the following line won't execute unless there is an error. _exit(127); } DEBUG("TEST3"); return -1; }