Ejemplo n.º 1
0
//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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
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);
}
Ejemplo n.º 4
0
// 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;
}
Ejemplo n.º 5
0
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;
}