REPLACE_STATIC void handle_lsp_request(struct mg_connection *conn, const char *path, struct file *filep) { void *p = NULL; lua_State *L = NULL; if (!mg_fopen(conn, path, "r", filep)) { send_http_error(conn, 404, "Not Found", "%s", "File not found"); } else if (filep->membuf == NULL && (p = mmap(NULL, filep->size, PROT_READ, MAP_PRIVATE, fileno(filep->fp), 0)) == MAP_FAILED) { send_http_error(conn, 500, http_500_error, "%s", "x"); } else if ((L = luaL_newstate()) == NULL) { send_http_error(conn, 500, http_500_error, "%s", "y"); } else { mg_printf(conn, "%s", "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\nConnection: close\r\n\r\n"); prepare_lua_environment(conn, L); conn->request_info.ev_data = L; call_user(conn, MG_INIT_LUA); lsp(conn, filep->membuf == NULL ? p : filep->membuf, filep->size, L); } if (L) lua_close(L); if (p) munmap(p, filep->size); mg_fclose(filep); }
static int handle_lsp_request(struct mg_connection *conn, const char *path, struct file *filep, struct lua_State *ls) { void *p = NULL; lua_State *L = NULL; FILE *fp = NULL; int error = 1; // We need both mg_stat to get file size, and mg_fopen to get fd if (!mg_stat(path, filep) || (fp = mg_fopen(path, "r")) == NULL) { lsp_send_err(conn, ls, "File [%s] not found", path); } else if ((p = mmap(NULL, (size_t) filep->size, PROT_READ, MAP_PRIVATE, fileno(fp), 0)) == MAP_FAILED) { lsp_send_err(conn, ls, "mmap(%s, %zu, %d): %s", path, (size_t) filep->size, fileno(fp), strerror(errno)); } else if ((L = ls != NULL ? ls : luaL_newstate()) == NULL) { send_http_error(conn, 500, http_500_error, "%s", "luaL_newstate failed"); } else { // We're not sending HTTP headers here, Lua page must do it. if (ls == NULL) { prepare_lua_environment(conn, L); } error = lsp(conn, path, p, filep->size, L); } if (L != NULL && ls == NULL) lua_close(L); if (p != NULL) munmap(p, filep->size); fclose(fp); return error; }
REPLACE_STATIC pid_t spawn_process(struct mg_connection *conn, const char *prog, char *envblk, char *envp[], int fd_stdin, int fd_stdout, const char *dir) { pid_t pid; const char *interp; envblk = NULL; // Unused if ((pid = fork()) == -1) { // Parent send_http_error(conn, 500, http_500_error, "fork(): %s", strerror(ERRNO)); } else if (pid == 0) { // Child if (chdir(dir) != 0) { cry(conn, "%s: chdir(%s): %s", __func__, dir, strerror(ERRNO)); } else if (dup2(fd_stdin, 0) == -1) { cry(conn, "%s: dup2(%d, 0): %s", __func__, fd_stdin, strerror(ERRNO)); } else if (dup2(fd_stdout, 1) == -1) { cry(conn, "%s: dup2(%d, 1): %s", __func__, fd_stdout, strerror(ERRNO)); } else { (void) dup2(fd_stdout, 2); (void) close(fd_stdin); (void) close(fd_stdout); // After exec, all signal handlers are restored to their default values, // with one exception of SIGCHLD. According to POSIX.1-2001 and Linux's // implementation, SIGCHLD's handler will leave unchanged after exec // if it was set to be ignored. Restore it to default action. signal(SIGCHLD, SIG_DFL); interp = conn->ctx->config[CGI_INTERPRETER]; if (interp == NULL) { (void) execle(prog, prog, NULL, envp); cry(conn, "%s: execle(%s): %s", __func__, prog, strerror(ERRNO)); } else { (void) execle(interp, interp, prog, NULL, envp); cry(conn, "%s: execle(%s %s): %s", __func__, interp, prog, strerror(ERRNO)); } } exit(EXIT_FAILURE); } // Parent. Close stdio descriptors (void) close(fd_stdin); (void) close(fd_stdout); return pid; }
static void lsp_send_err(struct mg_connection *conn, struct lua_State *L, const char *fmt, ...) { char buf[MG_BUF_LEN]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); if (L == NULL) { send_http_error(conn, 500, http_500_error, "%s", buf); } else { lua_pushstring(L, buf); lua_error(L); } }
/** * Public functions **/ void ezcfg_worker_process_upnp_http_new_connection(struct ezcfg_worker *worker) { int header_len, nread; char *buf; int buf_len; struct ezcfg *ezcfg; struct ezcfg_http *http; ASSERT(worker != NULL); http = (struct ezcfg_http *)ezcfg_worker_get_proto_data(worker); ASSERT(http != NULL); ezcfg = ezcfg_worker_get_ezcfg(worker); buf_len = EZCFG_HTTP_CHUNK_SIZE; buf = calloc(buf_len+1, sizeof(char)); /* +1 for \0 */ if (buf == NULL) { err(ezcfg, "not enough memory for processing http new connection\n"); return; } nread = 0; header_len = ezcfg_socket_read_http_header(ezcfg_worker_get_socket(worker), http, buf, buf_len, &nread); ASSERT(nread >= header_len); if (header_len <= 0) { err(ezcfg, "request error\n"); free(buf); return; /* Request is too large or format is not correct */ } /* 0-terminate the request: parse http request uses sscanf * !!! never, be careful not mangle the "\r\n\r\n" string!!! */ //buf[header_len - 1] = '\0'; ezcfg_http_set_state_request(http); if (ezcfg_http_parse_header(http, buf, header_len) == true) { unsigned short major, minor; char *p; major = ezcfg_http_get_version_major(http); minor = ezcfg_http_get_version_minor(http); if (major != 1 || minor != 1) { send_http_error(worker, 505, "HTTP version not supported", "%s", "Weird HTTP version"); goto exit; } p = ezcfg_socket_read_http_content(ezcfg_worker_get_socket(worker), http, buf, header_len, &buf_len, &nread); if (p == NULL) { send_http_error(worker, 400, "Bad Request", ""); goto exit; } buf = p; if (nread > header_len) { ezcfg_http_set_message_body(http, buf + header_len, nread - header_len); } ezcfg_worker_set_birth_time(worker, time(NULL)); handle_upnp_http_request(worker); } else { /* Do not put garbage in the access log */ send_http_error(worker, 400, "Bad Request", "Can not parse request: %.*s", nread, buf); } exit: /* release buf memory */ free(buf); }
static void handle_ssi_request(struct ezcfg_worker *worker) { struct ezcfg *ezcfg; struct ezcfg_http *http; struct ezcfg_master *master; struct ezcfg_nvram *nvram; struct ezcfg_ssi *ssi = NULL; char buf[1024]; char *request_uri; char *accept_language = NULL; size_t uri_len; char *msg = NULL; int msg_len; char *p; int len; time_t t; struct tm *tmp; ASSERT(worker != NULL); http = (struct ezcfg_http *)ezcfg_worker_get_proto_data(worker); ASSERT(http != NULL); ezcfg = ezcfg_worker_get_ezcfg(worker); master = ezcfg_worker_get_master(worker); nvram = ezcfg_master_get_nvram(master); /* HTTP header has been parsed */ p = ezcfg_http_get_header_value(http, EZCFG_HTTP_HEADER_ACCEPT_LANGUAGE); if (p != NULL) { accept_language = strdup(p); if (accept_language == NULL) goto func_exit; } ssi = ezcfg_ssi_new(ezcfg, nvram); if (ssi == NULL) { send_http_error(worker, 500, "Internal Server Error", "%s", "Not enough memory"); goto func_exit; } request_uri = ezcfg_http_get_request_uri(http); uri_len = strlen(request_uri); /* set default document root */ if (ezcfg_ssi_set_document_root(ssi, "/etc/ezcfg_upnpd") == false) { send_http_error(worker, 500, "Internal Server Error", "%s", "Not enough memory"); goto func_exit; } /* set file path */ uri_len = strlen(request_uri); if (uri_len+2 > sizeof(buf)) { send_http_error(worker, 505, "Bad Request", "%s", "File name is too large"); goto func_exit; } snprintf(buf, sizeof(buf), "%s", *request_uri == '/' ? "" : "/"); url_decode(request_uri, uri_len, buf+strlen(buf), uri_len+1, 0); remove_double_dots_and_double_slashes(buf); if (ezcfg_ssi_set_path(ssi, buf) == false) { send_http_error(worker, 500, "Internal Server Error", "%s", "Not enough memory"); goto func_exit; } if (ezcfg_ssi_open_file(ssi, "r") == NULL) { send_http_error(worker, 500, "Internal Server Error", "%s", "Cannot open file"); goto func_exit; } if (ezcfg_http_handle_ssi_request(http, nvram, ssi) < 0) { send_http_bad_request(worker); goto func_exit; } else { /* process SSI file */ msg_len = 0; msg = NULL; len = ezcfg_ssi_file_get_line(ssi, buf, sizeof(buf)); while(len >= 0) { if (len > 0) { p = realloc(msg, msg_len+len); if (p == NULL) { goto func_exit; } msg = p; p += msg_len; strncpy(p, buf, len); msg_len += len; } len = ezcfg_ssi_file_get_line(ssi, buf, sizeof(buf)); } p = ezcfg_http_set_message_body(http, msg, msg_len); if (p == NULL) { goto func_exit; } /* clean msg */ free(msg); msg = NULL; /* build HTTP response */ /* HTTP header Content-Language */ if (accept_language != NULL) { if (ezcfg_http_add_header(http, EZCFG_HTTP_HEADER_CONTENT_LANGUAGE, accept_language) == false) { err(ezcfg, "HTTP add header error.\n"); goto func_exit; } } /* HTTP header Content-Length */ snprintf(buf, sizeof(buf), "%d", msg_len); if (ezcfg_http_add_header(http, EZCFG_HTTP_HEADER_CONTENT_LENGTH, buf) == false) { err(ezcfg, "HTTP add header error.\n"); goto func_exit; } /* HTTP header Content-Type */ snprintf(buf, sizeof(buf), "%s; %s=%s", EZCFG_HTTP_MIME_TEXT_XML, EZCFG_HTTP_CHARSET_NAME, EZCFG_HTTP_CHARSET_UTF8); if (ezcfg_http_add_header(http, EZCFG_HTTP_HEADER_CONTENT_TYPE, buf) == false) { err(ezcfg, "HTTP add header error.\n"); goto func_exit; } /* HTTP header Date */ /* Date: Thu, 01 Jan 1970 00:00:45 GMT */ t = time(NULL); tmp = localtime(&t); if (tmp == NULL) { err(ezcfg, "localtime error.\n"); goto func_exit; } if (strftime(buf, sizeof(buf), "%a, %d %b %Y %T GMT", tmp) == 0) { err(ezcfg, "strftime returned 0\n"); goto func_exit; } if (ezcfg_http_add_header(http, EZCFG_HTTP_HEADER_DATE, buf) == false) { err(ezcfg, "HTTP add header error.\n"); goto func_exit; } msg_len = ezcfg_http_get_message_length(http); if (msg_len < 0) { err(ezcfg, "ezcfg_http_get_message_length error.\n"); goto func_exit; } msg_len++; /* one more for '\0' */ msg = (char *)malloc(msg_len); if (msg == NULL) { err(ezcfg, "malloc msg error.\n"); goto func_exit; } memset(msg, 0, msg_len); msg_len = ezcfg_http_write_message(http, msg, msg_len); ezcfg_worker_write(worker, msg, msg_len); goto func_exit; } func_exit: if (accept_language != NULL) free(accept_language); if (msg != NULL) free(msg); if (ssi != NULL) ezcfg_ssi_delete(ssi); }
// 8. LOAD_CONFIG_FILE // test: HTTP://192.168.1.155/cgi-bin/Flash2AppREMOTEM_load_config_file.cgi?path=/upload/input.xml static void proc_cmd_load_config_file(struct mg_connection* conn, const struct mg_request_info* request_info) { char configXmlPath[200]; char inputXmlPath[200]; char str_file_path[200]; char *address = 0, *netmask = 0, *gateway = 0; int dhcp = 0; char* broadcast_xml_field; char*rec_pre_xml_field; int found = 0; int isNetUpdate = 0; get_qsvar(request_info, "path", str_file_path, sizeof(str_file_path)); if (strlen(str_file_path) == 0) { mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\nerrno=%d\r\n", INPUT_PARAM_NOT_SPECIFIED); return; } sprintf(inputXmlPath, "%s%s", ODI_HOME, str_file_path); sprintf(configXmlPath, "%s", ODI_CONFIG_XML); logger_remotem("load_config_file: merge XML Config File: from %s to %s", inputXmlPath, ODI_CONFIG_XML); struct my_file xmlfile = MY_STRUCT_FILE_INITIALIZER; if (!my_file_stat(inputXmlPath, &xmlfile)) { logger_remotem("No Input Config file to Load %s", inputXmlPath); send_http_error(conn, 404, "No Input Config file to Load ", "%s not found", inputXmlPath); goto leave; } if (!my_file_stat(ODI_CONFIG_XML, &xmlfile)) { logger_remotem("No destination Config file to Merge %s", ODI_CONFIG_XML); send_http_error(conn, 404, "No original config file to compare for merge ", "%s not found", ODI_CONFIG_XML); goto leave; } // read network file logger_remotem("Start merge XML Config File: %s", inputXmlPath); xmlDocPtr inputXmlDocumentPointer = xmlParseFile(inputXmlPath); if (inputXmlDocumentPointer == 0) { logger_remotem("LOAD_CONFIG_FILE: input XML not well formed %s", inputXmlPath); mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\nInputXML file is not well-formed.\r\n"); return; } xmlDocPtr configXmlDocumentPointer = xmlParseFile(ODI_CONFIG_XML); if (configXmlDocumentPointer == 0) { logger_remotem("LOAD_CONFIG_FILE: config XML not well formed %s", ODI_CONFIG_XML); mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\nConfiguration XML file is not well-formed.\r\n"); return; } // doc check xmlNodePtr cur = xmlDocGetRootElement(inputXmlDocumentPointer); if (cur == NULL) { logger_remotem("LOAD_CONFIG_FILE: input XML is empty"); xmlFreeDoc(configXmlDocumentPointer); xmlFreeDoc(inputXmlDocumentPointer); goto leave; } // config-meta check if (xmlStrcmp(cur->name, (const xmlChar*)"config-metadata")) { logger_remotem("LOAD_CONFIG_FILE: config-metadata tag not found"); xmlFreeDoc(configXmlDocumentPointer); xmlFreeDoc(inputXmlDocumentPointer); goto leave; } xmlNodePtr destParent = xmlDocGetRootElement(configXmlDocumentPointer); //node not found if (destParent == NULL) { logger_remotem("LOAD_CONFIG_FILE: empty doc"); xmlFreeDoc(configXmlDocumentPointer); xmlFreeDoc(inputXmlDocumentPointer); goto leave; } if (xmlStrcmp(destParent->name, (const xmlChar*)"config-metadata")) { logger_remotem("LOAD_CONFIG_FILE: root node != config-metadata"); xmlFreeDoc(configXmlDocumentPointer); xmlFreeDoc(inputXmlDocumentPointer); goto leave; } destParent = destParent->xmlChildrenNode; while (destParent) { if ((!xmlStrcmp(destParent->name, (const xmlChar*)"config"))) { found = 1; //Parse child content for field that need reboot xmlNodePtr info = destParent->xmlChildrenNode; while (info != NULL) { if (!xmlStrcmp(info->name, (const xmlChar*)"remotem_broadcast_ip")) { // logger_info("Tag 1: %s", info->name); // logger_info("Content: %s", (char *)xmlNodeGetContent(info)); broadcast_xml_field = (char*)xmlNodeGetContent(info); } else if (!xmlStrcmp(info->name, (const xmlChar *) "rec_pre")) { // logger_info("Tag 2: %s", info->name); // logger_info("Content: %s", (char *)xmlNodeGetContent(info)); rec_pre_xml_field = (char*)xmlNodeGetContent(info); } info = info->next; } break; } destParent = destParent->next; } if (!found) { logger_remotem("LOAD_CONFIG_FILE: config tag not found in %s", configXmlPath); xmlFreeDoc(configXmlDocumentPointer); xmlFreeDoc(inputXmlDocumentPointer); goto leave; } cur = cur->xmlChildrenNode; xmlNodePtr child = NULL; char *new_date = 0, *new_time = 0, *new_tz = 0; char str_comm[200]; unsigned int config_change_reboot = 0; while (cur != NULL) { if ((!xmlStrcmp(cur->name, (const xmlChar*)"config"))) { child = cur->xmlChildrenNode; while (child != NULL) { if (!(xmlStrcmp(child->name, (const xmlChar*)"text"))) { ; } else if (!(xmlStrcmp(child->name, (const xmlChar*)"dvr_id"))) { // cannot change DVR ID ; } else if (!(xmlStrcmp(child->name, (const xmlChar*)"dts_date"))) { new_date = (char*)xmlNodeGetContent(child); if (strlen(new_date) == 10) // Check for valid date { logger_remotem("LOAD_CONFIG_FILE: setting date %s", new_date); modifytree(&destParent, child); } } else if (!(xmlStrcmp(child->name, (const xmlChar*)"dts_time"))) { new_time = (char*)xmlNodeGetContent(child); if (strlen(new_time) == 8) // Check for valid time { logger_remotem("LOAD_CONFIG_FILE: setting time %s", new_time); modifytree(&destParent, child); } } else if (!(xmlStrcmp(child->name, (const xmlChar*)"dvr_name"))) { char* str = (char*)xmlNodeGetContent(child); if (strlen(str) > 1) { logger_remotem("LOAD_CONFIG_FILE: setting dvr_name %s", str); modifytree(&destParent, child); set_dvr_name(str); } } else if (!(xmlStrcmp(child->name, (const xmlChar*)"ops_carnum"))) { char* str = (char*)xmlNodeGetContent(child); if (strlen(str) > 1) // Check for valid time { logger_remotem("LOAD_CONFIG_FILE: setting ops_carnum %s", str); modifytree(&destParent, child); set_dvr_name(str); } } else if (!(xmlStrcmp(child->name, (const xmlChar*)"usb_login"))) { char* str = (char*)xmlNodeGetContent(child); if (strlen(str) > 1) // Check for valid time { logger_remotem("LOAD_CONFIG_FILE: setting usb_login %s", str); modifytree(&destParent, child); set_assignable(str); } } else if (!(xmlStrcmp(child->name, (const xmlChar*)"dts_tz"))) { new_tz = (char*)xmlNodeGetContent(child); modifytree(&destParent, child); char ptr[strlen(new_tz) + 1]; int i, j = 0; for (i = 0; new_tz[i] != ' '; i++) { // skip till space } i++; // move up from the space for (i; new_tz[i] != '\0'; i++) { ptr[j++] = new_tz[i]; } ptr[j] = '\0'; memset(str_comm, 0, 200); sprintf(str_comm, "export TZ=%s", ptr); system(str_comm); } else if (!(xmlStrcmp(child->name, (const xmlChar*)"eth_dhcp"))) { isNetUpdate = 1; if (!(xmlStrcmp((const xmlChar*)xmlNodeGetContent(child), (const xmlChar*)"true"))) { dhcp = 1; logger_remotem("LOAD_CONFIG_FILE: change to DHCP"); } else { dhcp = 0; logger_remotem("LOAD_CONFIG_FILE: DHCP is static"); } modifytree(&destParent, child); } else if (!(xmlStrcmp(child->name, (const xmlChar*)"eth_addr"))) { address = (char *)xmlNodeGetContent(child); if (address != NULL && strlen(address) > 7) { isNetUpdate = 1; modifytree(&destParent, child); } } else if (!(xmlStrcmp(child->name, (const xmlChar*)"eth_mask"))) { netmask = (char*)xmlNodeGetContent(child); if (netmask != NULL && strlen(netmask) > 7) { isNetUpdate = 1; modifytree(&destParent, child); } } else if (!(xmlStrcmp(child->name, (const xmlChar*)"eth_gate"))) { gateway = (char*)xmlNodeGetContent(child); if (gateway != NULL && strlen(gateway) > 7) { isNetUpdate = 1; modifytree(&destParent, child); } // Set flag for config update item need to reboot to apply change } else if (!(xmlStrcmp(child->name, (const xmlChar*)"remotem_broadcast_ip"))) { logger_info("New: %s Old: %s", xmlNodeGetContent(child), broadcast_xml_field); if (strcmp((char*)xmlNodeGetContent(child), broadcast_xml_field)) { config_change_reboot = 1; } modifytree(&destParent, child); } else if (!(xmlStrcmp(child->name, (const xmlChar*)"rec_pre"))) { if (rec_pre_xml_field == NULL) { config_change_reboot = 1; } else if (strcmp((char*)xmlNodeGetContent(child), rec_pre_xml_field)) { if (strncmp(get_hw_version(), "3", 1)) // Only update when >= v4.0 { config_change_reboot = 1; } } modifytree(&destParent, child); } else { if (modifytree(&destParent, child) == -1) { logger_remotem("LOAD_CONFIG_FILE: %s doesn't contain %s tag", configXmlPath, (char*)child->name); } } child = child->next; } } cur = cur->next; } // end while loop until NULL all elements processed if (new_date == NULL && new_time == NULL) { logger_remotem("%s: date and time are null", __FUNCTION__); } else { set_sys_clock(new_date, new_time); } mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\nerrno=0\r\n"); if (isNetUpdate) { update_network(dhcp, address, netmask, gateway); } logger_remotem("LOAD_CONFIG_FILE: saving new config, size=%d", xmlSaveFileEnc(configXmlPath, configXmlDocumentPointer, "UTF-8")); leave: if (inputXmlDocumentPointer) { xmlFreeDoc(inputXmlDocumentPointer); } if (configXmlDocumentPointer) { xmlFreeDoc(configXmlDocumentPointer); } if (config_change_reboot == 1) { logger_info("Config item change need system reboot"); // write_command_to_serial_port("RST\r\n"); // sleep(1); system("reboot"); } }
// 5. DELETE_FILE static void proc_cmd_delete_file(struct mg_connection* conn, const struct mg_request_info* request_info) { char str_file_path[200]; char str_full_path[200]; // Get file name from the request get_qsvar(request_info, "path", str_file_path, sizeof(str_file_path)); sprintf(str_full_path, "%s%s", ODI_HOME, str_file_path); char* str_file_name = basename(str_file_path); if (str_file_path == NULL || strlen(str_file_path) == 0 || (strlen(str_file_name) == 0)) { logger_remotem("DELETE_FILE: path variable is null."); mg_printf(conn, "HTTP/1.0 200 OK\r\n" "Content-Type: text/plain;charset=iso-8859-1\r\n\r\n" "errno=%d\r\n", INPUT_PARAM_NOT_SPECIFIED); return; } if (my_str_cmp(str_file_path, CONF_DIRECTORY) == 0 || my_str_cmp(str_file_path, LOG_DIRECTORY) == 0 || is_valid_file_path(str_full_path) == 0) { // error : : Input parameter not specified. logger_remotem("DELETE_FILE: invalid file path %s.", str_file_path); mg_printf(conn, "HTTP/1.0 200 OK\r\n" "Content-Type: text/plain;charset=iso-8859-1\r\n\r\n" "errno=%d\r\n", FILE_NOT_ALLOWED_DELETE); return; } struct my_file file = MY_STRUCT_FILE_INITIALIZER; if (!my_file_stat(str_full_path, &file)) { logger_remotem("DELETE_FILE: File not found %s.", str_full_path); send_http_error(conn, 404, "Not Found", "%s", "File not found"); return; } else if (!file.modification_time) { logger_remotem("DELETE_FILE: IO error %s, errno %s", str_full_path, strerror(errno)); send_http_error(conn, 500, http_500_error, "remove(%s): %s", str_file_path, strerror(errno)); return; } else if (remove(str_full_path) != 0) { logger_remotem("DELETE_FILE: File Locked %s, errno %s", str_full_path, strerror(errno)); send_http_error(conn, 423, "Locked", "remove(%s): %s", str_file_path, strerror(errno)); return; } mg_printf(conn, "HTTP/1.0 200 OK\r\n\r\nerrno=0\r\n"); logger_remotem("DELETE_FILE: SUCCESS path %s", str_file_path); system("sync;sync"); }