diff --git a/ChangeLog.txt b/ChangeLog.txt index 7990865e2..b68ce3075 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1516,4 +1516,6 @@ commands (2019-01-20). * apps/nshlib: Now supports a Message of the Day (MOTD) that will be presented after the NSH greeting (2015-01-20). + * apps/nshlib: All sessions may be protected with logins using + the encrypted password in /etc/passwd (2016-01-20). diff --git a/nshlib/Kconfig b/nshlib/Kconfig index 84dc2fecb..9c463ebfe 100644 --- a/nshlib/Kconfig +++ b/nshlib/Kconfig @@ -1442,35 +1442,52 @@ config NSH_IOBUFFER_SIZE Determines the size of the I/O buffer to use for sending/ receiving TELNET commands/reponses. Default: 512 +endif # NSH_TELNET +endmenu # Telnet Configuration + +config NSH_LOGIN + bool + default n + +config NSH_CONSOLE_LOGIN + bool "Console Login" + default n + select NSH_LOGIN + ---help--- + If defined, then the console user will be required to provide a + username and password to start the NSH shell. + config NSH_TELNET_LOGIN bool "Telnet Login" default n + depends on NSH_TELNET + select NSH_LOGIN ---help--- If defined, then the Telnet user will be required to provide a username and password to start the NSH shell. -if NSH_TELNET_LOGIN +if NSH_LOGIN -config NSH_TELNET_USERNAME +config NSH_LOGIN_USERNAME string "Login Username" default "admin" + depends on !FSUTILS_PASSWD ---help--- Login user name. Default: "admin" -config NSH_TELNET_PASSWORD +config NSH_LOGIN_PASSWORD string "Login Password" - default "nuttx" + default "Administrator" + depends on !FSUTILS_PASSWD ---help--- - Login password: Default: "nuttx" + Login password: Default: "Administrator" -config NSH_TELNET_FAILCOUNT +config NSH_LOGIN_FAILCOUNT int "Login Retry Count" default 3 ---help--- Number of login retry attempts. -endif # NSH_TELNET_LOGIN -endif # NSH_TELNET -endmenu # Telnet Configuration +endif # NSH_LOGIN endif # NSH_LIBRARY endmenu # NSH Library diff --git a/nshlib/Makefile b/nshlib/Makefile index 4e4317a16..39ab25ad9 100644 --- a/nshlib/Makefile +++ b/nshlib/Makefile @@ -1,7 +1,7 @@ ############################################################################ # apps/nshlib/Makefile # -# Copyright (C) 2011-2013 Gregory Nutt. All rights reserved. +# Copyright (C) 2011-2013, 2016 Gregory Nutt. All rights reserved. # Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without @@ -50,6 +50,10 @@ else CSRCS += nsh_session.c endif +ifeq ($(CONFIG_NSH_CONSOLE_LOGIN),y) +CSRCS += nsh_login.c +endif + ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) CSRCS += nsh_fsutils.c endif diff --git a/nshlib/nsh.h b/nshlib/nsh.h index 7ae1ee5e2..568225e99 100644 --- a/nshlib/nsh.h +++ b/nshlib/nsh.h @@ -347,9 +347,9 @@ * If CONFIG_NSH_TELNET_LOGIN is defined, then these additional * options may be specified: * - * CONFIG_NSH_TELNET_USERNAME - Login user name. Default: "admin" - * CONFIG_NSH_TELNET_PASSWORD - Login password: Default: "nuttx" - * CONFIG_NSH_TELNET_FAILCOUNT - Number of login retry attempts. + * CONFIG_NSH_LOGIN_USERNAME - Login user name. Default: "admin" + * CONFIG_NSH_LOGIN_PASSWORD - Login password: Default: "Administrator" + * CONFIG_NSH_LOGIN_FAILCOUNT - Number of login retry attempts. * Default 3. */ @@ -375,16 +375,16 @@ #ifdef CONFIG_NSH_TELNET_LOGIN -# ifndef CONFIG_NSH_TELNET_USERNAME -# define CONFIG_NSH_TELNET_USERNAME "admin" +# ifndef CONFIG_NSH_LOGIN_USERNAME +# define CONFIG_NSH_LOGIN_USERNAME "admin" # endif -# ifndef CONFIG_NSH_TELNET_PASSWORD -# define CONFIG_NSH_TELNET_PASSWORD "nuttx" +# ifndef CONFIG_NSH_LOGIN_PASSWORD +# define CONFIG_NSH_LOGIN_PASSWORD "nuttx" # endif -# ifndef CONFIG_NSH_TELNET_FAILCOUNT -# define CONFIG_NSH_TELNET_FAILCOUNT 3 +# ifndef CONFIG_NSH_LOGIN_FAILCOUNT +# define CONFIG_NSH_LOGIN_FAILCOUNT 3 # endif #endif /* CONFIG_NSH_TELNET_LOGIN */ @@ -803,8 +803,10 @@ extern const char g_nshgreeting[]; #if defined(CONFIG_NSH_MOTD) && !defined(CONFIG_NSH_PLATFORM_MOTD) extern const char g_nshmotd[]; #endif +#ifdef CONFIG_NSH_LOGIN #if defined(CONFIG_NSH_TELNET_LOGIN) && defined(CONFIG_NSH_TELNET) extern const char g_telnetgreeting[]; +#endif extern const char g_userprompt[]; extern const char g_passwordprompt[]; extern const char g_loginsuccess[]; @@ -876,6 +878,19 @@ struct console_stdio_s; int nsh_session(FAR struct console_stdio_s *pstate); int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline); +/**************************************************************************** + * Name: nsh_login + * + * Description: + * Prompt the user for a username and password. Return a failure if valid + * credentials are not returned (after some retries. + * + ****************************************************************************/ + +#ifdef CONFIG_NSH_CONSOLE_LOGIN +int nsh_login(FAR struct console_stdio_s *pstate); +#endif + /* Application interface */ int nsh_command(FAR struct nsh_vtbl_s *vtbl, int argc, char *argv[]); diff --git a/nshlib/nsh_login.c b/nshlib/nsh_login.c new file mode 100644 index 000000000..b6134d2e3 --- /dev/null +++ b/nshlib/nsh_login.c @@ -0,0 +1,232 @@ +/**************************************************************************** + * apps/nshlib/nsh_login.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name Gregory Nutt nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#ifdef CONFIG_NSH_CLE +# include +#else +# include +#endif + +#include "nsh.h" +#include "nsh_console.h" + +#ifdef CONFIG_NSH_CONSOLE_LOGIN + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_token + ****************************************************************************/ + +static void nsh_token(FAR struct console_stdio_s *pstate, + FAR char *buffer, size_t buflen) +{ + FAR char *start; + FAR char *endp1; + bool quoted = false; + + /* Find the start of token. Either (1) the first non-white space + * character on the command line or (2) the character immediately after + * a quotation mark. + */ + + for (start = pstate->cn_line; *start; start++) + { + /* Does the token open with a quotation mark */ + + if (*start == '"') + { + /* Yes.. break out with start set to the character after the + * quotation mark. + */ + + quoted = true; + start++; + break; + } + + /* No, then any non-whitespace is the first character of the token */ + + else if (!isspace(*start)) + { + /* Break out with start set to the first character of the token */ + + break; + } + } + + /* Find the terminating character after the token on the command line. The + * terminating character is either (1) the matching quotation mark, or (2) + * any whitespace. + */ + + for (endp1 = start; *endp1; endp1++) + { + /* Did the token begin with a quotation mark? */ + + if (quoted) + { + /* Yes.. then only the matching quotation mark (or end of string) + * terminates + */ + + if (*endp1 == '"') + { + /* Break out... endp1 points to closing quotation mark */ + + break; + } + } + + /* No.. any whitespace (or end of string) terminates */ + + else if (isspace(*endp1)) + { + /* Break out... endp1 points to first while space encountered */ + + break; + } + } + + /* Replace terminating character with a NUL terminator */ + + *endp1 = '\0'; + + /* Copied the token into the buffer */ + + strncpy(buffer, start, buflen); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_login + * + * Description: + * Prompt the user for a username and password. Return a failure if valid + * credentials are not returned (after some retries. + * + ****************************************************************************/ + +int nsh_login(FAR struct console_stdio_s *pstate) +{ + char username[16]; + char password[16]; + int ret; + int i; + + /* Loop for the configured number of retries */ + + for (i = 0; i < CONFIG_NSH_LOGIN_FAILCOUNT; i++) + { + /* Ask for the login username */ + + fputs(g_userprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); + +#ifdef CONFIG_NSH_CLE + ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN, + INSTREAM(pstate), OUTSTREAM(pstate)); +#else + ret = readline(pstate->cn_line, CONFIG_NSH_LINELEN, + INSTREAM(pstate), OUTSTREAM(pstate)); +#endif + + username[0] = '\0'; + if (ret != EOF) + { + /* Parse out the username */ + + nsh_token(pstate, username, sizeof(username)); + } + + /* Ask for the login password */ + + fputs(g_passwordprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); + + password[0] = '\0'; + if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) + { + /* Parse out the password */ + + nsh_token(pstate, password, sizeof(password)); + + /* Verify the username and password */ + +#ifdef CONFIG_FSUTILS_PASSWD + ret = passwd_verify(username, password); + if (PASSWORD_VERIFY_MATCH(ret)) + +#else + if (strcmp(password, CONFIG_NSH_LOGIN_PASSWORD) == 0 && + strcmp(username, CONFIG_NSH_LOGIN_USERNAME) == 0) +#endif + { + fputs(g_loginsuccess, pstate->cn_outstream); + fflush(pstate->cn_outstream); + return OK; + } + else + { + fputs(g_badcredentials, pstate->cn_outstream); + fflush(pstate->cn_outstream); + } + } + } + + /* Too many failed login attempts */ + + fputs(g_loginfailure, pstate->cn_outstream); + fflush(pstate->cn_outstream); + return -1; +} + +#endif /* CONFIG_NSH_CONSOLE_LOGIN */ diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c index 55ce08d1f..30f7ef536 100644 --- a/nshlib/nsh_parse.c +++ b/nshlib/nsh_parse.c @@ -232,8 +232,10 @@ const char g_nshmotd[] = CONFIG_NSH_MOTD_STRING; /* Telnet login prompts */ +#ifdef CONFIG_NSH_LOGIN #if defined(CONFIG_NSH_TELNET_LOGIN) && defined(CONFIG_NSH_TELNET) const char g_telnetgreeting[] = "\nWelcome to NuttShell(NSH) Telnet Server...\n"; +#endif const char g_userprompt[] = "login: "; const char g_passwordprompt[] = "password: "; const char g_loginsuccess[] = "\nUser Logged-in!\n"; diff --git a/nshlib/nsh_session.c b/nshlib/nsh_session.c index ddb00b8df..8c017d527 100644 --- a/nshlib/nsh_session.c +++ b/nshlib/nsh_session.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_session.c * - * Copyright (C) 2007-2009, 2011-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2009, 2011-2014, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -51,30 +51,6 @@ #include "nsh.h" #include "nsh_console.h" -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -109,6 +85,16 @@ int nsh_session(FAR struct console_stdio_s *pstate) DEBUGASSERT(pstate); vtbl = &pstate->cn_vtbl; +#ifdef CONFIG_NSH_CONSOLE_LOGIN + /* Login User and Password Check */ + + if (nsh_login(pstate) != OK) + { + nsh_exit(vtbl, 1); + return -1; /* nsh_exit does not return */ + } +#endif /* CONFIG_NSH_CONSOLE_LOGIN */ + /* Present a greeting and possibly a Message of the Day (MOTD) */ fputs(g_nshgreeting, pstate->cn_outstream); diff --git a/nshlib/nsh_stdsession.c b/nshlib/nsh_stdsession.c index c45a9327b..2e730a61d 100644 --- a/nshlib/nsh_stdsession.c +++ b/nshlib/nsh_stdsession.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_stdsession.c * - * Copyright (C) 2013-2014 Gregory Nutt. All rights reserved. + * Copyright (C) 2013-2014, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -51,30 +51,6 @@ #include "nsh.h" #include "nsh_console.h" -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -/**************************************************************************** - * Private Functions - ****************************************************************************/ - /**************************************************************************** * Public Functions ****************************************************************************/ @@ -108,6 +84,16 @@ int nsh_session(FAR struct console_stdio_s *pstate) DEBUGASSERT(pstate); vtbl = &pstate->cn_vtbl; +#ifdef CONFIG_NSH_CONSOLE_LOGIN + /* Login User and Password Check */ + + if (nsh_login(pstate) != OK) + { + nsh_exit(vtbl, 1); + return -1; /* nsh_exit does not return */ + } +#endif /* CONFIG_NSH_CONSOLE_LOGIN */ + /* Present a greeting and possibly a Message of the Day (MOTD) */ printf("%s", g_nshgreeting); diff --git a/nshlib/nsh_telnetd.c b/nshlib/nsh_telnetd.c index 3047975ab..d8b650999 100644 --- a/nshlib/nsh_telnetd.c +++ b/nshlib/nsh_telnetd.c @@ -1,7 +1,7 @@ /**************************************************************************** * apps/nshlib/nsh_telnetd.c * - * Copyright (C) 2007-2013 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2013, 2016 Gregory Nutt. All rights reserved. * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without @@ -48,6 +48,7 @@ #include +#include #include #include "nsh.h" @@ -202,7 +203,10 @@ static int nsh_telnetlogin(FAR struct console_stdio_s *pstate) { char username[16]; char password[16]; - uint8_t i; +#ifdef CONFIG_FSUTILS_PASSWD + int ret; +#endif + int i; /* Present the NSH Telnet greeting */ @@ -211,12 +215,14 @@ static int nsh_telnetlogin(FAR struct console_stdio_s *pstate) /* Loop for the configured number of retries */ - for (i = 0; i < CONFIG_NSH_TELNET_FAILCOUNT; i++) + for (i = 0; i < CONFIG_NSH_LOGIN_FAILCOUNT; i++) { /* Ask for the login username */ fputs(g_userprompt, pstate->cn_outstream); fflush(pstate->cn_outstream); + + username[0] = '\0'; if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) { /* Parse out the username */ @@ -229,6 +235,8 @@ static int nsh_telnetlogin(FAR struct console_stdio_s *pstate) fputs(g_passwordprompt, pstate->cn_outstream); fflush(pstate->cn_outstream); nsh_telnetecho(pstate, TELNET_NOTUSE_ECHO); + + password[0] = '\0'; if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) { /* Parse out the password */ @@ -237,8 +245,13 @@ static int nsh_telnetlogin(FAR struct console_stdio_s *pstate) /* Verify the username and password */ - if (strcmp(password, CONFIG_NSH_TELNET_PASSWORD) == 0 && - strcmp(username, CONFIG_NSH_TELNET_USERNAME) == 0) +#ifdef CONFIG_FSUTILS_PASSWD + ret = passwd_verify(username, password); + if (PASSWORD_VERIFY_MATCH(ret)) +#else + if (strcmp(password, CONFIG_NSH_LOGIN_PASSWORD) == 0 && + strcmp(username, CONFIG_NSH_LOGIN_USERNAME) == 0) +#endif { fputs(g_loginsuccess, pstate->cn_outstream); fflush(pstate->cn_outstream); @@ -281,9 +294,9 @@ int nsh_telnetmain(int argc, char *argv[]) dbg("Session [%d] Started\n", getpid()); +#ifdef CONFIG_NSH_TELNET_LOGIN /* Login User and Password Check */ -#ifdef CONFIG_NSH_TELNET_LOGIN if (nsh_telnetlogin(pstate) != OK) { nsh_exit(vtbl, 1);