#include "lwip/arch.h" #include "lwip/api.h" #include "lwip/tcp.h" #include "common_config.h" #ifdef HTTP_SERVER_ENABLE #include "http_server.h" #include "web_params_api.h" #include "parameters.h" #include "urlcode.h" #ifdef HARDWARE_BT6707 #include "bt6707_fs/fsdata.c" #elif HARDWARE_BT6709 #include "bt6709_fs/fsdata.c" #elif HARDWARE_BT6709_MTS #include "bt6709_mts_fs/fsdata.c" #elif HARDWARE_BT6710 #include "bt6710_fs/fsdata.c" #elif HARDWARE_BT6711 || HARDWARE_BT6711_V1 #include "bt6711_fs/fsdata.c" #elif HARDWARE_BT6721 #include "bt6721_fs/fsdata.c" #endif #ifdef FTP_ENABLE #include "ftp.h" #endif // FTP_ENABLE #include "settings_api.h" #include "netconf.h" #include "testing.h" #include "rtc.h" #include "rng.h" #include "megatec.h" #include "log.h" #include "hal.h" #include "sntp_api.h" #ifdef RADIUS_SERVER_ENABLE #include "radius_user.h" #endif #ifdef PRINTF_STDLIB #include #endif #ifdef PRINTF_CUSTOM #include "tinystdio.h" #endif #include #include #include "FreeRTOS.h" #include "task.h" #include "fr_timers.h" static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err); static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); static int fs_open(char *name, struct fs_file *file); static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len); static err_t http_sent_history(void *arg, struct tcp_pcb *pcb, u16_t len); static err_t http_sent_log(void *arg, struct tcp_pcb *pcb, u16_t len); static void http_err(void *arg, err_t err); static void http_sent_log_err(void *arg, err_t err); static void send_data(struct tcp_pcb *pcb, struct http_state *hs); #ifdef HTTP_AUTH_ENABLE static void HTTP_GetUserCookie(uint8_t user_id, char *str, uint8_t *len); static void HTTP_SetUserCookie(char *str, uint8_t user_id); static void HTTP_UpdateUserLoginTime(uint8_t user_id); static void HTTP_ForceUserLogout(uint8_t user_id); void LogoutTimerCallback(TimerHandle_t pxTimer); void LoginTimerCallback(TimerHandle_t pxTimer); static void getAuthenticatedState(void); #endif static uint32_t Parse_Content_Length(char *data, uint32_t len); char *send_file(char *filename, char *pnonmatch, struct fs_file *file, uint16_t *Len); static uint32_t Parse_Header(char *data, uint32_t len, const char *field, uint32_t flen, char *value); bool GetFileName(char *inStr, char *fileName, uint8_t *fileNameLen); static char *HTTP_FTPFWUpdate(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut); static char *HTTP_FTPFWState(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut); #define NUM_LOCKS 3 static void *locks[NUM_LOCKS]; char sendBuf[SEND_BUF_MAX_LEN]; uint16_t sendBufLoadLen = 0; uint16_t printLen = 0; char receiveBuf[RECIVE_BUF_MAX_LEN]; uint16_t receivedBufLen = 0; #ifdef HTTP_AUTH_ENABLE #define MAX_POST_REQ_LEN 256 char post_req_data[MAX_POST_REQ_LEN]; uint32_t post_data_count = 0; uint32_t log_post_reqn; /* Logout timeout, 30 minutes */ #define WEB_LOGOUT_TIME configTICK_RATE_HZ*60*30 /* Max user active sessions count */ #define WEB_USER_MAX_SESSION_COUNT 5 struct { //auth_session_t session[WEB_USER_MAX_SESSION_COUNT]; char cookie[MAX_WEB_COOKIE_LEN]; TimerHandle_t LogoutTimer; } users[MAX_WEB_USERS]; TimerHandle_t RepeatLoginTimer; /* Repeat Login timeout, 1 minutes */ #define REPEAT_LOGIN_TIME configTICK_RATE_HZ*60*1 uint8_t cnt_err_psw = 0; bool Authenticated = false; uint8_t user_id = 0; // Id of currently logged-in user /* Level of currently logged-in user */ uint8_t seclevel = 0xFF; #endif /* Max HTTP file name length including "/" */ #define MAX_FILENAME_LEN 32 /* Max HTTP Etag field length */ #define MAX_ETAG_LEN 48 static const char If_None_Match[] = "If-None-Match: "; static const char Etag[] = "ETag: "; static volatile uint32_t DataFlag2 = 0; static volatile uint32_t DataFlag = 0; static volatile uint32_t size = 0; static uint32_t TotalReceived = 0; static volatile uint32_t TotalData = 0; static uint32_t ContentLengthOffset = 0; static const char Content_Length[17] = /* Content Length */ {0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x2d, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x3a, 0x20, }; const char HTTP_304_NOT_MODIFIED[] = "HTTP/1.1 304 Not Modified\r\n\r\n"; const char HTTP_401_NO_AUTH[] = "HTTP/1.1 401 No authorization\r\n\r\n"; const char HTTP_403_NOT_WHITE_LIST[] = "HTTP/1.1 403 Forbidden\r\n\r\n"; const char HTTP_500_SERVER_ERROR[] = "HTTP/1.1 500 Internal Server Error\r\n\r\n"; const char HTTP_200_OK[] = "HTTP/1.1 200 OK\r\n\r\n"; /* utf-8 marker to support MS Excel */ const char UTF8_BOM[] = {0xEF, 0xBB, 0xBF, 0x00}; const char REFRESH_LOGIN_PAGE[] = "\r\n"; const char REFRESH_RS_LOGIN_PAGE[] = "\r\n"; unsigned long log_ptr = 0; unsigned long log_size = 0; bool fLogTransInprog = false; #ifdef RADIUS_SERVER_ENABLE void auth_task(void *pvParameters); static bool fl_raddius_net_err = false; typedef enum { RS_AUTH_READY = 0, RS_AUTH_PROCESS, RS_AUTH_FINISH, MAX_RS_AUTH_STATE } rs_auth_state_t; static uint8_t auth_flag = RS_AUTH_READY; static char sendAuthBuf[500]; #endif /** * @brief Общая структура настроек */ extern SETTINGS_t sSettings; struct fs_file file = {0, 0}; typedef struct { char client_req[30]; uint8_t len; REQ_TYPE_SEND_t req_type_send; ACCESS_TYPE_t accsess; char *(*handler)(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut); } web_func_handler_t; #define X(x) (x), sizeof(x) - 1 // TODO Xify all the list like ftp_fw_update! web_func_handler_t process_web_funcs[] = { #ifdef HTTP_AUTH_ENABLE { "POST /login.cgi", 15, COMMON_ANSWER, ALL_ACCESS, HTTP_LoginPage }, { "GET /logout.cgi", 15, COMMON_ANSWER, TIME_ACCESS, HTTP_LogoutPage }, { "GET /changepwd.cgi", 18, COMMON_ANSWER, TIME_ACCESS, HTTP_ChangeUserPwd }, #endif { "GET /getJson.cgi", 16, COMMON_ANSWER, TIME_ACCESS, HTTP_GetParamsPage }, { "GET /settings.cgi", 17, COMMON_ANSWER, TIME_ACCESS, HTTP_GetSettingsPage }, { "POST /settings.cgi", 18, COMMON_ANSWER, TIME_ACCESS, HTTP_SetSettingsPage }, #ifdef NOTIFICATION_CONTROL_ENABLE { "GET /snmp.cgi", 13, COMMON_ANSWER, TIME_ACCESS, HTTP_SnmpParam }, #endif { "GET /info.cgi", 13, COMMON_ANSWER, TIME_ACCESS, HTTP_GetInfo }, { "POST /info.cgi", 14, COMMON_ANSWER, TIME_ACCESS, HTTP_SetInfoPage }, { "GET /history.cgi?page=all", 25, HISTORY_ANSWER, TIME_ACCESS, HTTP_HistoryPage }, { "GET /history.cgi", 16, COMMON_ANSWER, TIME_ACCESS, HTTP_HistoryPage }, { "GET /ups_history.cgi?page=all", 29, UPS_HISTORY_ANSWER, TIME_ACCESS, HTTP_UpsHistoryPage }, { "GET /ups_history.cgi", 20, COMMON_ANSWER, TIME_ACCESS, HTTP_UpsHistoryPage }, { "GET /reset.cgi", 14, COMMON_ANSWER, TIME_ACCESS, HTTP_Reset }, { "GET /bat_test.cgi", 17, COMMON_ANSWER, TIME_ACCESS, HTTP_UPSTest }, { "GET /ups_power.cgi", 18, COMMON_ANSWER, TIME_ACCESS, HTTP_UPSshutdown }, { "GET /reboot.cgi", 15, COMMON_ANSWER, TIME_ACCESS, HTTP_Reboot }, { "GET /confirm.cgi", 16, COMMON_ANSWER, TIME_ACCESS, HTTP_Confirm }, { "GET /fw_update.cgi", 18, COMMON_ANSWER, TIME_ACCESS, HTTP_ConfirmBootPwd }, #ifdef FTP_ENABLE { X("POST /ftp_fw_update.cgi"), COMMON_ANSWER, TIME_ACCESS, HTTP_FTPFWUpdate }, { X("GET /fw_dl_state.cgi"), COMMON_ANSWER, TIME_ACCESS, HTTP_FTPFWState }, #endif // FTP_ENABLE { "GET", 3, COMMON_ANSWER, ALL_ACCESS, HTTP_GetRequest }, { "", 0, COMMON_ANSWER, ALL_ACCESS, HTTP_NoFound }, { "", 0, 0, 0, NULL } }; #undef X static bool lock_buf(struct http_state *hs, void *buf) { /* Check if already locked */ for (uint8_t i = 0; i < NUM_LOCKS; i++) { if (locks[i] == buf) { DBG printf("[%p lock error]\r\n", buf); return false; } } /* Lock */ for (uint8_t i = 0; i < NUM_LOCKS; i++) { if (locks[i] == NULL) { locks[i] = buf; hs->locked = buf; DBG printf("[%p locked]\r\n", buf); return true; } } DBG printf("no free locks\r\n"); return false; } static bool unlock_buf(void *buf) { for (uint8_t i = 0; i < NUM_LOCKS; i++) { if (locks[i] == buf) { DBG printf("[%p unlocked]\r\n", buf); locks[i] = NULL; } } return true; } /** * @brief closes tcp connection * @param pcb: pointer to a tcp_pcb struct * @param hs: pointer to a http_state struct * @retval */ static void close_conn(struct tcp_pcb *pcb, struct http_state *hs) { tcp_arg(pcb, NULL); tcp_sent(pcb, NULL); tcp_recv(pcb, NULL); tcp_poll(pcb, NULL, 0); if (hs->locked != 0) { unlock_buf(hs->locked); } mem_free(hs); err_t err = tcp_close(pcb); DBG printf("%p close = %d (pcb: %d, pbuf_pool: %d)\r\n", pcb, err, lwip_stats.memp[MEMP_TCP_PCB]->used, lwip_stats.memp[MEMP_PBUF_POOL]->used); } /** * @brief callback function for handling TCP HTTP traffic * @param arg: pointer to an argument structure to be passed to callback function * @param pcb: pointer to a tcp_pcb structure * @param p: pointer to a packet buffer * @param err: LwIP error code * @retval err */ static err_t http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) { char *data; struct http_state *hs; web_func_handler_t *h; hs = arg; if (GetRebootStatus() == true) {; Reboot(WEB_ACT); } if (err == ERR_OK && p != NULL) { tcp_recved(pcb, p->tot_len); if (hs->file == NULL) { data = p->payload; receivedBufLen = p->tot_len; memcpy(receiveBuf, p->payload, receivedBufLen); /* Cut received string */ receiveBuf[receivedBufLen] = '\0'; if (strncmp(data, "GET /setProdate.cgi", 19) == 0 && strncmp(sSettings.sFlags.testState, "T2OK", 4)) { HTTP_Prodate(hs->reqnum, receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen); hs->file = sendBuf; hs->left = sendBufLoadLen; send_data(pcb, hs); tcp_sent(pcb, http_sent); } else { if (DataFlag2 >= 1) { hs->file = HTTP_SetSettingsPage(hs->reqnum, receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen); hs->left = sendBufLoadLen; send_data(pcb, hs); tcp_sent(pcb, http_sent); } else if (DataFlag >= 1) { hs->file = HTTP_SetInfoPage(hs->reqnum, receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen); hs->left = sendBufLoadLen; send_data(pcb, hs); tcp_sent(pcb, http_sent); } #ifdef HTTP_AUTH_ENABLE else if (log_post_reqn > 0 || post_data_count > 0) { hs->file = HTTP_LoginPage(hs->reqnum, receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen); hs->left = sendBufLoadLen; send_data(pcb, hs); tcp_sent(pcb, http_sent); } #endif else { #ifdef HTTP_AUTH_ENABLE getAuthenticatedState(); #endif for (h = &process_web_funcs[0]; h->handler; h++) { if (strncmp(data, h->client_req, h->len) == 0) { /* Skip common GET request (static files) - RAM buffers not used */ if (h->handler != HTTP_GetRequest) { if (!lock_buf(hs, sendBuf)) { DBG printf("Server is busy!\r\n"); /* TODO: Close connection or send error? */ #if 0 pbuf_free(p); close_conn(pcb, hs); return ERR_OK; #endif hs->file = (char *)HTTP_500_SERVER_ERROR; hs->left = strlen(HTTP_500_SERVER_ERROR); send_data(pcb, hs); tcp_sent(pcb, http_sent); pbuf_free(p); return ERR_OK; } } #ifdef HTTP_LOCK_ENABLE if (h->accsess == TIME_ACCESS) { uint32_t locked = 0; GetLockStateInt(&locked); if (locked) { hs->file = (char *)HTTP_403_FORBIDDEN; hs->left = strlen(HTTP_403_FORBIDDEN); send_data(pcb, hs); tcp_sent(pcb, http_sent); tcp_err(pcb, http_err); pbuf_free(p); return ERR_OK; } } #endif #ifdef HTTP_AUTH_ENABLE if (h->accsess == TIME_ACCESS && !Authenticated) { strcpy(sendBuf, HTTP_401_NO_AUTH); #ifdef RADIUS_SERVER_ENABLE if((sSettings.sRADIUS.RDSEnable == true) && (fl_raddius_net_err == false)) strcat(sendBuf, REFRESH_RS_LOGIN_PAGE); else #endif strcat(sendBuf, REFRESH_LOGIN_PAGE); sendBufLoadLen = strlen(sendBuf); hs->file = sendBuf; hs->left = sendBufLoadLen; send_data(pcb, hs); tcp_sent(pcb, http_sent); tcp_err(pcb, http_err); pbuf_free(p); return ERR_OK; } #endif hs->file = h->handler(hs->reqnum, receiveBuf, sendBuf, receivedBufLen, &sendBufLoadLen); hs->left = sendBufLoadLen; if (hs->file == 0) { unlock_buf(sendBuf); } if (hs->file != 0) { send_data(pcb, hs); switch (h->req_type_send) { case PARAMETER_ANSWER: //tcp_sent(pcb, http_sent_param_page); tcp_err(pcb, http_err); break; case HISTORY_ANSWER: tcp_sent(pcb, http_sent_history); tcp_err(pcb, http_sent_history); break; case UPS_HISTORY_ANSWER: tcp_sent(pcb, http_sent_log); tcp_err(pcb, http_sent_log_err); break; default: tcp_sent(pcb, http_sent); tcp_err(pcb, http_err); break; } } else if (DataFlag > 0 || DataFlag2 > 0 || log_post_reqn > 0 || post_data_count > 0) { /* Skip request without data (headers only were received) */ break; } else { close_conn(pcb, hs); } break; } } } } } pbuf_free(p); } return ERR_OK; } /** * @brief Sent callback for log file transfer (messages as is, not ordered) */ static err_t http_sent_history(void *arg, struct tcp_pcb *pcb, u16_t len) { struct http_state *hs; uint32_t nbytes = 0; static bool start = true; (void)len; hs = arg; if (hs->left > 0) { send_data(pcb, hs); } else { /* Release previously used send buffer to use * separate file transfer buffer (logFileBuf) */ if (hs->locked != 0) { unlock_buf(hs->locked); } memset(logFileBuf, 0, FILE_BUF_MAX_LEN); if (log_ptr + FILE_BUF_MAX_LEN <= log_size) { nbytes = History_GetData(log_ptr, logFileBuf, FILE_BUF_MAX_LEN, start); } else if (log_ptr < log_size) { nbytes = History_GetData(log_ptr, logFileBuf, (log_size - log_ptr), start); } else { nbytes = 0; } log_ptr += nbytes; start = false; if (nbytes == 0) { /* File transfer finished. */ start = true; close_conn(pcb, hs); /* Clear file transfer in progress flag */ fLogTransInprog = false; return ERR_OK; } hs->file = logFileBuf; hs->left = nbytes; send_data(pcb, hs); tcp_sent(pcb, http_sent_history); } return ERR_OK; } /** * @brief Sent callback for log file transfer (messages as is, not ordered) */ static err_t http_sent_log(void *arg, struct tcp_pcb *pcb, u16_t len) { struct http_state *hs; uint32_t nbytes = 0; static bool start = true; (void)len; hs = arg; if (hs->left > 0) { send_data(pcb, hs); } else { /* Release previously used send buffer to use * separate file transfer buffer (logFileBuf) */ if (hs->locked != 0) { unlock_buf(hs->locked); } memset(logFileBuf, 0, FILE_BUF_MAX_LEN); if (log_ptr + FILE_BUF_MAX_LEN_LOG <= log_size) { nbytes = LOG_GetData(log_ptr, logFileBuf, FILE_BUF_MAX_LEN_LOG, start); } else if (log_ptr < log_size) { nbytes = LOG_GetData(log_ptr, logFileBuf, (log_size - log_ptr), start); } else { nbytes = 0; } log_ptr += nbytes; start = false; if (nbytes == 0) { /* File transfer finished. */ start = true; close_conn(pcb, hs); /* Clear file transfer in progress flag */ fLogTransInprog = false; return ERR_OK; } hs->file = logFileBuf; hs->left = nbytes; send_data(pcb, hs); tcp_sent(pcb, http_sent_log); } return ERR_OK; } /** * @brief Error callback for log file transfer */ static void http_sent_log_err(void *arg, err_t err) { (void)err; (void)arg; /* Clear file transfer in progress flag */ fLogTransInprog = false; } /** * @brief callback function for handling connection errors * @param arg: pointer to an argument to be passed to callback function * @param err: LwIP error code * @retval none */ static void conn_err(void *arg, err_t err) { struct http_state *hs; (void)err; hs = arg; mem_free(hs); } /** * @brief callback function called after a successfull TCP data packet transmission * @param arg: pointer to an argument to be passed to callback function * @param pcb: pointer on tcp_pcb structure * @param len * @retval err : LwIP error code */ static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len) { struct http_state *hs; (void)len; hs = arg; if (hs->left > 0) { send_data(pcb, hs); } else { close_conn(pcb, hs); } return ERR_OK; } /** * @brief Error callback for common http transfer */ static void http_err(void *arg, err_t err) { struct http_state *hs; (void)err; (void)arg; hs = arg; DBG printf("http_err (%d): hs: %p\r\n", err, hs); if (hs->locked != 0) { unlock_buf(hs->locked); } mem_free(hs); } /** * @brief sends data found in member "file" of a http_state struct * @param pcb: pointer to a tcp_pcb struct * @param hs: pointer to a http_state struct * @retval none */ static void send_data(struct tcp_pcb *pcb, struct http_state *hs) { err_t err; u16_t len; /* We cannot send more data than space available in the send buffer */ if (tcp_sndbuf(pcb) < hs->left) { len = tcp_sndbuf(pcb); } else { len = hs->left; } err = tcp_write(pcb, hs->file, len, 0); if (err == ERR_OK) { hs->file += len; hs->left -= len; } } /** * @brief tcp poll callback function * @param arg: pointer to an argument to be passed to callback function * @param pcb: pointer on tcp_pcb structure * @retval err_t */ static err_t http_poll(void *arg, struct tcp_pcb *pcb) { if (arg == NULL) { tcp_close(pcb); } else { send_data(pcb, (struct http_state *)arg); } return ERR_OK; } /** * @brief callback function on TCP connection setup ( on port 80) * @param arg: pointer to an argument structure to be passed to callback function * @param pcb: pointer to a tcp_pcb structure * ¶m err: Lwip stack error code * @retval err */ static err_t http_accept(void *arg, struct tcp_pcb *pcb, err_t err) { struct http_state *hs; (void)arg; (void)err; /* set priority for the newly accepted tcp connection newpcb */ tcp_setprio(pcb, TCP_PRIO_MIN); /* Allocate memory for the structure that holds the state of the connection */ hs = mem_malloc(sizeof(struct http_state)); if (hs == NULL) { return ERR_MEM; } /* Initialize the structure. */ hs->file = NULL; hs->left = 0; hs->reqnum = 0; hs->locked = NULL; /* Tell TCP that this is the structure we wish to be passed for our callbacks. */ tcp_arg(pcb, hs); /* Tell TCP that we wish to be informed of incoming data by a call to the http_recv() function. */ tcp_recv(pcb, http_recv); tcp_err(pcb, conn_err); tcp_poll(pcb, http_poll, 10); return ERR_OK; } /** * @brief Opens a file defined in fsdata.c ROM filesystem * @param name : pointer to a file name * @param file : pointer to a fs_file structure * @retval 1 if success, 0 if fail */ static int fs_open(char *name, struct fs_file *file) { struct fsdata_file_noconst *f; for (f = (struct fsdata_file_noconst *)FS_ROOT; f != NULL; f = (struct fsdata_file_noconst *)f->next) { if (!strcmp(name, f->name)) { file->data = f->data; file->len = f->len; return 1; } } return 0; } /** * @brief Initialize the HTTP server (start its thread) * @param none * @retval None */ void HTTP_Init() { err_t err; struct tcp_pcb *pcb; #ifdef RADIUS_SERVER_ENABLE xTaskCreate(auth_task, "auth_task", 4 * configMINIMAL_STACK_SIZE, NULL, ( configMAX_PRIORITIES - 3), NULL); #endif /*create new pcb*/ pcb = tcp_new_ip_type(IPADDR_TYPE_ANY); LWIP_ASSERT("httpd_init: tcp_new failed", pcb != NULL); /* set lowest prio to HTTP connections */ //tcp_setprio(pcb, TCP_PRIO_MIN); /* bind HTTP traffic to pcb */ err = tcp_bind(pcb, IP_ANY_TYPE, 80); LWIP_UNUSED_ARG(err); /* in case of LWIP_NOASSERT */ LWIP_ASSERT("httpd_init: tcp_bind failed", err == ERR_OK); /* start listening on port 80 */ pcb = tcp_listen(pcb); /* define callback function for TCP connection setup */ tcp_accept(pcb, http_accept); #ifdef HTTP_AUTH_ENABLE char buf[MAX_WEB_COOKIE_LEN]; uint8_t user_id; for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) { /* Flush user cookie by random value */ sprintf(buf, "%X", (unsigned int)GetRandomNumber()); HTTP_SetUserCookie(buf, user_id); /* Create user logout timers */ users[user_id].LogoutTimer = xTimerCreate("LogoutTmr", WEB_LOGOUT_TIME, pdFALSE, ( void * ) user_id, LogoutTimerCallback); } RepeatLoginTimer = xTimerCreate("LoginTmr", REPEAT_LOGIN_TIME, pdFALSE, ( void * ) 0, LoginTimerCallback); #endif } char *HTTP_HistoryPage(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { uint8_t i, valueLen = 0; char value[20]; (void)lenBufIn; (void)reqNum; memset(bufOut, 0, FILE_BUF_MAX_LEN); ClearParamString(bufIn); memset(value, 0, 20); GetParamValue(bufIn, "page", value, &valueLen); if (strcmp(value, "all") == 0) { if (!LOG_IsInit()) { return 0; } if (fLogTransInprog == false) { // Send log as raw data log_ptr = 0; log_size = History_GetTotalSTRCount() * STRING_SIZE_HISTORY + sizeof(UTF8_BOM) - 1; sprintf(bufOut, "HTTP/1.1 200 OK\r\nContent-Length:%lu\r\n\r\n%s", log_size, UTF8_BOM); *lenBufOut = strlen(bufOut); // Set file transfer in progress flag fLogTransInprog = true; return bufOut; } else { // We send nothing if file transfer already in progress return 0; } } else { if (!LOG_IsInit()) { return 0; } else { HTTP_GetHistoryPage(bufOut, atoi(value)); *lenBufOut = strlen(bufOut); return bufOut; } } } char *HTTP_UpsHistoryPage(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { uint8_t i, valueLen = 0; char value[20]; (void)lenBufIn; (void)reqNum; memset(bufOut, 0, FILE_BUF_MAX_LEN); ClearParamString(bufIn); memset(value, 0, 20); GetParamValue(bufIn, "page", value, &valueLen); if (strcmp(value, "all") == 0) { if (!LOG_IsInit()) { return 0; } if (fLogTransInprog == false) { // Send log as raw data log_ptr = 0; log_size = LOG_GetTotalSTRCount() * STRING_SIZE + sizeof(UTF8_BOM) - 1; sprintf(bufOut, "HTTP/1.1 200 OK\r\nContent-Length:%lu\r\n\r\n%s", log_size, UTF8_BOM); *lenBufOut = strlen(bufOut); // Set file transfer in progress flag fLogTransInprog = true; return bufOut; } else { // We send nothing if file transfer already in progress return 0; } } else { if (!LOG_IsInit()) { return 0; } else { HTTP_GetUpsHistoryPage(bufOut, atoi(value)); *lenBufOut = strlen(bufOut); return bufOut; } } } /** * @brief Установка даты производства */ // TODO Убрать заглушку! void HTTP_Prodate(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { uint8_t valueLen = 0; char value[20]; (void)lenBufIn; (void)reqNum; memset(bufOut, 0, SEND_BUF_MAX_LEN); ClearParamString(bufIn); memset(value, 0, 20); GetParamValue(bufIn, "prodate", value, &valueLen); /* printf("Prodate: "); printf(value); printf("\r\n"); */ /* Устанавливаем дату производства */ SETTINGS_SetProDate(value, valueLen); /* Пока отправляем true */ strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type:text/html\r\n\r\nTrue"); *lenBufOut = strlen(bufOut); TEST_SetServerFlag(); } /** * @brief * @retval None */ char *HTTP_SetSettingsPage(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { char *DataOffset; (void)reqNum; if (seclevel == USER) { return 0; } DataOffset = 0; // POST Packet received if (DataFlag2 == 0) { TotalReceived = 0; memset(bufOut, 0, strlen(bufOut)); bufOut[0] = '0'; // parse packet for Content-length field size = Parse_Content_Length(bufIn, lenBufIn); DataOffset = strstr(bufIn, "managerIP"); // case of MSIE8 : we do not receive data in the POST packet if (DataOffset == 0) { DataFlag2++; return 0; } else { TotalReceived = lenBufIn - (DataOffset - bufIn); strncat(bufOut, DataOffset, TotalReceived); } } if (DataFlag2 == 0) { DataFlag2++; } else if (DataFlag2 == 1 && TotalReceived == 0) { /* parse packet for the octet-stream field */ DataOffset = strstr(bufIn, "managerIP"); TotalReceived += lenBufIn; strncat(bufOut, DataOffset, TotalReceived); DataFlag2++; } /* DataFlag >1 => the packet is data only */ else { TotalReceived += lenBufIn; strncat(bufOut, bufIn, lenBufIn); } // check if last data packet if (TotalReceived == size) { DBG printf("State: Received %u bytes\r\n", (unsigned int)TotalReceived); // printf("receive %s \r\n", sendBuf); strncat(bufOut, " ", 1); HTTP_SetSettings(bufOut, strlen(sendBuf)); memset(sendBuf, 0, size); DataFlag2 = 0; strcpy(bufOut, HTTP_200_OK); strcat(bufOut, "\r\n"); *lenBufOut = strlen(bufOut); return bufOut; } return 0; } /** * @brief * @retval None */ void HTTP_SetSettings(char *buf, uint16_t lenBuf) { uint8_t valueLen = 0; const uint8_t len = MAX_WEB_PARAM_LEN; char value[MAX_WEB_PARAM_LEN]; char str[MAX_WEB_PARAM_LEN]; (void)lenBuf; //printf(buf); //ClearParamString(buf); #define XJSON_SETTINGS_TAG(tag, get_param, set_param) JSON_SET_PARAM(tag, set_param, buf); WEB_SETTINGS_TAGS_TABLE #undef XJSON_SETTINGS_CREATE /* Если параметры WEB изменились выставляем флаг, сохраняем настройки и перезагружаемся */ if (GetStateWebReinit() == true) { SetWebReinitFlag(true); HTTP_SaveSettings(); /* Блокируем управление ключем на тау секунд*/ //IO_KeyBlockOn(); vTaskDelay(1010); Reboot(WEB_ACT); } HTTP_SaveSettings(); } #ifdef NOTIFICATION_CONTROL_ENABLE /** * @brief * @retval None */ char *HTTP_SnmpParam(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { char value[8]; uint8_t valueLen; char tempStr[50]; strncpy(tempStr, bufIn, 50); (void)reqNum; /* В запросе нет параметров, нужно формировать JSON ответ */ if (strstr(tempStr, "?_") == NULL) { memset(bufOut, 0, SEND_BUF_MAX_LEN); if (seclevel == USER) { return 0; } HTTP_SetNotification(bufIn, lenBufIn); } return HTTP_GetTrapAccess(bufIn, lenBufIn, bufOut, lenBufOut); } /** * @brief * @retval None */ void HTTP_SetNotification(char *buf, uint16_t lenBuf) { uint8_t num_notification, value_notification; const uint8_t len = 20; uint16_t len2 = 0, len3 = 0, total_len = 0; char str[20], value[20]; ClearParamString(buf); total_len = strcspn(buf, "?") + 1; lenBuf = strlen(buf); const uint16_t strend = strcspn(buf, "_"); while (total_len < (strend)) { memset(value, 0, len); len2 = strcspn(&buf[total_len], "&"); strncat(value, &buf[total_len], len2); memset(str, 0, len); len3 = strcspn(&value[0], "="); strncat(str, &value[0], (len3)); num_notification = atoi(str); memset(str, 0, len); strncat(str, &value[len3 + 1], (len2 - len3 - 1)); value_notification = atoi(str); SetNotificationFlagsStr(&value_notification, num_notification); total_len = total_len + strlen(value) + 1; } HTTP_SaveSettings(); } #endif /** * @brief * @retval None */ char *HTTP_SetInfoPage(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { char *DataOffset; (void)reqNum; if (seclevel == USER) { return 0; } DataOffset = 0; // POST Packet received if (DataFlag == 0) { TotalReceived = 0; memset(bufOut, 0, strlen(bufOut)); bufOut[0] = '0'; // parse packet for Content-length field size = Parse_Content_Length(bufIn, lenBufIn); DataOffset = strstr(bufIn, "sysname"); // case of MSIE8 : we do not receive data in the POST packet if (DataOffset == 0) { DataFlag++; return 0; } else { TotalReceived = lenBufIn - (DataOffset - bufIn); strncat(bufOut, DataOffset, TotalReceived); } } if (DataFlag == 0) { DataFlag++; } else if (DataFlag == 1 && TotalReceived == 0) { /* parse packet for the octet-stream field */ DataOffset = strstr(bufIn, "sysname"); TotalReceived += lenBufIn; strncat(bufOut, DataOffset, TotalReceived); DataFlag++; } /* DataFlag >1 => the packet is data only */ else { TotalReceived += lenBufIn; strncat(bufOut, bufIn, lenBufIn); } // check if last data packet if (TotalReceived == size) { strncat(bufOut, " ", 1); HTTP_SetInfo(bufOut, strlen(bufOut)); DataFlag = 0; memset(bufOut, 0, size); strcpy(bufOut, HTTP_200_OK); strcat(bufOut, "\r\n\r\n"); *lenBufOut = strlen(bufOut); return bufOut; } return 0; } /** * @brief * @retval None */ void HTTP_SetInfo(char *buf, uint16_t lenBuf) { uint8_t valueLen = 0; const uint8_t len = 110; char value[330]; char str[110]; (void)lenBuf; // ClearParamString(buf); memset(value, 0, len); /* Название устройства */ GetParamValue(buf, "sysname", value, &valueLen); url_decode(str, sizeof(str), value); SetNameDeviceStr(str); memset(value, 0, len); /* Владелец */ GetParamValue(buf, "owner", value, &valueLen); url_decode(str, sizeof(str), value); SetOwner(str); memset(value, 0, len); /* Владелец */ GetParamValue(buf, "sysLocation", value, &valueLen); url_decode(str, sizeof(str), value); SetLocation(str); memset(value, 0, len); /* Комментарий */ GetParamValue(buf, "comment", value, &valueLen); url_decode(str, sizeof(str), value); SetComment(str); memset(value, 0, len); HTTP_SaveSettings(); } char *HTTP_Reset(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { (void)bufIn; (void)bufOut; (void)lenBufIn; (void)reqNum; if (seclevel == USER) { return 0; } HTTP_ResetSettings(); HTTP_SaveSettings(); fs_open("/settings.html", &file); *lenBufOut = file.len; return file.data; } char *HTTP_Confirm(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { (void)bufIn; (void)bufOut; (void)lenBufIn; (void)reqNum; SetWebReinitFlag(false); SetConfirmWebParamsFlag(); fs_open("/index.html", &file); *lenBufOut = file.len; return file.data; } char *HTTP_GetRequest(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { (void)bufOut; (void)reqNum; #ifdef HTTP_AUTH_ENABLE const char *html_page_name[] = { "/main.css", "/rotek.png", "/favicon.ico", "/role.js" }; #endif char filename[MAX_FILENAME_LEN]; char nonmatch[MAX_ETAG_LEN]; char *pnonmatch = NULL; uint8_t len; memset(filename, 0, MAX_FILENAME_LEN); if (GetFileName(bufIn, filename, &len)) { /* Parce If-Non_Match value */ #ifdef HTTP_AUTH_ENABLE if (!Authenticated) { for (uint8_t i = 0; i < 4; i ++) { if (strcmp(filename, html_page_name[i]) == 0) { break; } #ifdef RADIUS_SERVER_ENABLE if (strcmp(filename, "/check_auth.html") == 0 && auth_flag != RS_AUTH_READY ) { if (auth_flag == RS_AUTH_FINISH){ auth_flag = RS_AUTH_READY; } else { strcpy(sendAuthBuf, "HTTP/1.0 200 OK\r\nContent-Type: text/html;\r\n\r\n"); strcat(sendAuthBuf, "

