//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; }
int main(int argc, char **argv) { ////joseph stuff get_full_conf(argc, argv); ////justin stuff int sock; struct addrinfo hints, *res; int reuseaddr = 1; /* True */ /* Get the address info */ memset(&hints, 0, sizeof hints); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; char str_envelope_port[25]; sprintf(str_envelope_port, "%d", int_global_envelope_port); if (getaddrinfo(NULL, str_envelope_port, &hints, &res) != 0) { DEBUG("getaddrinfo"); return 1; } /* Create the socket */ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock == -1) { DEBUG("socket"); return 1; } /* Enable the socket to reuse the address */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(int)) == -1) { DEBUG("setsockopt"); return 1; } /* Bind to the address */ if (bind(sock, res->ai_addr, res->ai_addrlen) == -1) { DEBUG("bind"); return 1; } /* Listen */ if (listen(sock, 128) == -1) { DEBUG("listen"); return 1; } freeaddrinfo(res); /* Set up the zombie signal handler */ struct sigaction sa1; sa1.sa_handler = wait_for_child; sigemptyset(&sa1.sa_mask); sa1.sa_flags = SA_RESTART | SA_NOCLDSTOP; if (sigaction(SIGCHLD, &sa1, NULL) == -1) { DEBUG("sigaction Set Listen SIGCHLD error"); return 1; } /* Set up the kill signal handler */ struct sigaction sa2; sa2.sa_handler = kill_handler; sigemptyset(&sa2.sa_mask); //sa2.sa_flags = SA_RESTART; sa2.sa_flags = 0;//nothing if (sigaction(SIGTERM, &sa2, NULL) == -1) { DEBUG("sigaction Set Listen SIGTERM error"); return 1; } init_aes_key_iv(); //get time zone time_t time_last; time(&time_last); //convert to localtime struct tm *tm_last = localtime(&time_last); time_t time_current; struct tm *tm_current; NOTICE("STARTUP SUCCESSFULL\n"); bol_error_state = false;//stop var logs caused by startup non-error errno = 0;//now if there is an error that doesn't set errno, we know that it didn't /* Main loop */ while (1) { struct sockaddr_in their_addr; socklen_t size = sizeof(struct sockaddr_in); int newsock = accept(sock, (struct sockaddr*)&their_addr, &size); if (newsock == -1) { DEBUG("accept:(%s)", strerror(errno)); //perror("accept"); free_config(); return 0; } DEBUG("Got a connection from %s on port %d\n", inet_ntoa(their_addr.sin_addr), htons(their_addr.sin_port)); // when we were starting as root and then setting the user name //setuid( pwbufp->pw_uid ); //get time zone time(&time_current); //convert to localtime tm_current = localtime(&time_current); //check for reinit if (tm_current->tm_yday != tm_last->tm_yday) { init_aes_key_iv(); tm_last = tm_current; } DEBUG("###################################################\n"); DEBUG("############## NEW ENVELOPE REQUEST ###############\n"); // ############ development ############### /* handle(newsock); close(newsock); */ // ############ production ############### int pid; pid = fork(); if (pid == 0) { // In child process close(sock); /* Set up the default kill signal handler (read: remove custom handler) */ /* struct sigaction sa3; sa3.sa_handler = SIG_DFL; sigemptyset(&sa3.sa_mask); //sa3.sa_flags = SA_RESTART; if (sigaction(SIGTERM, &sa3, NULL) == -1) { perror("sigaction Set Listen SIGTERM default error"); return 1; } */ global_csock = newsock; errno = 0;//now if there is an error that doesn't set errno, we know that it didn't handle(newsock); if (close(newsock) != 0) { ERROR_NORESPONSE("close(newsock): %d (%s)", errno, strerror(errno)); } free_config(); //exit(EXIT_SUCCESS); return 0; } else { // Parent process if (pid == -1) { DEBUG("fork:(%s)", strerror(errno)); //perror("fork"); free_config(); return 1; } else { close(newsock); } } //########################################## } free_config(); close(sock); return 0; }
char *s_exec_send_return(char *str_user_environment, char *str_stdin_input, int args, ... ) { NOTICE("EXECUTE"); char *str_final_buffer = NULL; FILE *pFile = NULL; FILE *pWriteFile = NULL; int pfp1[2], pfp2[2], pid; /* the pipe and the process */ //FILE *fdopen(); /* fdopen makes a fd a stream */ int parent1_end, child1_end, parent2_end, child2_end; /* of pipe */ parent1_end = SUN_READ; child1_end = SUN_WRITE; parent2_end = SUN_WRITE; child2_end = SUN_READ; ERROR_CHECK(pipe(pfp1) == 0, "pipe failed: %d (%s)", errno, strerror(errno)); ERROR_CHECK(pipe(pfp2) == 0, "pipe failed: %d (%s)", errno, strerror(errno)); ERROR_CHECK((pid = fork()) != -1, "fork failed: %d (%s)", errno, strerror(errno)); /* --------------- parent code here ------------------- */ /* need to close one end and fdopen other end */ if (pid > 0) { ERROR_CHECK(close(pfp1[child1_end]) == 0, "close failed: %d (%s)", errno, strerror(errno)); ERROR_CHECK(close(pfp2[child2_end]) == 0, "close failed: %d (%s)", errno, strerror(errno)); //send content pWriteFile = fdopen(pfp2[parent2_end], "w"); //filehandle error ERROR_CHECK(pWriteFile, "fopen pWriteFile failed: %d (%s)\n", errno, strerror(errno)); //write content ERROR_CHECK(fwrite(str_stdin_input, 1, strlen(str_stdin_input), pWriteFile) == strlen(str_stdin_input), "fwrite pWriteFile failed: %d (%s)\n", errno, strerror(errno)); ERROR_CHECK(fclose(pWriteFile) == 0, "fclose pWriteFile failed: %d (%s)\n", errno, strerror(errno)); //get content pFile = fdopen(pfp1[parent1_end], "r"); //filehandle error ERROR_CHECK(pFile, "fopen pFile failed. %d (%s)\n", errno, strerror(errno)); //put content into final_buffer ERROR_CAT_CSTR(str_final_buffer, ""); char buffer[2048 + 1]; while (fgets(buffer, 2048, pFile) != NULL) { buffer[2048] = '\0'; ERROR_CAT_APPEND(str_final_buffer, buffer); } //int int_len_file = strlen(final_buffer); ERROR_CHECK(ferror(pFile) == 0, "ferror failed: %d (%s)", errno, strerror(errno)); ERROR_CHECK(fclose(pFile) != -1, "fclose pWriteFile failed. %d (%s)\n", errno, strerror(errno)); return str_final_buffer; error: if(pfp1[0]) close(pfp1[0]); if(pfp1[1]) close(pfp1[1]); if(pfp2[0]) close(pfp2[0]); if(pfp2[1]) close(pfp2[1]); if (pFile) fclose(pFile); if (pWriteFile) fclose(pWriteFile); SFREE(str_final_buffer); return NULL; } /* --------------- child code here --------------------- */ /* need to redirect stdin or stdout then exec the cmd */ DEBUG("global_csock: %i", global_csock); if (global_csock > -1) { DEBUG("close(global_csock): %i", global_csock); close(global_csock); } if (close(pfp1[parent1_end]) == -1) {/* close the parent end */ ERROR_NORESPONSE("CHILD: Could not close(pfp1[parent1_end])"); exit(1); /* do NOT return */ } if (close(pfp2[parent2_end]) == -1) {/* close the parent end */ ERROR_NORESPONSE("CHILD: Could not close(pfp2[parent2_end])"); exit(1); /* do NOT return */ } if (dup2(pfp1[child1_end], child1_end) == -1) { ERROR_NORESPONSE("CHILD: Could not dup2(pfp1[child1_end], child1_end)"); exit(1); } if (dup2(pfp2[child2_end], child2_end) == -1) { ERROR_NORESPONSE("CHILD: Could not dup2(pfp2[child2_end], child2_end)"); exit(1); } //copy stderr as well as stdout if (dup2(pfp1[child1_end], 2) == -1) { ERROR_NORESPONSE("CHILD: Could not dup2(pfp1[child1_end], 2)"); exit(1); } if (close(pfp1[child1_end]) == -1) { /* done with this one */ ERROR_NORESPONSE("CHILD: Could not close(pfp1[child1_end])"); exit(1); } if (close(pfp2[child2_end]) == -1) { /* done with this one */ ERROR_NORESPONSE("CHILD: Could not close(pfp2[child2_end])"); exit(1); } /* all set to run cmd */ // 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); } } if (prog_name_len == 0) { ERROR_NORESPONSE("First arg must be a complete path, e.g. /bin/touch. You tried '%s'.", prog ); exit(1); } 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) { arr_args[i] = (char*)salloc(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'; ERROR_NORESPONSE("arr_args[i]: %s, %i", arr_args[i], i); } 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 // user environment variables 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) { //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 if (ptr_user_environment < ptr_end_user_environment) { DEBUG(">%s|%s|%s<", str_name, str_value, ptr_user_environment); } char *temp = uri_to_cstr(str_value, strlen(str_value)); setenv(str_name, temp, 1); SFREE(temp); } DEBUG("prog: %s", prog); int int_status = execv(prog, arr_args); ptr_user_environment = str_user_environment; while (ptr_user_environment < ptr_end_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 if (ptr_user_environment < ptr_end_user_environment) { DEBUG(">%s|%s|%s<", str_name, str_value, ptr_user_environment); } unsetenv(str_name); } if (int_status == -1) { ERROR_NORESPONSE("Error executing '%s' %d (%s)\n", prog_name, errno, strerror(errno)); _exit(127); } // 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. ERROR_NORESPONSE("Error in sunny_exec: '%s'\n", prog_name); exit(1); }
// 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; }
bool handle(int csock) { NOTICE("################# REQUEST"); PGconn *cnxn = NULL; char buf[BUF_LEN + 2]; buf[0] = 0; DEFINE_VAR_ALL(str_response, str_request, str_uri, str_temp, str_form_data); DEFINE_VAR_MORE(str_correct_referer_start1, str_correct_referer_start2); DEFINE_VAR_MORE(str_referer, str_host, str_request_len, str_boundary); DEFINE_VAR_MORE(str_cookie_envelope, str_complete_response, str_buffer); DEBUG("### get the str_request\n"); //########################################## //### get the str_request //DEBUG(">%d|%d<", SSIZE_MAX, BUF_LEN); int int_request_len = BUF_LEN; memset(buf, 0, BUF_LEN + 1); int_request_len = read(csock, buf, BUF_LEN); FINISH_SALLOC(str_request, int_request_len + 1); memcpy(str_request, buf, int_request_len); str_request[int_request_len] = '\0'; //HERE BE DRAGONS //Maintainer: joseph //This code reads from the socket only for as long as is necessary. //If we have just one extra read command, it will hang until the browser //sends more data. Which it won't. So read until end of request. //@@@@@@@@@@@@@@@@@@@@@**^^""~~~"^@@^*@*@@**@@@@@@@@@ //@@@@@@@@@@@@@*^^'"~ , - ' '; ,@@b. ' -e@@@@@@@@@ //@@@@@@@@*^"~ . ' . ' ,@@@@( e@*@@@@@@@@@@ //@@@@@^~ . . ' @@@@@@, ~^@@@@@@@@@@@ //@@@~ ,e**@@*e, ,e**e, . ' '@@@@@@e, "*@@@@@'^@ //@',e@@@@@@@@@@ e@@@@@@ ' '*@@@@@@ @@@' 0 //@@@@@@@@@@@@@@@@@@@@@',e, ; ~^*^' ;^~ ' 0 //@@@@@@@@@@@@@@@^""^@@e@@@ .' ,' .' @ //@@@@@@@@@@@@@@' '@@@@@ ' , ,e' . ;@ //@@@@@@@@@@@@@' ,&&, ^@*' , . i^"@e, ,e@e @@ //@@@@@@@@@@@@' ,@@@@, ; ,& !,,@@@e@@@@ e@@ //@@@@@,~*@@*' ,@@@@@@e, ', e^~^@, ~'@@@@@@,@@@ //@@@@@@, ~" ,e@@@@@@@@@*e*@* ,@e @@""@e,,@@@@@@@@@ //@@@@@@@@ee@@@@@@@@@@@@@@@" ,e@' ,e@' e@@@@@@@@@@@@@ //@@@@@@@@@@@@@@@@@@@@@@@@" ,@" ,e@@e,,@@@@@@@@@@@@@@ //@@@@@@@@@@@@@@@@@@@@@@@~ ,@@@,,0@@@@@@@@@@@@@@@@@@@ //@@@@@@@@@@@@@@@@@@@@@@@@,,@@@@@@@@@@@@@@@@@@@@@@@@@ //""""""""""""""""""""""""""""""""""""""""""""""""""" char *ptr_boundary_start = strstr(str_request, "Content-Type: multipart/form-data; boundary="); if (ptr_boundary_start != NULL && strchr(ptr_boundary_start, 13) == NULL) { memset(buf, 0, BUF_LEN + 1); int int_current_length = read(csock, buf, BUF_LEN); FINISH_SREALLOC(str_request, int_current_length + int_request_len + 1); memcpy(str_request + int_request_len, buf, int_current_length); str_request[int_current_length + int_request_len] = '\0'; int_request_len = int_request_len + int_current_length; } //DEBUG("test0>%s|%i<", str_request, int_request_len); char *request_ptr; //// ****if upload then special case if (strstr(str_request, "Content-Type: multipart/form-data; boundary=") != 0) { //get boundary char *boundary_ptr = strstr(str_request, "Content-Type: multipart/form-data; boundary=") + 44; char *boundary_end_ptr = strchr(boundary_ptr, 13) != 0 ? strchr(boundary_ptr, 13) : strchr(boundary_ptr, 10); DEBUG("str_boundary: %d %d", boundary_end_ptr, boundary_ptr); int int_boundary_length = boundary_end_ptr - boundary_ptr; DEBUG("str_boundary: %d", int_boundary_length); FINISH_SALLOC(str_boundary, int_boundary_length + 3); //extra and null byte DEBUG("TESTING1"); memcpy(str_boundary, boundary_ptr, int_boundary_length); DEBUG("TESTING2"); str_boundary[int_boundary_length + 0] = '-'; DEBUG("TESTING3"); str_boundary[int_boundary_length + 1] = '-'; DEBUG("TESTING4"); str_boundary[int_boundary_length + 2] = '\0'; DEBUG("TESTING5"); int int_current_length = BUF_LEN; DEBUG("TESTING6"); //DEBUG("str_boundary: %s", str_boundary); //DEBUG("str_request: %s", str_request); DEBUG("bstrstr(\"%-10s\", %d, \"%s\", %d", str_request, int_request_len, str_boundary, int_boundary_length + 2); /* DEBUG("test0>%s<", bstrstr( str_request, int_request_len, str_boundary, int_boundary_length + 2) == NULL ? "NULL" : "NOT NULL"); while (bstrstr( str_request, int_request_len, str_boundary, int_boundary_length + 2) == NULL) {//while null DEBUG("test1"); memset(buf, 0, BUF_LEN + 1); //FINISH_SALLOC(str_buffer, BUF_LEN + 2); DEBUG("test2"); int_current_length = read(csock, buf, BUF_LEN); DEBUG("test3"); FINISH_SREALLOC(str_request, int_request_len + int_current_length + 1); DEBUG("test4>%s<", str_request); memcpy(str_request + int_request_len, buf, int_current_length); int_request_len = int_request_len + int_current_length; str_request[int_request_len] = '\0'; //SFREE(str_buffer); DEBUG("test5>%i<", int_request_len); } */ DEBUG(">%s<", bstrstr( str_request + int_request_len - int_current_length - int_boundary_length, int_current_length + int_boundary_length, str_boundary, int_boundary_length + 2) == NULL ? "NULL" : "NOT NULL"); while (bstrstr( str_request + int_request_len - int_current_length - int_boundary_length, int_current_length + int_boundary_length, str_boundary, int_boundary_length + 2) == NULL) {//while null memset(buf, 0, BUF_LEN + 1); //DEBUG("test1"); int_current_length = read(csock, buf, BUF_LEN); //DEBUG("test2"); FINISH_SREALLOC(str_request, int_request_len + int_current_length + 1); //DEBUG("test3>%s<", str_request); memcpy(str_request + int_request_len, buf, int_current_length); int_request_len = int_request_len + int_current_length; str_request[int_request_len] = '\0'; //DEBUG("test4>%i<", int_request_len); } DEBUG("test5>%s<", bstrstr( str_request, int_request_len, str_boundary, int_boundary_length + 2) - 25); SFREE(str_boundary); //// **** // if post or put, then get content length and receive that amount after two newlines, then break } else if (strncmp(str_request, "P", 1) == 0) { //we need Content-Length: before we can continue while (! strstr(str_request, "Content-Length:")) { memset(buf, 0, BUF_LEN + 1); //DEBUG("test1"); int_request_len = read(csock, buf, BUF_LEN); //DEBUG("test2>%i<", int_request_len); //buf[request_len] = 0; FINISH_CAT_APPEND(str_request, buf); //DEBUG("#request_len:%d", int_request_len); } request_ptr = strstr(str_request, "Content-Length:"); // if we didn't find anything we need to stop, len("Content-Length")==15 if (strlen(request_ptr) < 16) { // error bad str_request FINISH("Bad str_request"); } // move pointer to start of content length value request_ptr = request_ptr + 15; //DEBUG("request_ptr>%s<", request_ptr); // step through the buffer and see if we can get the length int req_len = 0; while (request_ptr != 0 && *request_ptr != '\r' && *request_ptr != '\n') { if (request_ptr == 0 && req_len == 0) { // error bad str_request } //do not comment next line!!!!!!!! give inconsistent output without this line!!!!!! idk why!!!!!!! //DEBUG("test1>%c<", *request_ptr); /////////////// if (*request_ptr != '\r' && *request_ptr != '\n') { request_ptr = request_ptr + 1; req_len = req_len + 1; } } FINISH_SALLOC(str_request_len, req_len + 1); request_ptr = request_ptr - req_len; memcpy(str_request_len, request_ptr, req_len); str_request_len[req_len] = '\0'; //DEBUG("test2>%s|%s<", str_request_len, request_ptr, req_len); req_len = atoi(str_request_len); SFREE(str_request_len); while (strstr(str_request,"\r\n\r\n") == 0 && strstr(str_request, "\n\n") == 0 && strstr(str_request, "\r\r") == 0) { memset(buf,0,BUF_LEN + 1); int_request_len = read(csock, buf, BUF_LEN); FINISH_CAT_APPEND(str_request, buf); } request_ptr = strstr(str_request,"\r\n\r\n") != 0 ? strstr(str_request,"\r\n\r\n") + 4 : strstr(str_request,"\n\n") != 0 ? strstr(str_request,"\n\n") + 2 : strstr(str_request,"\r\r") != 0 ? strstr(str_request,"\r\r") + 2 : 0; unsigned int int_length_we_want = ((request_ptr - str_request) + req_len); //DEBUG("test3>%s|%s<", str_request, request_ptr); //DEBUG("test4>%i|%i|%i|%i<\n", int_length_we_want, strlen( str_request ), (request_ptr - str_request), req_len); while (int_length_we_want > strlen(str_request)) { memset(buf,0,BUF_LEN + 1); int_request_len = read(csock, buf, BUF_LEN); FINISH_CAT_APPEND(str_request, buf); //DEBUG("test4.1>%i|%i<\n", int_length_we_want, strlen( str_request )); } //DEBUG("test5\n"); int_request_len = strlen(str_request); // if not POST, then break at two newlines. // (only other request we accept is GET, we don't use any other methods of request) } else { while (strstr(str_request,"\r\n\r\n") == 0 && strstr(str_request,"\n\n") == 0 && strstr(str_request,"\r\r") == 0) { memset(buf, 0, BUF_LEN + 1); int_request_len = read(csock, buf, BUF_LEN); FINISH_CAT_APPEND(str_request, buf); } int_request_len = strlen(str_request); } DEBUG("request_len>%i<", strlen(str_request)); /* //for testing actions GS.ajaxJSON('URI', 'PARAMS', function (data, error) { if (!error) { console.log(data); } else { GS.ajaxErrorDialog(data); } }); */ str_uri = str_uri_path(str_request); FINISH_CHECK(str_uri != NULL, "str_uri_path failed"); INFO("### str_uri: %s", str_uri); str_host = request_header(str_request, "host"); INFO("### str_host: %s", str_host); //DEBUG("### REQUEST: %s", str_request); //check referer str_referer = request_header(str_request, "Referer"); INFO("### str_referer: %s", str_referer); //when we have a referer, we should make sure it matches our website, but we have a few exceptions. if (str_referer != NULL) { FINISH_CAT_CSTR(str_correct_referer_start1, "https://", str_host); FINISH_CAT_CSTR(str_correct_referer_start2, "http://" , str_host); FINISH_CHECK( strncmp(str_correct_referer_start1, str_referer, strlen(str_correct_referer_start1)) == 0 || strncmp(str_correct_referer_start2, str_referer, strlen(str_correct_referer_start2)) == 0 || strlen(str_referer) <= 0 || strncmp(str_uri, "/v1/" , 4 ) != 0 || //strncmp(str_uri, "/v1/env/auth", 12) == 0 || strncmp(str_uri, "/v1/cluster" , 11) == 0 || strncmp(str_uri, "/v1/app" , 7 ) == 0 || strncmp(str_uri, "/v1/dev" , 7 ) == 0, "Referer does not match host."); SFREE(str_correct_referer_start1); SFREE(str_correct_referer_start2); } //#################################################################################################### //######################################### MANAGE COOKIES ########################################### // set up database connection // FEAR NOT GCC! This will not be used uninitialized. //PQinitOpenSSL(0, 0); //prevent Libpq from initializing ssl bool bol_valid_subdomain = false; //if subdomain database configuration is active, then change int_global_current_conn_port //we use int_global_current_conn_port to connect to the postgres instance //if the subdomain is the default subdomain, we should connect to production //if the subdomain is not the default subdomain, we should connect to the correct developer area //if the subdomain is not recognized, we should connect to production if (strlen(str_global_developers) > 0) { char *temp = strchr(str_host, '.'); int int_length = temp - str_host; FINISH_SALLOC(str_current_subdomain, int_length + 1); DEBUG("### str_host: %s, temp: %s, char: %c, int_length: %d\n", str_host, temp, '.', int_length); memcpy(str_current_subdomain, str_host, int_length); str_current_subdomain[int_length] = '\0'; str_temp = getport(str_global_developers, str_current_subdomain); FINISH_CHECK(str_temp != NULL, "getport failed"); if (strlen(str_temp) > 0) { DEBUG("VALID SUBDOMAIN DETECTED >%s|%s<", str_global_developers, str_temp); int_global_current_conn_port = atoi(str_temp); bol_valid_subdomain = true; } SFREE(str_temp); } else { FINISH_CAT_CSTR(str_current_subdomain, ""); } DEBUG(">%s|%s|%i|%i<", str_uri, "/auth_envelope/accept_auth", strlen(str_uri), strncmp(str_uri, "/auth_envelope/accept_auth", 26) == 0); DEBUG("test0>str_request: %s", str_request); str_cookie_envelope = str_cookie(str_request, "envelope"); DEBUG("test1"); bol_global_public = false; DEBUG("str_uri: >%s< str_uri + 13 + strcspn(str_uri + 13, \"./\"): >%s<", str_uri, str_uri + 13 + strcspn(str_uri + 13, "./")); // if the URL does not start with /v1 // then serve from the web_root if (strncmp(str_uri, "/v1/", 4) != 0) { str_response = link_web_root(csock, str_uri, bol_valid_subdomain ? str_current_subdomain : ""); FINISH_CHECK(str_response != NULL, "link_web_root failed"); goto finish; // postgres functions that start with actionnc_ or acceptnc_ // these CAN have a COOKIE, but it WON'T BE USED // set up a public connection } else if (//str_cookie_envelope == NULL && strlen(str_uri) >= 13 && strncmp(str_uri, "/v1/cluster/", 12) == 0 && (strncmp(str_uri + 13 + strcspn(str_uri + 13, "./"), ".acceptnc_", 10) == 0 || strncmp(str_uri + 13 + strcspn(str_uri + 13, "./"), ".actionnc_", 10) == 0)) { cnxn = set_cnxn_public(csock, str_request); // built in envelope functions // these links CAN have a COOKIE, but if we don't then set up a public connection } else if (str_cookie_envelope == NULL && ((strlen(str_uri) >= 18 && strncmp(str_uri, "/v1/env/action_info" , 18) == 0) || (strlen(str_uri) >= 20 && strncmp(str_uri, "/v1/env/action_upload" , 20) == 0) || (strlen(str_uri) >= 22 && strncmp(str_uri, "/v1/env/accept_download" , 22) == 0) || (strlen(str_uri) >= 23 && strncmp(str_uri, "/v1/envelope/action_info" , 23) == 0) || (strlen(str_uri) >= 25 && strncmp(str_uri, "/v1/envelope/action_upload" , 25) == 0) || (strlen(str_uri) >= 27 && strncmp(str_uri, "/v1/envelope/accept_download", 27) == 0) || (strlen(str_uri) >= 21 && strncmp(str_uri, "/v1/env/action_select", 21) == 0) || (strlen(str_uri) >= 21 && strncmp(str_uri, "/v1/env/action_update", 21) == 0) || (strlen(str_uri) >= 21 && strncmp(str_uri, "/v1/env/action_insert", 21) == 0) || (strlen(str_uri) >= 21 && strncmp(str_uri, "/v1/env/action_delete", 21) == 0) || (strlen(str_uri) >= 20 && strncmp(str_uri, "/v1/env/action_order" , 20) == 0))) { cnxn = set_cnxn_public(csock, str_request); // authentication links for normal user, these CAN have a COOKIE } else if ((strlen(str_uri) >= 26 && strncmp(str_uri, "/auth_envelope/accept_auth", 26) == 0) || (strlen(str_uri) >= 12 && strncmp(str_uri, "/v1/env/auth", 12) == 0)) { /* FINISH_CHECK(strncmp(str_current_subdomain, str_global_subdomain, strlen(str_global_subdomain)) == 0, "Must be in \"%s\" subdomain.", str_global_subdomain); */ str_response = link_auth(cnxn, str_request); FINISH_CHECK(str_response != NULL, "link_auth failed"); goto finish; // authentication links for superuser, these REQUIRE a COOKIE } else if ((strlen(str_uri) >= 16 && strncmp(str_uri, "/v1/postage/auth", 16) == 0)) { str_response = link_auth_postage(str_request); FINISH_CHECK(str_response != NULL, "link_auth_postage failed"); goto finish; // superuser links, these REQUIRE a COOKIE } else if (strncmp(str_uri, "/v1/dev" , 7 ) == 0 || strncmp(str_uri, "/v1/postage", 11) == 0 || strncmp(str_uri, "/v1/sql" , 7 ) == 0) { cnxn = set_cnxn_postage(csock, str_uri, str_request); // subdomain links, these REQUIRE a COOKIE } else if (bol_valid_subdomain) { cnxn = set_cnxn_test(csock, str_uri, str_request); // production links, these REQUIRE a COOKIE } else { cnxn = set_cnxn(csock, str_uri, str_request); } //IF NULL THEN EXIT, CSOCK IS ALREADY WRITTEN TO BY set_cnxn AND set_cnxn_test if (cnxn == NULL) { //if we use FINISH_CHECK, there will be a sunlogf //we don't want a sunlogf cause there is no error. we just want to return goto finish; } // cnxn GARANTEED TO BE VALID HERE //if public cookie (or nocookie always) then public action if (bol_global_public) { str_response = main_public_action(cnxn, csock, str_uri, str_request, int_request_len, bol_valid_subdomain ? str_current_subdomain : ""); FINISH_CHECK(str_response != NULL, "link_auth failed"); goto finish; } //################################################################################################ //########################## HAVE COOKIE, HAVE CNXN, PARSE REQUESTS ############################## DEBUG("COOKIE IS VALID"); //not a webroot request if (strncmp(str_uri, "/v1/", 4) == 0) { char *ptr_uri = str_uri + 3; //this link is for accessing the database if (strlen(ptr_uri) >= 9 && strncmp(ptr_uri, "/cluster/", 9) == 0) { str_response = link_cluster(cnxn, ptr_uri, str_request, csock); FINISH_CHECK(str_response != NULL, "link_cluster failed"); //this link is for uploading a file to role } else if (strlen(ptr_uri) >= 16 && strncmp(ptr_uri, "/upload_envelope", 16) == 0) { str_response = link_upload(cnxn, str_request, int_request_len, bol_valid_subdomain ? str_current_subdomain : ""); FINISH_CHECK(str_response != NULL, "link_upload failed"); //this link is for builtin c actions like action_select (read from view) } else if (strlen(ptr_uri) >= 10 && strncmp(ptr_uri, "/envelope/", 10) == 0) { // link system is in envelope_handle_c.c str_response = link_system(cnxn, csock, ptr_uri + 5, str_request, int_request_len, bol_valid_subdomain ? str_current_subdomain : ""); FINISH_CHECK(str_response != NULL, "link_system failed"); //shorter version of the above link } else if (strlen(ptr_uri) >= 5 && strncmp(ptr_uri, "/env/", 5) == 0) { // link system is in envelope_handle_c.c str_response = link_system(cnxn, csock, ptr_uri, str_request, int_request_len, bol_valid_subdomain ? str_current_subdomain : ""); FINISH_CHECK(str_response != NULL, "link_system failed"); //read file from role } else if (strlen(ptr_uri) >= 6 && strncmp(ptr_uri, "/role/", 6) == 0) { str_response = link_role(csock, cnxn, ptr_uri, bol_valid_subdomain ? str_current_subdomain : ""); FINISH_CHECK(str_response != NULL, "link_role failed"); //read app file } else if (strncmp(ptr_uri, "/app/", 5) == 0) { str_response = link_apps(csock, cnxn, ptr_uri, bol_valid_subdomain ? str_current_subdomain : ""); FINISH_CHECK(str_response != NULL, "link_apps failed"); //read app file, but require superuser } else if (strncmp(ptr_uri, "/dev/", 5) == 0) { str_response = link_apps(csock, cnxn, ptr_uri, bol_valid_subdomain ? str_current_subdomain : ""); FINISH_CHECK(str_response != NULL, "link_apps failed"); //more builtin c actions, but require superuser } else if (strlen(ptr_uri) >= 9 && strncmp(ptr_uri, "/postage/", 9) == 0) { // link system is in postage_handle_c2.c str_response = link_system_postage(cnxn, csock, ptr_uri, str_request, int_request_len); FINISH_CHECK(str_response != NULL, "link_system_postage failed"); //run arbitrary sql, must be superuser } else if (strlen(ptr_uri) >= 4 && strncmp(ptr_uri, "/sql", 4) == 0) { str_response = link_sql(csock, cnxn, str_request); FINISH_CHECK(str_response != NULL, "link_sql failed"); //if none of these, error } else { NOTICE("REQUEST TYPE: UNHANDLED str_uri:%s", str_uri); FINISH_CAT_CSTR(str_response, "HTTP/1.1 303 See Other\r\nLocation: /index.html\r\n"); } //web_root request should already have been handled, error } else { NOTICE("REQUEST TYPE: UNHANDLED str_uri:%s", str_uri); FINISH_CAT_CSTR(str_response, "HTTP/1.1 303 See Other\r\nLocation: /index.html\r\n"); } finish: if (str_response != NULL) { INFO("REPLACE COOKIE IN str_response"); //replace cookie before expiration str_complete_response = replace_cookie(str_response, str_request); SFREE_PWORD(str_response); DEBUG("str_complete_response: %s", str_complete_response); if ((long)write(csock, str_complete_response, strlen(str_complete_response)) != (long)strlen(str_complete_response)) { str_complete_response = ERROR_RESPONSE("write failed: %d (%s)", errno, strerror(errno)); write(csock, str_complete_response, strlen(str_complete_response)); } } else { ERROR_NORESPONSE("no str_response"); } fsync(csock); NOTICE("RESPONSE SENT %d bytes", strlen(str_complete_response)); if (cnxn != NULL) PQfinish(cnxn); SFREE_PWORD(str_request); SFREE_ALL(); return true; }