// $_POST_RAW contains the entire post message and is read from stdin on access static Exec_stat cgi_compute_post_raw_var(void *p_context, MCVariable *p_var) { MCCacheHandle *t_stdin = new MCCacheHandle(s_cgi_stdin_cache); bool t_success = true; char *t_content_length; t_content_length = MCS_getenv("CONTENT_LENGTH"); if (t_content_length != NULL) { uint32_t t_length; t_length = atoi(t_content_length); uint32_t t_read = 0; char *t_data; t_data = new char[t_length]; t_success = t_stdin->Read(t_data, t_length, t_read) && t_length == t_read; // Store the raw POST data if (t_success) s_cgi_post_raw -> copysvalue(MCString(t_data, t_length)); delete t_data; } delete t_stdin; return t_success ? ES_NORMAL : ES_ERROR; }
bool MCSessionGenerateID(MCStringRef &r_id) { // php calculates session ids by hashing a string composed of REMOTE_ADDR, time in seconds & milliseconds, and a random value MCAutoStringRef t_remote_addr_string; char *t_remote_addr; t_remote_addr = NULL; if (MCS_getenv(MCSTR("REMOTE_ADDR"), &t_remote_addr_string)) MCCStringClone(MCStringGetCString(*t_remote_addr_string), t_remote_addr); time_t t_time; time(&t_time); MCAutoDataRef t_randombytes; // MW-2013-05-21; [[ RandomBytes ]] Use system primitive rather than SSL // directly. /* UNCHECKED */ MCU_random_bytes(64, &t_randombytes); md5_state_t t_state; md5_byte_t t_digest[16]; md5_init(&t_state); if (t_remote_addr != NULL) md5_append(&t_state, (md5_byte_t *)t_remote_addr, MCCStringLength(t_remote_addr)); md5_append(&t_state, (md5_byte_t *)&t_time, sizeof(t_time)); md5_append(&t_state, (md5_byte_t *)MCDataGetBytePtr(*t_randombytes), 64); md5_finish(&t_state, t_digest); return byte_to_hex((uint8_t*)t_digest, 16, r_id); }
Boolean MCDispatch::openenv(const char *sname, const char *env, char **outpath, IO_handle &stream, uint4 offset) { if ((env = MCS_getenv(env)) != NULL) { char *pathstring = strclone(env); char *fullpath = new char[strlen(env) + strlen(sname) + 2]; char *eptr = pathstring; while (eptr != NULL) { char *path = eptr; eptr = strchr(eptr, ENV_SEPARATOR); if (eptr != NULL) *eptr++ = '\0'; #ifdef _WIN32 sprintf(fullpath, "%s\\%s", path, sname); #else sprintf(fullpath, "%s/%s", path, sname); #endif if ((stream = MCS_open(fullpath, IO_READ_MODE, True, False, offset)) != NULL) { delete pathstring; *outpath = fullpath; return True; } } delete pathstring; delete fullpath; } return False; }
// MM-2011-07-13: Added new deferred variable $_GET_BINARY. // $_GET_BINARY is just the binary get data not encoded in the native charset. static Exec_stat cgi_compute_get_binary_var(void *p_context, MCVariable *p_var) { MCExecPoint ep; const char *t_query_string; t_query_string = MCS_getenv("QUERY_STRING"); if (t_query_string != NULL) cgi_store_form_urlencoded(ep, s_cgi_get_binary, t_query_string, t_query_string + strlen(t_query_string), false); return ES_NORMAL; }
// MM-2011-07-13: Added new deferred variable $_GET_RAW. // $_GET_RAW is just a copy of the QUERY_STRING. static Exec_stat cgi_compute_get_raw_var(void *p_context, MCVariable *p_var) { MCExecPoint ep; const char *t_query_string; t_query_string = MCS_getenv("QUERY_STRING"); if (t_query_string != NULL) s_cgi_get_raw -> copysvalue(MCString(t_query_string, strlen(t_query_string))); return ES_NORMAL; }
bool MCSessionCreateSession(MCSessionIndexRef p_index, MCStringRef p_session_id, MCSession *&r_session) { bool t_success = true; MCSession *t_session = NULL; MCAutoStringRef t_remote_addr_string; char *t_remote_addr; t_remote_addr = NULL; if (MCS_getenv(MCSTR("REMOTE_ADDR"), &t_remote_addr_string)) MCCStringClone(MCStringGetCString(*t_remote_addr_string), t_remote_addr); t_success = MCMemoryNew(t_session); if (t_success) t_success = MCCStringClone(t_remote_addr ? t_remote_addr : "", t_session->ip); if (t_success) { if (p_session_id != nil && !MCStringIsEmpty(p_session_id)) { t_session->id = strdup(MCStringGetCString(p_session_id)); t_success = true; } else { MCAutoStringRef t_session_id; t_success = MCSessionGenerateID(&t_session_id); t_session->id = strdup(MCStringGetCString(*t_session_id)); } } if (t_success) t_success = MCCStringFormat(t_session->filename, "%s_%s", t_remote_addr ? t_remote_addr : "", t_session->id); if (t_success) t_success = MCSessionIndexAddSession(p_index, t_session); if (t_success) r_session = t_session; else { if (t_session != NULL) MCSessionCloseSession(t_session, false); } return t_success; }
static Exec_stat cgi_compute_cookie_var(void *p_context, MCVariable *p_var) { bool t_success = true; char *t_cookie_string; t_cookie_string = MCS_getenv("HTTP_COOKIE"); MCExecPoint ep; if (t_cookie_string == NULL) return ES_NORMAL; cgi_store_cookie_urlencoded(ep, s_cgi_cookie, t_cookie_string, t_cookie_string + MCCStringLength(t_cookie_string), true); return ES_NORMAL; }
static bool cgi_multipart_get_boundary(char *&r_boundary) { bool t_success = true; char *t_content_type; t_content_type = MCS_getenv("CONTENT_TYPE"); char *t_params = NULL; uint32_t t_index = 0; char **t_names = NULL; char **t_values = NULL; uint32_t t_param_count = 0; t_success = MCCStringFirstIndexOf(t_content_type, ';', t_index); if (t_success) t_success = MCMultiPartParseHeaderParams(t_content_type + t_index + 1, t_names, t_values, t_param_count); r_boundary = NULL; if (t_success) { for (uint32_t i = 0; i < t_param_count; i++) { if (MCCStringEqualCaseless(t_names[i], "boundary") && MCCStringLength(t_values[i]) > 0) { r_boundary = t_values[i]; t_values[i] = NULL; break; } } } if (t_success) t_success = r_boundary != NULL; for (uint32_t i = 0; i < t_param_count; i++) { MCCStringFree(t_names[i]); MCCStringFree(t_values[i]); } MCMemoryDeleteArray(t_names); MCMemoryDeleteArray(t_values); return t_success; }
// IM-2011-08-05: Reorganization of post variables, now generating all at the same time static Exec_stat cgi_compute_post_variables() { Exec_stat t_stat = ES_NORMAL; if (s_cgi_processed_post) return ES_NORMAL; s_cgi_processed_post = true; char *t_content_type; t_content_type = MCS_getenv("CONTENT_TYPE"); if (t_content_type != NULL && strcasecmp(t_content_type, "application/x-www-form-urlencoded") == 0) { // TODO: currently we assume that urlencoded form data is small enough to fit into memory, // so we fetch the contents from $_POST_RAW (which automatically reads the data from stdin). // in the future we should read from stdin to avoid duplicating large amounts of data MCExecPoint raw_ep, ep; MCVarref *t_raw_ref; t_raw_ref = s_cgi_post_raw->newvarref(); t_stat = t_raw_ref->eval(raw_ep); if (t_stat == ES_NORMAL) { MCString t_raw_string; t_raw_string = raw_ep.getsvalue(); cgi_store_form_urlencoded(ep, s_cgi_post_binary, t_raw_string.getstring(), t_raw_string.getstring() + t_raw_string.getlength(), false); cgi_store_form_urlencoded(ep, s_cgi_post, t_raw_string.getstring(), t_raw_string.getstring() + t_raw_string.getlength(), true); } delete t_raw_ref; } else if (t_content_type != NULL && MCCStringBeginsWithCaseless(t_content_type, "multipart/form-data;")) { // read post-data from stdin, via the stream cache MCExecPoint ep; MCCacheHandle *t_stdin = new MCCacheHandle(s_cgi_stdin_cache); IO_handle t_stdin_handle = new IO_header(t_stdin, 0); cgi_store_form_multipart(ep, t_stdin_handle); MCS_close(t_stdin_handle); } return t_stat; }
bool MCSessionFindMatchingSession(MCSessionIndexRef p_index, MCStringRef p_session_id, MCSession *&r_session) { MCAutoStringRef t_remote_addr_str; const char *t_remote_addr = NULL; if (!MCS_getenv(MCSTR("REMOTE_ADDR"), &t_remote_addr_str)) t_remote_addr = ""; else t_remote_addr = MCStringGetCString(*t_remote_addr_str); for (uint32_t i = 0; i < p_index->session_count; i++) { if (MCStringIsEqualToCString(p_session_id, p_index->session[i]->id, kMCCompareExact) && MCCStringEqual(p_index->session[i]->ip, t_remote_addr)) { r_session = p_index->session[i]; return true; } } return false; }
static void cgi_fix_path_variables() { char *t_path, *t_path_end; t_path = strdup(MCS_getenv("PATH_TRANSLATED")); t_path_end = t_path + strlen(t_path); #ifdef _WINDOWS_SERVER for(uint32_t i = 0; t_path[i] != '\0'; i++) if (t_path[i] == '\\') t_path[i] = '/'; #endif char t_sep; t_sep = '\0'; while (!MCS_exists(t_path, True)) { char *t_new_end; t_new_end = strrchr(t_path, '/'); *t_path_end = t_sep; if (t_new_end == NULL) { t_sep = '\0'; break; } t_path_end = t_new_end; t_sep = *t_path_end; *t_path_end = '\0'; } MCS_setenv("PATH_TRANSLATED", t_path); *t_path_end = t_sep; MCS_setenv("PATH_INFO", t_path_end); free(t_path); }
IO_stat MCDispatch::loadfile(const char *inname, MCStack *&sptr) { IO_handle stream; char *openpath = NULL; char *fname = strclone(inname); if ((stream = MCS_open(fname, IO_READ_MODE, True, False, 0)) != NULL) if (fname[0] != PATH_SEPARATOR && fname[1] != ':') { char *curpath = MCS_getcurdir(); if (curpath[strlen(curpath) - 1] == '/') curpath[strlen(curpath) - 1] = '\0'; openpath = new char[strlen(curpath) + strlen(fname) + 2]; sprintf(openpath, "%s/%s", curpath, fname); delete curpath; } else openpath = strclone(fname); else { char *tmparray = new char[strlen(fname) + 1]; strcpy(tmparray, fname); char *tname = strrchr(tmparray, PATH_SEPARATOR); if (tname == NULL) tname = tmparray; else tname++; if ((stream = MCS_open(tname, IO_READ_MODE, True, False, 0)) != NULL) { char *curpath = MCS_getcurdir(); openpath = new char[strlen(curpath) + strlen(tname) + 2]; sprintf(openpath, "%s/%s", curpath, tname); delete curpath; } else { if (!openstartup(tname, &openpath, stream) && !openenv(tname, "MCPATH", &openpath, stream, 0) && !openenv(tname, "PATH", &openpath, stream, 0)) { char *homename; if ((homename = MCS_getenv("HOME")) != NULL) { openpath = new char[strlen(homename) + strlen(tname) + 13]; if (homename[strlen(homename) - 1] == '/') homename[strlen(homename) - 1] = '\0'; sprintf(openpath, "%s/%s", homename, tname); if ((stream = MCS_open(openpath, IO_READ_MODE, True, False, 0)) == NULL) { sprintf(openpath, "%s/stacks/%s", homename, tname); if ((stream = MCS_open(openpath, IO_READ_MODE, True, False, 0)) == NULL) { sprintf(openpath, "%s/components/%s", homename, tname); if ((stream = MCS_open(openpath, IO_READ_MODE, True, False, 0)) == NULL) { delete openpath; openpath = NULL; } } } } } } delete tmparray; } if (stream == NULL) { if (openpath != NULL) delete openpath; delete fname; return IO_ERROR; } delete fname; IO_stat stat = readfile(openpath, inname, stream, sptr); delete openpath; MCS_close(stream); return stat; }
bool cgi_initialize() { // need to ensure PATH_TRANSLATED points to the script and PATH_INFO contains everything that follows cgi_fix_path_variables(); // Resolve the main script that has been requested by the CGI interface. MCserverinitialscript = MCsystem -> ResolvePath(MCS_getenv("PATH_TRANSLATED")); // Set the current folder to be that containing the CGI file. char *t_server_script_folder; t_server_script_folder = strdup(MCserverinitialscript); #ifdef _WINDOWS_SERVER strrchr(t_server_script_folder, '\\')[0] = '\0'; #else strrchr(t_server_script_folder, '/')[0] = '\0'; #endif MCsystem -> SetCurrentFolder(t_server_script_folder); delete t_server_script_folder; // Initialize the headers. MCservercgiheaders = NULL; MCservercgiheaders_sent = false; // Get the document root MCservercgidocumentroot = getenv("DOCUMENT_ROOT"); // Initialize the input wrapper. This creates a cache of the input stream // which is filled as the stream is read from. this allows stdin to be used // to populate the post data arrays, and also to be read from by the script // without conflicting s_cgi_stdin_cache = new MCStreamCache(IO_stdin->handle); IO_stdin = new IO_header(new MCCacheHandle(s_cgi_stdin_cache), 0); // Initialize the output wrapper, this simply ensures we output headers // before any content. IO_stdout = new IO_header(new cgi_stdout, 0); // Need an exec-point for variable creation. MCExecPoint ep; // Construct the _SERVER variable /* UNCHECKED */ MCVariable::createwithname_cstring("$_SERVER", s_cgi_server); s_cgi_server -> setnext(MCglobals); MCglobals = s_cgi_server; for(uint32_t i = 0; environ[i] != NULL; i++) { static const char *s_cgi_vars[] = { "GATEWAY_INTERFACE=", "SERVER_ADDR=", "SERVER_NAME=", "SERVER_SOFTWARE=", "SERVER_PROTOCOL=", "REQUEST_METHOD=", "REQUEST_TIME=", "QUERY_STRING=", "DOCUMENT_ROOT=", "HTTPS=", // MW-2009-08-12: For some reason I missed this first time around :o) "REMOTE_USER="******"REMOTE_ADDR=", "REMOTE_HOST=", "REMOTE_PORT=", // MM-2011-09-08: Added as part of customer support request for REMOTE_USER. // The standard Apache LiveCode server config redirects the script to the server engine. // This appears to mean that REMOTE_USER is never set // (I guess it will only ever be set if the server engine itself is behind authentication) // but REDIRECT_REMOTE_USER is. "REDIRECT_REMOTE_USER="******"SERVER_ADMIN=", "SERVER_PORT=", "SERVER_SIGNATURE=", "PATH_TRANSLATED=", "REQUEST_URI=", "PATH_INFO=", "SCRIPT_NAME=", "SCRIPT_FILENAME=", "CONTENT_TYPE=", "CONTENT_LENGTH=", NULL }; bool t_found; t_found = false; if (strncasecmp(environ[i], "HTTP_", 5) == 0) t_found = true; else for(uint32_t j = 0; s_cgi_vars[j] != NULL && !t_found; j++) if (strncasecmp(environ[i], s_cgi_vars[j], strlen(s_cgi_vars[j])) == 0) t_found = true; if (t_found) { const char *t_value; t_value = strchr(environ[i], '='); if (t_value == NULL) { ep . clear(); t_value = environ[i] + strlen(environ[i]); } else ep . setsvalue(t_value + 1); s_cgi_server -> getvalue() . store_element(ep, MCString(environ[i], t_value - environ[i])); } } // Construct the GET variables by parsing the QUERY_STRING /* UNCHECKED */ MCDeferredVariable::createwithname_cstring("$_GET_RAW", cgi_compute_get_raw_var, nil, s_cgi_get_raw); s_cgi_get_raw -> setnext(MCglobals); MCglobals = s_cgi_get_raw; /* UNCHECKED */ MCDeferredVariable::createwithname_cstring("$_GET", cgi_compute_get_var, nil, s_cgi_get); s_cgi_get -> setnext(MCglobals); MCglobals = s_cgi_get; /* UNCHECKED */ MCDeferredVariable::createwithname_cstring("$_GET_BINARY", cgi_compute_get_binary_var, nil, s_cgi_get_binary); s_cgi_get_binary -> setnext(MCglobals); MCglobals = s_cgi_get_binary; // Construct the _POST variables by reading stdin. /* UNCHECKED */ MCDeferredVariable::createwithname_cstring("$_POST_RAW", cgi_compute_post_raw_var, nil, s_cgi_post_raw); s_cgi_post_raw -> setnext(MCglobals); MCglobals = s_cgi_post_raw; /* UNCHECKED */ MCDeferredVariable::createwithname_cstring("$_POST", cgi_compute_post_var, nil, s_cgi_post); s_cgi_post -> setnext(MCglobals); MCglobals = s_cgi_post; /* UNCHECKED */ MCDeferredVariable::createwithname_cstring("$_POST_BINARY", cgi_compute_post_binary_var, nil, s_cgi_post_binary); s_cgi_post_binary -> setnext(MCglobals); MCglobals = s_cgi_post_binary; // Construct the FILES variable by reading stdin /* UNCHECKED */ MCDeferredVariable::createwithname_cstring("$_FILES", cgi_compute_files_var, nil, s_cgi_files); s_cgi_files -> setnext(MCglobals); MCglobals = s_cgi_files; // Construct the COOKIES variable by parsing HTTP_COOKIE /* UNCHECKED */ MCDeferredVariable::createwithname_cstring("$_COOKIE", cgi_compute_cookie_var, nil, s_cgi_cookie); s_cgi_cookie -> setnext(MCglobals); MCglobals = s_cgi_cookie; // Create the $_SESSION variable explicitly, to be populated upon calls to "start session" // required as implicit references to "$_SESSION" will result in its creation as an env var MCVariable *t_session_var = NULL; /* UNCHECKED */ MCVariable::createwithname_cstring("$_SESSION", t_session_var); t_session_var->setnext(MCglobals); MCglobals = t_session_var; return true; }