Ожидание соединения с RADIUS сервером

"); } sendBufLoadLen = strlen(sendAuthBuf); return sendAuthBuf; } #endif if (i == 3) { #ifdef RADIUS_SERVER_ENABLE if((sSettings.sRADIUS.RDSEnable == true) && (fl_raddius_net_err == false)) strcpy(filename, "/rslogin.html"); else #endif strcpy(filename, "/login.html"); } } } else { HTTP_UpdateUserLoginTime(user_id); } #endif uint8_t nonmatch_len = Parse_Header(bufIn, lenBufIn, lenBufIn, 15, nonmatch); if (nonmatch_len < MAX_ETAG_LEN && nonmatch_len > 0) { //DBG printf("If_None_Match: %s\r\n", nonmatch); pnonmatch = nonmatch; } return send_file(filename, pnonmatch, &file, lenBufOut); } return 0; } char *HTTP_NoFound(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { (void)bufIn; (void)lenBufIn; (void)reqNum; if (Authenticated) { #ifdef HTTP_AUTH_ENABLE HTTP_UpdateUserLoginTime(user_id); #endif fs_open("/index.html", &file); // + *lenBufOut = file.len; return file.data; } else { strcpy(bufOut, HTTP_401_NO_AUTH); #ifdef RADIUS_SERVER_ENABLE if((sSettings.sRADIUS.RDSEnable == true) && (fl_raddius_net_err == false)) strcat(bufOut, REFRESH_RS_LOGIN_PAGE); else #endif strcat(bufOut, REFRESH_LOGIN_PAGE); *lenBufOut = strlen(bufOut); return bufOut; } } /** * @brief Запуск/останов теста UPS */ char *HTTP_UPSTest(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { uint8_t valueLen = 0; char tempValue[20]; char tempValue2[20]; int8_t res = 0; char log_string[50]; (void)lenBufIn; (void)reqNum; if (seclevel == USER) { return 0; } memset(tempValue, 0, 20); memset(tempValue2, 0, 20); memset(log_string, 0, 50); strcpy(bufOut, HTTP_200_OK); GetParamValue(bufIn, "func", tempValue, &valueLen); if (strcmp(tempValue, "stop") == 0) { res = ups_metac_service_pdu(ups_cancel_test); if (res == 1 || res == 0) { strcat(bufOut, "Команда \"Останов теста\" принята ИБП!"); strcpy(log_string, name_login); strcat(log_string, " (Останов)"); log_event_data(LOG_TEST_UPS, log_string); } if (res == -1) { strcat(bufOut, "Команда \"Останов теста\" отклонена ИБП!"); } } else if (strcmp(tempValue, "discharge") == 0) { res = ups_metac_service_pdu(ups_test_low_bat); set_act_source(WEB_ACT); if (res == 1 || res == 0) { strcat(bufOut, "Команда \"Запуск теста\" принята ИБП!"); } if (res == -1) { strcat(bufOut, "Команда \"Запуск теста\" отклонена ИБП!"); } } else if (strncmp(tempValue, "time", 6) == 0) { GetParamValue(bufIn, "time", tempValue2, &valueLen); TimeParam = atoi(tempValue2); res = ups_metac_service_pdu(ups_test_time); if (res == 1 || res == 0) { strcat(bufOut, "Команда \"Запуск теста\" принята ИБП!"); } if (res == -1) { strcat(bufOut, "Команда \"Запуск теста\" отклонена ИБП!"); } } *lenBufOut = strlen(bufOut); return bufOut; } /** * @brief Выклюение UPS */ char *HTTP_UPSshutdown(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { uint8_t valueLen = 0; char *valueLenEnd = 0; char tempValue[50]; char tempValue2[50]; int8_t res = 0; char log_string[50]; (void)lenBufIn; (void)reqNum; if (seclevel == USER) { return 0; } memset(tempValue, 0, 50); memset(log_string, 0, 50); strcpy(bufOut, HTTP_200_OK); GetParamValue(bufIn, "func", tempValue, &valueLen); if (strcmp(tempValue, "reboot") == 0) { res = ups_metac_service_pdu(ups_cancel_shut_down); if (res == 1) { strcpy(log_string, name_login); strcat(log_string, " (Останов)"); log_event_data(LOG_SHUTDOWN_UPS, log_string); strcat(bufOut, "Команда \"Отмена выключения нагрузки\" принята ИБП!"); } else { strcat(bufOut, "Команда \"Отмена выключения нагрузки\" отклонена ИБП!"); } } else if (strncmp(tempValue, "off", 5) == 0) { memset(tempValue2, 0, 50); GetParamValue(bufIn, "after", tempValue2, &valueLen); TimeParamFloat = atof(tempValue2); res = ups_metac_service_pdu(ups_shutdown); if (res == 1) { strcat(bufOut, "Команда \"Отключения нагрузки\" принята ИБП!"); log_event_data(LOG_SHUTDOWN_UPS, name_login); } else { strcat(bufOut, "Команда \"Отключения нагрузки\" отклонена ИБП!"); } } *lenBufOut = strlen(bufOut); return bufOut; } /** * @brief Проверка пароля для перехода в режим bootloader * @retval None */ char *HTTP_ConfirmBootPwd(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { (void)bufIn; (void)lenBufIn; (void)reqNum; if (seclevel == USER) { return 0; } strcpy(bufOut, HTTP_200_OK); *lenBufOut = strlen(bufOut); /* Запускаем задачу отложенной перезагрузки. Контроллер должен успеть отправить ответ серверу о статусе пароля */ set_act_source(WEB_ACT); HTTP_StartResetTask(true); return bufOut; } #ifdef FTP_ENABLE // Download the firmware via FTP, put it on the SPI flash, verify it and reboot the controller static char *HTTP_FTPFWUpdate(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { (void)bufIn; (void)lenBufIn; (void)reqNum; // check the logged user's permission level if (seclevel == USER) { return 0; } FTP_Update_t *settings = &sSettings.sFTPUpdate; ftpcfg.settings = settings; char value[30]; // FIXME GetParamValue doesn't check for buffer overflow // ebalbekova told we don't need any verification against malicious actors GetParamValue0(bufIn, "ftp_server", value, NULL); if (!ipaddr_aton(value, &settings->server_ip)) { IP4_ADDR(&settings->server_ip, 192,168,0,253); } GetParamValue0(bufIn, "ftp_port", value, NULL); settings->server_port = atoi(value); settings->server_port = settings->server_port == 0 ? 21 : settings->server_port; GetParamValue0(bufIn, "ftp_path", settings->remote_path, NULL); GetParamValue0(bufIn, "ftp_login", settings->user, NULL); if (settings->user[0] == 0) { strcpy(settings->user, "anonymous"); } GetParamValue0(bufIn, "ftp_password", settings->pass, NULL); if (settings->pass[0] == 0) { strcpy(settings->pass, "guest"); } HTTP_SaveSettings(); start_ftp_client(&ftpcfg); strcpy(bufOut, HTTP_200_OK); *lenBufOut = strlen(bufOut); return bufOut; } static char *HTTP_FTPFWState(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { (void)bufIn; (void)lenBufIn; (void)reqNum; char *progress = get_ftp_progress(); *lenBufOut = sprintf(bufOut, "HTTP/1.1 200 OK\r\nContent-Type:text/plain\r\n\r\n%s", progress); return bufOut; } #endif // FTP_ENABLE #ifdef HTTP_AUTH_ENABLE void LoginTimerCallback(TimerHandle_t pxTimer) { cnt_err_psw = 0; DBG printf("cnt_err_psw %d", cnt_err_psw); xTimerStop(RepeatLoginTimer, 0); } #ifdef RADIUS_SERVER_ENABLE void auth_task(void *pvParameters) { for(;;){ if(auth_flag == RS_AUTH_PROCESS) { HTTP_RADIUSAuthConfirmWebPwd(post_req_data, sendAuthBuf, strlen(post_req_data), &sendBufLoadLen); auth_flag = RS_AUTH_FINISH; } vTaskDelay(40); } } /** * @brief Проверка пароля для входа в Web * @retval None */ int HTTP_RADIUSAuthConfirmWebPwd(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { char tempStr[52]; char login[20]; char password[20]; char tmp_password[33]; uint8_t valueLen, user_id; char *strPtr = 0; char WebPassword[MAX_WEB_PASSWD_LEN]; char WebLogin[MAX_WEB_LOGIN_LEN]; memset(login, 0, 20); memset(password, 0, 20); memset(tmp_password, 0, 33); memset(tempStr, 0, 52); memset(name_login, 0, 50); tempStr[0] = '0'; /* Get first 50 bytes of string */ strncat(tempStr, bufIn, 49); /* Add " " to the string in order GetParamValue() can be able to parse the param */ strcat(tempStr, " "); GetParamValue(tempStr, "login", login, &valueLen); GetParamValue(tempStr, "password", tmp_password, &valueLen); url_decode(password, sizeof(password), tmp_password); valueLen = strlen(password); switch (RC_Login(login, password)) { case RC_ERROR: Authenticated = false; break; case RC_LOGIN_ADMIN_OK: Authenticated = true; user_id = 0; break; case RC_LOGIN_USER_OK: Authenticated = true; user_id = 1; break; case RC_NET_ERR: Authenticated = false; fl_raddius_net_err = true; strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type: text/html;\r\n\r\n"); strcat(bufOut, "

Ошибка соединения с RADIUS сервером

"); *lenBufOut = strlen(bufOut); return SEND_REQUIRED_NO; break; case RC_ACC_DENIED: Authenticated = false; break; default: break; } snprintf(name_login, (strlen(login) + 1), login); if (Authenticated) { /* Generate cookie */ sprintf(tempStr, "%X", (unsigned int)GetRandomNumber()); /* Set users cookie */ HTTP_SetUserCookie(tempStr, user_id); HTTP_UpdateUserLoginTime(user_id); /* Send login and cookie back */ strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type:text/html\r\nSet-Cookie: uname="); strcat(bufOut, login); strcat(bufOut, "\r\nSet-Cookie: id="); strcat(bufOut, tempStr); sprintf(tempStr, "%d", (user_id + 1)); strcat(bufOut, "\r\nSet-Cookie: role="); strcat(bufOut, tempStr); strcat(bufOut, "\r\nSet-Cookie: auth=1"); strcat(bufOut, "\r\n\r\n"); strcat(bufOut, "\r\n\r\n"); *lenBufOut = strlen(bufOut); fl_raddius_net_err = false; log_event_data(LOG_LOGIN, name_login); /* Запускаем задачу-таймер логаута. */ /* TODO отправить ответ серверу о статусе пароля */ return SEND_REQUIRED_YES; } else { if (cnt_err_psw <= 4) { cnt_err_psw ++; } DBG printf("cnt_err_psw %d", cnt_err_psw); if (cnt_err_psw == 4) { xTimerStart(RepeatLoginTimer, 0); } strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type: text/html;\r\n\r\n"); if (cnt_err_psw < 4) { strcat(bufOut, "

Не правильный логин или пароль

"); } else { strcat(bufOut, "

Вход заблокирован!

Повторите попытку через 1 минуту

"); } *lenBufOut = strlen(bufOut); return SEND_REQUIRED_NO; } } #endif /** * @brief Проверка пароля для входа в Web * @retval None */ int HTTP_LocalAuthConfirmWebPwd(char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { char tempStr[52]; char login[20]; char password[20]; char tmp_password[33]; uint8_t valueLen, user_id; char *strPtr = 0; char WebPassword[MAX_WEB_PASSWD_LEN]; char WebLogin[MAX_WEB_LOGIN_LEN]; memset(login, 0, 20); memset(password, 0, 20); memset(tmp_password, 0, 33); memset(tempStr, 0, 52); memset(name_login, 0, 50); tempStr[0] = '0'; /* Get first 50 bytes of string */ strncat(tempStr, bufIn, 49); /* Add " " to the string in order GetParamValue() can be able to parse the param */ strcat(tempStr, " "); GetParamValue(tempStr, "login", login, &valueLen); GetParamValue(tempStr, "password", tmp_password, &valueLen); url_decode(password, sizeof(password), tmp_password); valueLen = strlen(password); for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) { GetUserLogin(user_id, WebLogin, &valueLen); GetUserPassword(user_id, WebPassword, &valueLen); /* Check login and password */ if ((strncmp(WebLogin, login, MAX_WEB_LOGIN_LEN) == 0) && (strncmp(WebPassword, password, MAX_WEB_PASSWD_LEN) == 0)) { /* Login and pass are valid */ /* TODO replace global flag with user-pass-cookie */ if (cnt_err_psw < 4) { cnt_err_psw = 0; Authenticated = true; switch (user_id) { case 0: snprintf(name_login, sizeof(name_login), "Администратор"); break; case 1: snprintf(name_login, sizeof(name_login), "Пользователь"); break; default: break; } } else { Authenticated = false; } break; } else { Authenticated = false; } } if (Authenticated) { /* Generate cookie */ sprintf(tempStr, "%X", (unsigned int)GetRandomNumber()); /* Set users cookie */ HTTP_SetUserCookie(tempStr, user_id); HTTP_UpdateUserLoginTime(user_id); /* Send login and cookie back */ strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type:text/html\r\nSet-Cookie: uname="); strcat(bufOut, login); strcat(bufOut, "\r\nSet-Cookie: id="); strcat(bufOut, tempStr); sprintf(tempStr, "%d", (user_id + 1)); strcat(bufOut, "\r\nSet-Cookie: role="); strcat(bufOut, tempStr); strcat(bufOut, "\r\nSet-Cookie: auth=1"); strcat(bufOut, "\r\n\r\n"); strcat(bufOut, "\r\n\r\n"); *lenBufOut = strlen(bufOut); #ifdef RADIUS_SERVER_ENABLE fl_raddius_net_err = false; #endif log_event_data(LOG_LOGIN, name_login); /* Запускаем задачу-таймер логаута. */ /* TODO отправить ответ серверу о статусе пароля */ return SEND_REQUIRED_YES; } else { if (cnt_err_psw <= 4) { cnt_err_psw ++; } DBG printf("cnt_err_psw %d", cnt_err_psw); if (cnt_err_psw == 4) { xTimerStart(RepeatLoginTimer, 0); } strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type: text/html;\r\n\r\n"); if (cnt_err_psw < 4) { strcat(bufOut, "

