cli.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. #include "cli.h"
  2. #include <string.h>
  3. #include "FreeRTOS.h"
  4. #include "task.h"
  5. #include "FreeRTOS_CLI.h"
  6. #include "CLI_Commands.h"
  7. #include "settings_api.h"
  8. #include "parameters.h"
  9. #include "control_symbol.h"
  10. #include "log.h"
  11. #include "web_params_api.h"
  12. #include "tinystdio.h"
  13. #define ISO_nl 0x0a
  14. #define ISO_cr 0x0d
  15. #define REPEAT_SENSOR_INFO_TIME configTICK_RATE_HZ*5*1
  16. #define array_len(x) (sizeof(x)/sizeof(x[0]))
  17. /**
  18. * @brief Общая структура настроек
  19. */
  20. extern SETTINGS_t sSettings;
  21. uint8_t id_change_pwd = 0;
  22. const int8_t * const pcWarningMessage = ( const int8_t * ) "Количество соединенений превышено. Данное соединение будет закрыто\r\n";
  23. #ifdef HARDWARE_BT6709
  24. const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT-6709 command server - connection accepted.\r\nlogin:";
  25. #else
  26. const int8_t * const pcWelcomeMessage = ( const int8_t * ) "BT-6707 command server - connection accepted.\r\nlogin:";
  27. #endif
  28. static const int8_t * const pcEndOfCommandOutputString = ( int8_t * ) "\r\n[Нажмите клавишу ENTER для повторного выполнения предыдущей команды]\r\n>";
  29. extern int8_t cOutputBuffer[ configCOMMAND_INT_MAX_OUTPUT_SIZE ];
  30. cli_state_t cli_states[MAX_SESSIONS];
  31. void SensorInfoTimerCallback(TimerHandle_t pxTimer) {
  32. portBASE_TYPE xReturned = pdTRUE;
  33. uint8_t num_timer;
  34. for (uint8_t i = 0; i < array_len(cli_states); i ++) {
  35. if(pxTimer == cli_states[i].RepeatSensorInfoTimer){
  36. num_timer = i;
  37. break;
  38. }
  39. }
  40. do {
  41. /* Ensure there is not a string lingering in
  42. the output buffer. */
  43. cOutputBuffer[ 0 ] = 0x00;
  44. xReturned = FreeRTOS_CLIProcessCommand(&cli_states[num_timer], "sensor info", cOutputBuffer, configCOMMAND_INT_MAX_OUTPUT_SIZE);
  45. cli_states[num_timer].send(cli_states[num_timer].num_connect, cOutputBuffer, strlen( ( const char * ) cOutputBuffer ));
  46. } while( xReturned != pdFALSE );
  47. xTimerStart(cli_states[num_timer].RepeatSensorInfoTimer, 0);
  48. }
  49. static portBASE_TYPE FreeRTOS_CLIAuthProcess( int8_t * pcWriteBuffer, cli_state_t *s)
  50. {
  51. portBASE_TYPE xReturn = pdTRUE;
  52. uint32_t len;
  53. uint8_t valueLen, user_id;
  54. char WebPassword[MAX_WEB_PASSWD_LEN];
  55. char WebLogin[MAX_WEB_LOGIN_LEN];
  56. char password[cmdMAX_INPUT_SIZE] = { 0 };
  57. const int8_t * const pcPSWHeader = ( int8_t * ) "\r\npassword:";
  58. const int8_t * const pcLoginHeader = ( int8_t * ) "\r\nlogin:";
  59. memset(pcWriteBuffer, 0, configCOMMAND_INT_MAX_OUTPUT_SIZE);
  60. switch(s->input_state){
  61. case CLI_AUTH:
  62. memset(s->login, 0, MAX_WEB_LOGIN_LEN);
  63. len = strlen(s->buf);
  64. if(len < MAX_WEB_LOGIN_LEN){
  65. strncpy(s->login, s->buf, len);
  66. //sendopt(s, TELNET_WILL, TELOPT_ECHO);
  67. strncpy( ( char * ) pcWriteBuffer, ( const char * ) pcPSWHeader, strlen( ( char * ) pcPSWHeader ) );
  68. s->input_state = CLI_AUTH_PASSW;
  69. xReturn = pdTRUE;
  70. }
  71. else{
  72. xReturn = pdFALSE;
  73. }
  74. break;
  75. case CLI_AUTH_PASSW:
  76. //sendopt(s, TELNET_WONT, TELOPT_ECHO);
  77. memset(name_login_telnet, 0, 50);
  78. memset(password, 0, MAX_WEB_PASSWD_LEN);
  79. len = strlen(s->buf);
  80. strncpy(password, s->buf, len);
  81. for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) {
  82. GetUserLogin(user_id, WebLogin, &valueLen);
  83. GetUserPassword(user_id, WebPassword, &valueLen);
  84. /* Check login and password */
  85. if ((strncmp(WebLogin, s->login, MAX_WEB_LOGIN_LEN) == 0) &&
  86. (strncmp(WebPassword, password, MAX_WEB_PASSWD_LEN) == 0)) {
  87. /* Login and pass are valid */
  88. s->user_id = user_id;
  89. s->login_err = 0;
  90. strcpy( ( char * ) pcWriteBuffer, "\r\nАвторизация успешно пройдена\r\n>" );
  91. s->input_state = CLI_CMD;
  92. switch (user_id) {
  93. case 0:
  94. snprintf(name_login_telnet, sizeof(name_login_telnet), "Администратор");
  95. break;
  96. case 1:
  97. snprintf(name_login_telnet, sizeof(name_login_telnet), "Пользователь");
  98. break;
  99. default:
  100. break;
  101. }
  102. log_event_data(LOG_LOGIN_TELNET, name_login_telnet);
  103. xReturn = pdTRUE;
  104. break;
  105. }
  106. else{
  107. xReturn = pdFALSE;
  108. }
  109. }
  110. break;
  111. default:
  112. xReturn = pdFALSE;
  113. s->input_state = CLI_AUTH;
  114. return xReturn;
  115. break;
  116. }
  117. if(xReturn == pdFALSE){
  118. s->input_state = CLI_AUTH;
  119. if(s->login_err < 4){
  120. s->login_err ++;
  121. strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка авторизации\r\n" );
  122. strncat( ( char * ) pcWriteBuffer, ( const char * ) pcLoginHeader, strlen( ( char * ) pcLoginHeader ) );
  123. xReturn = pdTRUE;
  124. }
  125. else{
  126. s->login_err = 0;
  127. xReturn = pdFALSE;
  128. }
  129. }
  130. return xReturn;
  131. }
  132. static portBASE_TYPE FreeRTOS_ChangePWDProcess( int8_t * pcWriteBuffer, cli_state_t *s)
  133. {
  134. portBASE_TYPE xReturn = pdTRUE;
  135. uint32_t len;
  136. static char password[ MAX_WEB_PASSWD_LEN ] = { 0 };
  137. char password2[ MAX_WEB_PASSWD_LEN ] = { 0 };
  138. const int8_t * const pcNewPSWHeader = ( int8_t * ) "\r\nВведите повторно новый пароль:";
  139. memset(pcWriteBuffer, 0, configCOMMAND_INT_MAX_OUTPUT_SIZE);
  140. len = strlen(s->buf);
  141. if(s->input_state == CLI_CHANGE_PWD){
  142. memset(password, 0, MAX_WEB_PASSWD_LEN);
  143. if(len >= MAX_WEB_PASSWD_LEN){
  144. strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
  145. s->input_state = CLI_CMD;
  146. } else {
  147. if(!control_string_en_digit(s->buf, len)){
  148. strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
  149. s->input_state = CLI_CMD;
  150. } else {
  151. strncpy(password, s->buf, len);
  152. strncpy( ( char * ) pcWriteBuffer, ( const char * ) pcNewPSWHeader, strlen( ( char * ) pcNewPSWHeader ) );
  153. s->input_state = CLI_CHANGE_PWD_ACK;
  154. }
  155. }
  156. } else {
  157. s->input_state = CLI_CHANGE_PWD;
  158. memset(password2, 0, cmdMAX_INPUT_SIZE);
  159. if(len >= MAX_WEB_LOGIN_LEN){
  160. strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
  161. s->input_state = CLI_CMD;
  162. } else {
  163. strncpy(password2, s->buf, len);
  164. if (strncmp(password, password2, MAX_WEB_PASSWD_LEN) == 0) {
  165. memcpy(sSettings.sAuth[id_change_pwd].password, password, 11);
  166. telnet_act = true;
  167. HTTP_SaveSettings();
  168. log_event_data(LOG_PSW_CHANGE, name_login_telnet);
  169. strcpy( ( char * ) pcWriteBuffer, "\r\nПароль успешно изменен\r\n>" );
  170. s->input_state = CLI_CMD;
  171. xReturn = pdTRUE;
  172. } else {
  173. strcpy( ( char * ) pcWriteBuffer, "\r\nОшибка при вводе нового пароля\r\n>" );
  174. s->input_state = CLI_CMD;
  175. }
  176. }
  177. }
  178. return xReturn;
  179. }
  180. static void cli_input(cli_state_t *s)
  181. {
  182. portBASE_TYPE xReturned;
  183. switch(s->input_state){
  184. case CLI_AUTH:
  185. case CLI_AUTH_PASSW:
  186. if(FreeRTOS_CLIAuthProcess(cOutputBuffer, s)){
  187. s->send(s->num_connect, cOutputBuffer, strlen( ( const char * ) cOutputBuffer ));
  188. memset( s->buf, 0x00, cmdMAX_INPUT_SIZE );
  189. }
  190. else{
  191. s->state = STATE_CLOSE;
  192. }
  193. break;
  194. case CLI_CMD:
  195. /* The input string has been terminated. Was the
  196. input a quit command? */
  197. if( strcmp( "quit", ( const char * ) s->buf ) == 0 )
  198. {
  199. s->state = STATE_CLOSE;
  200. }
  201. else
  202. {
  203. /* The input string was not a quit command.
  204. Pass the string to the command interpreter. */
  205. /* See if the command is empty, indicating that the last command is
  206. to be executed again. */
  207. if( s->bufptr == 0 )
  208. {
  209. if(s->flag_telnet_ip_option ){
  210. s->flag_telnet_ip_option = false;
  211. return;
  212. }
  213. else{
  214. strcpy( s->buf, s->prev_cmd );
  215. }
  216. }
  217. /* Transmit a line separator, just to make the
  218. output easier to read. */
  219. s->send(s->num_connect, "\r\n", strlen( "\r\n" ));
  220. do
  221. {
  222. /* Ensure there is not a string lingering in
  223. the output buffer. */
  224. cOutputBuffer[ 0 ] = 0x00;
  225. // FIXME telnetState should go into the command processor
  226. //input_state = s->input_state;
  227. xReturned = FreeRTOS_CLIProcessCommand(s, s->buf, cOutputBuffer, configCOMMAND_INT_MAX_OUTPUT_SIZE );
  228. //s->input_state = input_state;
  229. s->send(s->num_connect, cOutputBuffer, strlen( ( const char * ) cOutputBuffer ));
  230. } while( xReturned != pdFALSE );
  231. if( strcmp( "sensor info", ( const char * ) s->buf ) == 0 ){
  232. strcpy( s->prev_cmd, s->buf );
  233. memset( s->buf, 0x00, cmdMAX_INPUT_SIZE );
  234. xTimerStart(s->RepeatSensorInfoTimer, 0);
  235. } else {
  236. /* All the strings generated by the input
  237. command have been sent. Clear the input
  238. string ready to receive the next command.
  239. Remember the command that was just processed
  240. first in case it is to be processed again. */
  241. strcpy( s->prev_cmd, s->buf );
  242. memset( s->buf, 0x00, cmdMAX_INPUT_SIZE );
  243. if(s->input_state != CLI_CHANGE_PWD)
  244. s->send(s->num_connect, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ));
  245. }
  246. }
  247. break;
  248. case CLI_CHANGE_PWD:
  249. case CLI_CHANGE_PWD_ACK:
  250. FreeRTOS_ChangePWDProcess(cOutputBuffer, s);
  251. s->send(s->num_connect, cOutputBuffer, strlen( ( const char * ) cOutputBuffer ));
  252. memset( s->buf, 0x00, cmdMAX_INPUT_SIZE );
  253. break;
  254. }
  255. }
  256. void cli_getchar(cli_state_t *s, char incoming_char)
  257. {
  258. s->buf[s->bufptr] = incoming_char;
  259. bool echo_enabled = true; // FIXME
  260. if(echo_enabled && s->input_state != CLI_AUTH_PASSW){
  261. if(s->buf[s->bufptr] != 0x03 && s->buf[s->bufptr] != 0x7f){
  262. s->send( s->num_connect, &s->buf[s->bufptr], 1);
  263. }
  264. }
  265. else if(s->input_state == CLI_AUTH_PASSW){
  266. s->send( s->num_connect, " ", 1);
  267. }
  268. if(s->buf[s->bufptr] == ISO_nl || s->buf[s->bufptr] == 0) {
  269. s->bufptr = 0;
  270. return;
  271. }
  272. if(s->buf[s->bufptr] == ISO_cr || s->bufptr == sizeof(s->buf) - 1) {
  273. if(s->bufptr > 0) {
  274. s->buf[s->bufptr] = 0;
  275. }
  276. cli_input(s);
  277. s->bufptr = 0;
  278. } else if( s->buf[s->bufptr] == '\b' || s->buf[s->bufptr] == 0x7f) {
  279. /* Backspace was pressed. Erase the last character in the string - if any. */
  280. s->buf[s->bufptr] = '\0';
  281. if (s->bufptr > 0) {
  282. s->bufptr--;
  283. s->buf[s->bufptr] = '\0';
  284. const char backspace[] = "\b \b";
  285. s->send(s->num_connect, backspace, sizeof(backspace));
  286. }
  287. } else if (s->buf[s->bufptr] == 0x03){
  288. xTimerStop(s->RepeatSensorInfoTimer, 0);
  289. s->flag_telnet_ip_option = true;
  290. if(s->input_state != CLI_CHANGE_PWD && s->input_state != CLI_CHANGE_PWD_ACK)
  291. s->send( s->num_connect, pcEndOfCommandOutputString, strlen( ( const char * ) pcEndOfCommandOutputString ));
  292. } else {
  293. ++s->bufptr;
  294. }
  295. }
  296. void cli_init(void)
  297. {
  298. for (uint8_t i = 0; i < array_len(cli_states); i++) {
  299. memset(cli_states[i].buf, 0, cmdMAX_INPUT_SIZE);
  300. memset(cli_states[i].prev_cmd, 0, cmdMAX_INPUT_SIZE);
  301. memset(cli_states[i].optdata, 0, cmdMAX_INPUT_SIZE);
  302. cli_states[i].optlen = 0;
  303. cli_states[i].num_connect = 0;
  304. cli_states[i].user_id = USER;
  305. cli_states[i].flag_telnet_ip_option = false;
  306. cli_states[i].RepeatSensorInfoTimer = xTimerCreate("SensorInfoTmr", REPEAT_SENSOR_INFO_TIME, pdFALSE, ( void * ) i, SensorInfoTimerCallback);
  307. }
  308. vRegisterCLICommands();
  309. }
  310. cli_state_t *alloc_state(void)
  311. {
  312. for (unsigned i = 0; i < array_len(cli_states); ++i) {
  313. if (cli_states[i].state == STATE_UNUSED) {
  314. cli_states[i].state = STATE_CLOSE;
  315. cli_states[i].prev_cmd[0] = 0; // don't leak the previous user's history
  316. return &cli_states[i];
  317. }
  318. }
  319. return 0;
  320. }
  321. void cli_hello(cli_state_t *cli_state)
  322. {
  323. cli_state->state = STATE_NORMAL;
  324. const char hello[] = "hello\r\n>";
  325. cli_state->send(cli_state->num_connect, hello, sizeof(hello));
  326. }
  327. user_level_t cli_auth_user(char *user, char *password)
  328. {
  329. user_level_t rv = MAX_USER_LEVELS;
  330. char WebPassword[MAX_WEB_PASSWD_LEN];
  331. char WebLogin[MAX_WEB_LOGIN_LEN];
  332. uint8_t valueLen, user_id;
  333. for (user_id = 0; user_id < MAX_WEB_USERS; user_id++) {
  334. GetUserLogin(user_id, WebLogin, &valueLen);
  335. GetUserPassword(user_id, WebPassword, &valueLen);
  336. /* Check login and password */
  337. if ((strncmp(WebLogin, user, MAX_WEB_LOGIN_LEN) == 0) &&
  338. (strncmp(WebPassword, password, MAX_WEB_PASSWD_LEN) == 0)) {
  339. /* Login and pass are valid */
  340. rv = user_id;
  341. break;
  342. }
  343. }
  344. return rv;
  345. }