diff --git a/components/finsh/shell.c b/components/finsh/shell.c index ae0934f5d1d9eb2ecc93da2550db88b6d9041b60..7e8a84ab277e2636468893305af78476f9d0b5bb 100644 --- a/components/finsh/shell.c +++ b/components/finsh/shell.c @@ -33,6 +33,7 @@ * 2010-04-01 Bernard add prompt output when start and remove the empty history * 2011-02-23 Bernard fix variable section end issue of finsh shell * initialization when use GNU GCC compiler. + * 2016-11-26 armink add password authentication */ #include @@ -174,6 +175,93 @@ rt_uint32_t finsh_get_echo() return shell->echo_mode; } +#ifdef FINSH_USING_AUTH +/** + * set a new password for finsh + * + * @param password new password + * + * @return result, RT_EOK on OK, -RT_ERROR on the new password length is less than + * FINSH_PASSWORD_MIN or greater than FINSH_PASSWORD_MAX + */ +rt_err_t finsh_set_password(const char *password) { + rt_ubase_t level; + rt_size_t pw_len = rt_strlen(password); + + if (pw_len < FINSH_PASSWORD_MIN || pw_len > FINSH_PASSWORD_MAX) + return -RT_ERROR; + + level = rt_hw_interrupt_disable(); + rt_strncpy(shell->password, password, FINSH_PASSWORD_MAX); + rt_hw_interrupt_enable(level); + + return RT_EOK; +} + +/** + * get the finsh password + * + * @return password + */ +const char *finsh_get_password(void) +{ + return shell->password; +} + +static void finsh_wait_auth(void) +{ + char ch; + rt_bool_t input_finish = RT_FALSE; + char password[FINSH_PASSWORD_MAX] = { 0 }; + rt_size_t cur_pos = 0; + while (1) + { + rt_kprintf("Password for finsh: "); + while (!input_finish) + { + /* wait receive */ + if (rt_sem_take(&shell->rx_sem, RT_WAITING_FOREVER) != RT_EOK) continue; + + /* read one character from device */ + while (rt_device_read(shell->device, 0, &ch, 1) == 1) + { + if (ch >= ' ' && ch <= '~' && cur_pos < FINSH_PASSWORD_MAX) + { + /* change the printable characters to '*' */ + rt_kprintf("*"); + password[cur_pos++] = ch; + } + else if (ch == '\b' && cur_pos > 0) + { + /* backspace */ + password[cur_pos] = '\0'; + cur_pos--; + rt_kprintf("\b \b"); + } + else if (ch == '\r' || ch == '\n') + { + rt_kprintf("\n"); + input_finish = RT_TRUE; + break; + } + } + } + if (!rt_strncmp(shell->password, password, FINSH_PASSWORD_MAX)) return; + else + { + /* authentication failed, delay 2S for retry */ + rt_thread_delay(2 * RT_TICK_PER_SECOND); + rt_kprintf("Sorry, try again.\n"); + cur_pos = 0; + input_finish = RT_FALSE; + rt_memset(password, '\0', FINSH_PASSWORD_MAX); + /* read all last dirty data */ + while (rt_device_read(shell->device, 0, &ch, 1) == 1); + } + } +} +#endif /* FINSH_USING_AUTH */ + static void shell_auto_complete(char *prefix) { @@ -305,7 +393,6 @@ void finsh_thread_entry(void *parameter) #ifndef FINSH_USING_MSH_ONLY finsh_init(&shell->parser); #endif - rt_kprintf(FINSH_PROMPT); /* set console device as shell device */ if (shell->device == RT_NULL) @@ -320,6 +407,16 @@ void finsh_thread_entry(void *parameter) #endif } +#ifdef FINSH_USING_AUTH + /* set the default password when the password isn't setting */ + if (rt_strlen(finsh_get_password()) == 0) + RT_ASSERT(finsh_set_password(FINSH_DEFAULT_PASSWORD) == RT_EOK); + /* waiting authenticate success */ + finsh_wait_auth(); +#endif + + rt_kprintf(FINSH_PROMPT); + while (1) { /* wait receive */ diff --git a/components/finsh/shell.h b/components/finsh/shell.h index 751590366a0b227d9cda1cf2e2e3b34453f149a5..a4c96b9a26468602f42958d422a07c03509ffb64 100644 --- a/components/finsh/shell.h +++ b/components/finsh/shell.h @@ -68,6 +68,18 @@ const char* finsh_get_prompt(void); #endif #endif +#ifdef FINSH_USING_AUTH + #ifndef FINSH_PASSWORD_MAX + #define FINSH_PASSWORD_MAX RT_NAME_MAX + #endif + #ifndef FINSH_PASSWORD_MIN + #define FINSH_PASSWORD_MIN 6 + #endif + #ifndef FINSH_DEFAULT_PASSWORD + #define FINSH_DEFAULT_PASSWORD "rtthread" + #endif +#endif /* FINSH_USING_AUTH */ + enum input_stat { WAIT_NORMAL, @@ -98,6 +110,10 @@ struct finsh_shell rt_uint8_t line_curpos; rt_device_t device; + +#ifdef FINSH_USING_AUTH + char password[FINSH_PASSWORD_MAX]; +#endif }; void finsh_set_echo(rt_uint32_t echo); @@ -107,4 +123,9 @@ int finsh_system_init(void); void finsh_set_device(const char* device_name); const char* finsh_get_device(void); +#ifdef FINSH_USING_AUTH +rt_err_t finsh_set_password(const char *password); +const char *finsh_get_password(void); +#endif + #endif