Не правильный логин или пароль

"); } else { strcat(bufOut, "

Вход заблокирован!

Повторите попытку через 1 минуту

"); } *lenBufOut = strlen(bufOut); return SEND_REQUIRED_NO; } } /** * @brief Чтение Cookie пользователя */ static void HTTP_GetUserCookie(uint8_t user_id, char *str, uint8_t *len) { sprintf(str, "%s", users[user_id].cookie); *len = strlen(str); } /** * @brief Установка Cookie пользователя */ static void HTTP_SetUserCookie(char *str, uint8_t user_id) { strcpy(users[user_id].cookie, str); } /** * @brief Обновление времени последней активности пользователя */ static void HTTP_UpdateUserLoginTime(uint8_t user_id) { xTimerStart(users[user_id].LogoutTimer, 0); } /** * @brief Принудительный логаут пользователя */ static void HTTP_ForceUserLogout(uint8_t user_id) { char cookie[MAX_WEB_COOKIE_LEN]; /* Flush user cookie by random value */ sprintf(cookie, "%X", (unsigned int)GetRandomNumber()); HTTP_SetUserCookie(cookie, user_id); } /** * @brief >Callback таймера логаута пользователя */ void LogoutTimerCallback(TimerHandle_t pxTimer) { uint8_t user_id = (uint8_t)pvTimerGetTimerID( pxTimer ); HTTP_ForceUserLogout(user_id); } /** * @brief Смена пароля пользователя * @retval None */ char *HTTP_ChangeUserPwd(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { char tempStr[110]; char value[20]; char login[20]; char password[20]; char tmp[75]; uint8_t valueLen, valueLen2, user_id; char WebLogin[MAX_WEB_LOGIN_LEN]; (void)reqNum; (void)lenBufIn; if (seclevel == USER) { return 0; } memset(login, 0, sizeof(login)); memset(password, 0, sizeof(password)); memset(tempStr, 0, sizeof(tempStr)); memset(value, 0, sizeof(value)); memset(tmp, 0, sizeof(tmp)); ClearParamString(bufIn); strncpy(tempStr, bufIn, 110); strcpy(bufOut, HTTP_200_OK); if (GetParamValue(tempStr, "username", login, &valueLen) && GetParamValue(tempStr, "oldpass", tmp, &valueLen)) { url_decode(password, sizeof(password), tmp); for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) { memset(value, 0, 20); memset(WebLogin, 0, MAX_WEB_LOGIN_LEN); GetUserLogin(user_id, WebLogin, &valueLen); GetUserPassword(user_id, value, &valueLen2); /* Check login and password */ if ((strncmp(WebLogin, login, MAX_WEB_LOGIN_LEN) == 0) && (memcmp(password, value, 11) == 0)) { memset(tmp, 0, sizeof(tmp)); memset(password, 0, 20); if (GetParamValue(tempStr, "newpass", tmp, &valueLen)) { url_decode(password, sizeof(password), tmp); valueLen = strlen(password); memcpy(sSettings.sAuth[user_id].password, password, sizeof(sSettings.sAuth[user_id].password)); HTTP_SaveSettings(); log_event_data(LOG_PSW_CHANGE, name_login); strcat(bufOut, "Пароль успешно изменён"); *lenBufOut = strlen(bufOut); return bufOut; } else { strcat(bufOut, "Введены некорректные данные!"); *lenBufOut = strlen(bufOut); return bufOut; } } } strcat(bufOut, "Введён неверный пароль!"); } else { strcat(bufOut, "Введены некорректные данные!"); } *lenBufOut = strlen(bufOut); return bufOut; } static void getAuthenticatedState(void) { char CookieBuf[51]; char *CookiePtr = NULL; char name[MAX_WEB_COOKIE_LEN]; char id[MAX_WEB_COOKIE_LEN]; uint8_t nameLen = 0, idLen = 0; receiveBuf[receivedBufLen] = '\0'; //printf("receive %s \r\n", receiveBuf); // Get cookie "uname" value memset(CookieBuf, 0, sizeof(CookieBuf)); CookiePtr = strstr(receiveBuf, "uname="); strncpy(CookieBuf, CookiePtr, 50); //printf("********CookieBuf1= %s\r\n", CookieBuf); memset(name, 0, MAX_WEB_COOKIE_LEN); GetCookieValue(CookieBuf, "uname=", name, &nameLen); //printf("********CookieBuf2= %s\r\n", CookieBuf); //printf("********uname= %s\r\n", name); memset(CookieBuf, 0, sizeof(CookieBuf)); // Get cookie "id" value CookiePtr = strstr(receiveBuf, " id="); strncpy(CookieBuf, CookiePtr, 50); //printf("********CookieBuf1= %s\r\n", CookieBuf); memset(id, 0, MAX_WEB_COOKIE_LEN); GetCookieValue(CookieBuf, "id=", id, &idLen); // printf("********ID= %s\r\n", id); seclevel = 0xFF; for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) { HTTP_GetUserCookie(user_id, CookieBuf, &idLen); if (strncmp(id, CookieBuf, idLen) == 0 ) { GetUserLevelInt(user_id, &seclevel); Authenticated = true; break; } Authenticated = false; seclevel = 0xFF; } } void HTTP_ConfirmWebPwd(char *bufIn, char *bufOut, char *postBuf, uint16_t lenBufIn, uint16_t *lenBufOut) { #ifdef RADIUS_SERVER_ENABLE static char rs_id[16]; if (auth_flag != RS_AUTH_READY) { strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type: text/html;\r\n\r\n"); char CookieBuf[51]; char *CookiePtr = NULL; char rs_id_check[MAX_WEB_COOKIE_LEN]; uint8_t rs_idLen = 0; CookiePtr = strstr(bufIn, "rs_id="); strncpy(CookieBuf, CookiePtr, 50); GetCookieValue(CookieBuf, "rs_id=", rs_id_check, &rs_idLen); if (strncmp(rs_id, rs_id_check, strlen(rs_id)) == 0 && rs_idLen != 0) { strcat(bufOut, "

RADIUS сервер занят. Повторите попытку позже

"); } else { strcat(bufOut, "

RADIUS сервер занят. Повторите попытку позже

"); } return; } if ((sSettings.sRADIUS.RDSEnable == true) && (fl_raddius_net_err == false)) { auth_flag = RS_AUTH_PROCESS; /* Generate cookie */ sprintf(rs_id, "%X", (unsigned int)GetRandomNumber()); strcpy(bufOut, "HTTP/1.0 200 OK\r\nContent-Type:text/html\r\nSet-Cookie: rs_id="); strcat(bufOut, rs_id); strcat(bufOut, "\r\n\r\n"); strcat(bufOut, "

Ожидание соединения с RADIUS сервером

"); } else #endif { HTTP_LocalAuthConfirmWebPwd(postBuf, bufOut, strlen(postBuf), lenBufOut); } } char *HTTP_LoginPage(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { (void)reqNum; uint32_t req_data_received = 0; char *offset = 0; memset(bufOut, 0, SEND_BUF_MAX_LEN); //printf("request 1: %d\r\n", lenBufIn); if (post_data_count == 0) { /* parse packet for Content-length field */ post_data_count = Parse_Content_Length(bufIn, lenBufIn); //printf("Content-length: %d\r\n", (int)post_data_count); if (post_data_count < MAX_POST_REQ_LEN) { memset(post_req_data, 0, MAX_POST_REQ_LEN); /* parse packet for "\r\n\r\n" */ offset = (strstr(bufIn, "\r\n\r\n")) + 4; req_data_received = lenBufIn - (offset - bufIn); //printf("req data received: %d\r\n", (int)req_data_received); /* Check if "\r\n\r\n" was found */ if (offset != 0) { /* if data was splited in two packets */ if (req_data_received < post_data_count) { /* Copy request data to buffer */ snprintf(post_req_data, req_data_received, "%s", bufIn); //printf("copied: %d\r\n", (int)req_data_received); post_data_count -= req_data_received; // log_post_reqn++; } /* if data received completely */ else { strncat(post_req_data, &bufIn[offset - bufIn], post_data_count); //printf("post_req_data: %s\r\n", post_req_data); /* End reqest */ post_data_count = 0; log_post_reqn = 0; HTTP_ConfirmWebPwd(bufIn, bufOut, post_req_data, lenBufIn, lenBufOut); *lenBufOut = strlen(bufOut); return bufOut; } } /* request was fragmented before "\r\n\r\n" */ else { log_post_reqn++; /* wait max 2 requests */ if (log_post_reqn > 1) { post_data_count = 0; log_post_reqn = 0; /* Redirect to login page */ #ifdef RADIUS_SERVER_ENABLE if((sSettings.sRADIUS.RDSEnable == true) && (fl_raddius_net_err == false)) fs_open("/rslogin.html", &file); else #endif fs_open("/login.html", &file); *lenBufOut = file.len; return file.data; } } } else { DBG printf("Too long POST request!\r\n"); /* Ignore request */ post_data_count = 0; log_post_reqn = 0; /* Redirect to login page */ #ifdef RADIUS_SERVER_ENABLE if((sSettings.sRADIUS.RDSEnable == true) && (fl_raddius_net_err == false)) fs_open("/rslogin.html", &file); else #endif fs_open("/login.html", &file); *lenBufOut = file.len; return file.data; } } else if (post_data_count > 0) { strncat(post_req_data, receiveBuf, post_data_count); post_data_count = 0; log_post_reqn = 0; HTTP_ConfirmWebPwd(bufIn, bufOut, post_req_data, lenBufIn, lenBufOut); *lenBufOut = strlen(bufOut); return bufOut; } else { /* Redirect to login page */ #ifdef RADIUS_SERVER_ENABLE if((sSettings.sRADIUS.RDSEnable == true) && (fl_raddius_net_err == false)) fs_open("/rslogin.html", &file); else #endif fs_open("/login.html", &file); *lenBufOut = file.len; return file.data; } return 0; } char *HTTP_LogoutPage(uint32_t reqNum, char *bufIn, char *bufOut, uint16_t lenBufIn, uint16_t *lenBufOut) { (void)bufIn; (void)bufOut; (void)lenBufIn; (void)reqNum; Authenticated = false; seclevel = 0xFF; HTTP_ForceUserLogout(user_id); fs_open("/settings.html", &file); *lenBufOut = file.len; return file.data; } #endif /** * @brief sends file from flash FS * @param filename: pointer to the file name to send * @param pnonmatch: pointer to the If-Non_Match value * @param pcb: pointer to a tcp_pcb struct * @param hs: pointer to a http_state struct * @param file: pointer to a fs_file struct * @retval */ char *send_file(char *filename, char *pnonmatch, struct fs_file *file, uint16_t *Len) { int res = 0; char etag[MAX_ETAG_LEN]; char *petag = NULL; res = fs_open(filename, file); if (res == 0) { printf("Not found: %s\r\n", filename); sprintf(filename, "/index.html"); fs_open(filename, file); } /* Find Etag value */ uint8_t etag_len = Parse_Header(file->data, file->len, Etag, 6, etag); if (etag_len < MAX_ETAG_LEN && etag_len > 0) { DBG printf("Etag: %s\r\n", etag); petag = etag; } /* Compare Etag and If-Non-Match fields */ if (pnonmatch && petag && (strcmp(pnonmatch, petag) == 0)) { /* Send 304 code */ sprintf(sendBuf, HTTP_304_NOT_MODIFIED); DBG printf(sendBuf); *Len = strlen(sendBuf); return sendBuf; } else { /* Send file */ //DBG printf("%s\r\n\r\n", filename); *Len = file->len; return file->data; } } /** * @brief Extract the custom field data from HTML data * @param data : pointer on receive packet buffer * @param len : buffer length * @param field : field name * @param flen : field name length * @retval value : pointer for field data */ static uint32_t Parse_Header(char *data, uint32_t len, const char *field, uint32_t flen, char *value) { uint32_t i = 0, size = 0; char *ptr; uint32_t Offset = 0; /* Find field name in data buffer */ for (i = 0; i < len; i++) { if (strncmp ((char *)(data + i), field, flen) == 0) { Offset = i + flen; break; } } /* Copy Field value */ if (Offset) { i = 0; ptr = (char *)(data + Offset); while (*(ptr + i) != 0x0d) { value[i] = *(ptr + i); i++; } value[i] = '\0'; size = i; } return size; } /** * @brief * @retval None */ bool GetFileName(char *inStr, char *fileName, uint8_t *fileNameLen) { char *beginValue = NULL; char *endValue = NULL; int len = 0; char *strPtr = NULL; strPtr = strstr(inStr, "GET"); if (strPtr == NULL) { strPtr = strstr(inStr, "POST"); } if (strPtr == NULL) { *fileNameLen = 0; return false; } else { beginValue = strpbrk(strPtr, "/"); endValue = strpbrk(beginValue, " "); if (endValue == NULL) { *fileNameLen = 0; return false; } len = endValue - beginValue; if (len < MAX_FILENAME_LEN) { strncpy(fileName, beginValue, len); *fileNameLen = len; fileName[len] = '\0'; return true; } else { return false; } } } /** * @brief Extract the Content_Length data from HTML data * @param data : pointer on receive packet buffer * @param len : buffer length * @retval size : Content_length in numeric format */ static uint32_t Parse_Content_Length(char *data, uint32_t len) { uint32_t i = 0, size = 0, S = 1; int32_t j = 0; char sizestring[6], *ptr; ContentLengthOffset = 0; /* find Content-Length data in packet buffer */ for (i = 0; i < len; i++) { if (strncmp ((char *)(data + i), Content_Length, 16) == 0) { ContentLengthOffset = i + 16; break; } } /* read Content-Length value */ if (ContentLengthOffset) { i = 0; ptr = (char *)(data + ContentLengthOffset); while (*(ptr + i) != 0x0d) { sizestring[i] = *(ptr + i); i++; ContentLengthOffset++; } if (i > 0) { /* transform string data into numeric format */ for (j = i - 1; j >= 0; j--) { size += (sizestring[j] - 0x30) * S; S = S * 10; } } } return size; } /** * @brief get the value of an URL parameter supplied in a HTTP request, zero-terminated */ uint8_t GetParamValue0(char *inStr, char *paramName, char *paramValue, uint8_t *paramLen) { uint8_t tmplen; uint8_t *len = paramLen ? paramLen : &tmplen; uint8_t rv = GetParamValue(inStr, paramName, paramValue, len); paramValue[*len] = 0; return rv; } /** * @brief get the value of an URL parameter supplied in a HTTP request * @retval None */ uint8_t GetParamValue(char *inStr, char *paramName, char *paramValue, uint8_t *paramLen) { char *beginValue = 0; char *endValue = 0; int len = 0; char *strPtr = 0; char paramName_tmp[50]; memset(paramName_tmp, 0, sizeof(paramName_tmp)); paramName_tmp[0] = '&'; strncat(paramName_tmp, paramName, strlen(paramName)); strcat(paramName_tmp, "="); strPtr = strstr(inStr, paramName_tmp); if (strPtr == 0) { paramName_tmp[0] = '0'; strPtr = strstr(inStr, paramName_tmp); if (strPtr == 0) { paramName_tmp[0] = '\n'; strPtr = strstr(inStr, paramName_tmp); } if (strPtr == 0) { paramName_tmp[0] = '?'; strPtr = strstr(inStr, paramName_tmp); } } if (strPtr != 0) { beginValue = strpbrk(strPtr, "="); endValue = strpbrk(&strPtr[1], "&"); if (endValue == 0) { endValue = strpbrk(strPtr, " "); } if (endValue == 0) { endValue = strPtr + strlen(strPtr); } len = endValue - beginValue - 1; strncpy(paramValue, beginValue + 1, len); *endValue = '0'; *beginValue = '0'; if (paramLen) { *paramLen = len; } return 1; } else { if (paramLen) { *paramLen = 0; } return 0; } } /** * @brief * @retval None */ uint8_t GetCookieValue(char *inStr, char *paramName, char *paramValue, uint8_t *paramLen) { char *beginValue = 0; char *endValue = 0; char *endValueTemp = 0; int len = 0; char *strPtr = 0; strPtr = strstr(inStr, paramName); if (strPtr != 0) { beginValue = strpbrk(strPtr, "="); endValue = strpbrk(strPtr, ";"); endValueTemp = strpbrk(strPtr, "\r"); if (endValueTemp != 0 && endValueTemp < endValue) { endValue = endValueTemp; } if (endValue == 0) { endValue = strpbrk(strPtr, "\n"); } len = endValue - beginValue - 1; strncpy(paramValue, beginValue + 1, len); *endValue = '0'; *beginValue = '0'; *paramLen = len; return 1; } else { *paramLen = 0; return 0; } } char *Parce_Boundary(const char *data, uint32_t len, char *dst, uint8_t dstlen) { char *ptr = NULL; char *boundary = NULL; uint8_t i = 0; for (uint32_t j = 0; j < len; j++) { if (strncmp ((char *)(data + j), "boundary=", 9) == 0) { boundary = (char *)data + j + 9; break; } } if (!boundary) { return NULL; } *dst++ = '-'; *dst++ = '-'; ptr = boundary; while ((*ptr != 0x0d) && (i < dstlen - 4)) { *dst++ = *ptr++; i++; } //*dst++ = '-'; //*dst++ = '-'; *dst = '\0'; if (i > 0) { return boundary; } else { return NULL; } } void ClearParamString(char *inBuf) { uint16_t len; char *str; str = strstr(inBuf, "HTTP"); if (str != 0) { len = str - inBuf; memset(str, 0, RECIVE_BUF_MAX_LEN - len - 1); } } #endif