From 07cf99130cff5aeefab66473b2d2f94e22dc83f1 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 20 Jan 2016 15:22:02 -0600 Subject: [PATCH] nsh_stdsession() cannot use the same login logic as nsh_session(); Also put telnet login in a separate file for symmetry --- nshlib/Makefile | 9 +- nshlib/nsh.h | 8 ++ nshlib/nsh_stdlogin.c | 228 +++++++++++++++++++++++++++++++++++ nshlib/nsh_stdsession.c | 3 +- nshlib/nsh_telnetd.c | 227 +---------------------------------- nshlib/nsh_telnetlogin.c | 251 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 497 insertions(+), 229 deletions(-) create mode 100644 nshlib/nsh_stdlogin.c create mode 100644 nshlib/nsh_telnetlogin.c diff --git a/nshlib/Makefile b/nshlib/Makefile index 39ab25ad9..67e64bf35 100644 --- a/nshlib/Makefile +++ b/nshlib/Makefile @@ -46,13 +46,15 @@ CSRCS += nsh_timcmds.c nsh_envcmds.c nsh_syscmds.c nsh_dbgcmds.c ifeq ($(CONFIG_NFILE_STREAMS),0) CSRCS += nsh_stdsession.c +ifeq ($(CONFIG_NSH_CONSOLE_LOGIN),y) +CSRCS += nsh_stdlogin.c +endif else CSRCS += nsh_session.c -endif - ifeq ($(CONFIG_NSH_CONSOLE_LOGIN),y) CSRCS += nsh_login.c endif +endif ifneq ($(CONFIG_NFILE_DESCRIPTORS),0) CSRCS += nsh_fsutils.c @@ -93,6 +95,9 @@ endif ifeq ($(CONFIG_NSH_TELNET),y) CSRCS += nsh_telnetd.c +ifeq ($(CONFIG_NSH_TELNET_LOGIN),y) +CSRCS += nsh_telnetlogin.c +endif endif ifneq ($(CONFIG_NSH_DISABLESCRIPT),y) diff --git a/nshlib/nsh.h b/nshlib/nsh.h index 568225e99..1c1609d91 100644 --- a/nshlib/nsh.h +++ b/nshlib/nsh.h @@ -888,7 +888,15 @@ int nsh_parse(FAR struct nsh_vtbl_s *vtbl, char *cmdline); ****************************************************************************/ #ifdef CONFIG_NSH_CONSOLE_LOGIN +# if CONFIG_NFILE_DESCRIPTORS > 0 int nsh_login(FAR struct console_stdio_s *pstate); +# else +int nsh_stdlogin(FAR struct console_stdio_s *pstate); +# endif +#endif + +#ifdef CONFIG_NSH_TELNET_LOGIN +int nsh_telnetlogin(FAR struct console_stdio_s *pstate); #endif /* Application interface */ diff --git a/nshlib/nsh_stdlogin.c b/nshlib/nsh_stdlogin.c new file mode 100644 index 000000000..1e86e48a1 --- /dev/null +++ b/nshlib/nsh_stdlogin.c @@ -0,0 +1,228 @@ +/**************************************************************************** + * apps/nshlib/nsh_stdlogin.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_stdtoken + ****************************************************************************/ + +static void nsh_stdtoken(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_stdlogin + * + * Description: + * Prompt the user for a username and password. Return a failure if valid + * credentials are not returned (after some retries. + * + ****************************************************************************/ + +int nsh_stdlogin(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 */ + + printf("%s", g_userprompt); + + /* Get the reponse, handling all possible cases */ + +#ifdef CONFIG_NSH_CLE + ret = cle(pstate->cn_line, CONFIG_NSH_LINELEN, + stdin, stdout); +#else + ret = std_readline(pstate->cn_line, CONFIG_NSH_LINELEN); +#endif + + username[0] = '\0'; + if (ret != EOF) + { + /* Parse out the username */ + + nsh_stdtoken(pstate, username, sizeof(username)); + } + + /* Ask for the login password */ + + printf("%s", g_passwordprompt); + + password[0] = '\0'; + if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, stdin) != NULL) + { + /* Parse out the password */ + + nsh_stdtoken(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 + { + printf("%s", g_loginsuccess); + return OK; + } + else + { + printf("%s", g_badcredentials); + } + } + } + + /* Too many failed login attempts */ + + printf("%s", g_loginfailure); + return -1; +} + +#endif /* CONFIG_NSH_CONSOLE_LOGIN */ diff --git a/nshlib/nsh_stdsession.c b/nshlib/nsh_stdsession.c index 2e730a61d..ebf76a687 100644 --- a/nshlib/nsh_stdsession.c +++ b/nshlib/nsh_stdsession.c @@ -87,7 +87,7 @@ int nsh_session(FAR struct console_stdio_s *pstate) #ifdef CONFIG_NSH_CONSOLE_LOGIN /* Login User and Password Check */ - if (nsh_login(pstate) != OK) + if (nsh_stdlogin(pstate) != OK) { nsh_exit(vtbl, 1); return -1; /* nsh_exit does not return */ @@ -109,6 +109,7 @@ int nsh_session(FAR struct console_stdio_s *pstate) /* Output the fixed message of the day */ printf("%s\n", g_nshmotd); + # endif #endif diff --git a/nshlib/nsh_telnetd.c b/nshlib/nsh_telnetd.c index d8b650999..5c9560f80 100644 --- a/nshlib/nsh_telnetd.c +++ b/nshlib/nsh_telnetd.c @@ -40,15 +40,10 @@ #include #include -#include -#include -#include #include -#include #include -#include #include #include "nsh.h" @@ -56,235 +51,15 @@ #ifdef CONFIG_NSH_TELNET -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -#ifdef CONFIG_NSH_TELNET_LOGIN - -# define TELNET_IAC 255 -# define TELNET_WILL 251 -# define TELNET_WONT 252 -# define TELNET_DO 253 -# define TELNET_DONT 254 -# define TELNET_USE_ECHO 1 -# define TELNET_NOTUSE_ECHO 0 - -#endif /* CONFIG_NSH_TELNET_LOGIN */ - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - /**************************************************************************** * Private Functions ****************************************************************************/ -/**************************************************************************** - * Name: nsh_telnetecho - ****************************************************************************/ - -#ifdef CONFIG_NSH_TELNET_LOGIN -static void nsh_telnetecho(FAR struct console_stdio_s *pstate, uint8_t is_use) -{ - uint8_t optbuf[4]; - optbuf[0] = TELNET_IAC; - optbuf[1] = (is_use == TELNET_USE_ECHO) ? TELNET_WILL : TELNET_DO; - optbuf[2] = 1; - optbuf[3] = 0; - fputs((char *)optbuf, pstate->cn_outstream); - fflush(pstate->cn_outstream); -} -#endif - -/**************************************************************************** - * Name: nsh_telnettoken - ****************************************************************************/ - -#ifdef CONFIG_NSH_TELNET_LOGIN -static void nsh_telnettoken(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); -} -#endif - -/**************************************************************************** - * Name: nsh_telnetlogin - ****************************************************************************/ - -#ifdef CONFIG_NSH_TELNET_LOGIN -static int nsh_telnetlogin(FAR struct console_stdio_s *pstate) -{ - char username[16]; - char password[16]; -#ifdef CONFIG_FSUTILS_PASSWD - int ret; -#endif - int i; - - /* Present the NSH Telnet greeting */ - - fputs(g_telnetgreeting, pstate->cn_outstream); - fflush(pstate->cn_outstream); - - /* 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); - - username[0] = '\0'; - if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) - { - /* Parse out the username */ - - nsh_telnettoken(pstate, username, sizeof(username)); - } - - /* Ask for the login password */ - - 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 */ - - nsh_telnettoken(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); - nsh_telnetecho(pstate, TELNET_USE_ECHO); - return OK; - } - else - { - fputs(g_badcredentials, pstate->cn_outstream); - fflush(pstate->cn_outstream); - } - } - - nsh_telnetecho(pstate, TELNET_USE_ECHO); - } - - /* Too many failed login attempts */ - - fputs(g_loginfailure, pstate->cn_outstream); - fflush(pstate->cn_outstream); - return -1; -} -#endif /* CONFIG_NSH_TELNET_LOGIN */ - -/**************************************************************************** - * Public Functions - ****************************************************************************/ - /**************************************************************************** * Name: nsh_telnetmain ****************************************************************************/ -int nsh_telnetmain(int argc, char *argv[]) +static int nsh_telnetmain(int argc, char *argv[]) { FAR struct console_stdio_s *pstate = nsh_newconsole(); FAR struct nsh_vtbl_s *vtbl; diff --git a/nshlib/nsh_telnetlogin.c b/nshlib/nsh_telnetlogin.c new file mode 100644 index 000000000..5cb82ce42 --- /dev/null +++ b/nshlib/nsh_telnetlogin.c @@ -0,0 +1,251 @@ +/**************************************************************************** + * apps/nshlib/nsh_telnetlogin.c + * + * Copyright (C) 2007-2013, 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 + +#include "nsh.h" +#include "nsh_console.h" + +#ifdef CONFIG_NSH_TELNET_LOGIN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define TELNET_IAC 255 +#define TELNET_WILL 251 +#define TELNET_WONT 252 +#define TELNET_DO 253 +#define TELNET_DONT 254 +#define TELNET_USE_ECHO 1 +#define TELNET_NOTUSE_ECHO 0 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: nsh_telnetecho + ****************************************************************************/ + +static void nsh_telnetecho(FAR struct console_stdio_s *pstate, uint8_t is_use) +{ + uint8_t optbuf[4]; + optbuf[0] = TELNET_IAC; + optbuf[1] = (is_use == TELNET_USE_ECHO) ? TELNET_WILL : TELNET_DO; + optbuf[2] = 1; + optbuf[3] = 0; + fputs((char *)optbuf, pstate->cn_outstream); + fflush(pstate->cn_outstream); +} + +/**************************************************************************** + * Name: nsh_telnettoken + ****************************************************************************/ + +static void nsh_telnettoken(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_telnetlogin + ****************************************************************************/ + +int nsh_telnetlogin(FAR struct console_stdio_s *pstate) +{ + char username[16]; + char password[16]; +#ifdef CONFIG_FSUTILS_PASSWD + int ret; +#endif + int i; + + /* Present the NSH Telnet greeting */ + + fputs(g_telnetgreeting, pstate->cn_outstream); + fflush(pstate->cn_outstream); + + /* 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); + + username[0] = '\0'; + if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) + { + /* Parse out the username */ + + nsh_telnettoken(pstate, username, sizeof(username)); + } + + /* Ask for the login password */ + + 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 */ + + nsh_telnettoken(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); + nsh_telnetecho(pstate, TELNET_USE_ECHO); + return OK; + } + else + { + fputs(g_badcredentials, pstate->cn_outstream); + fflush(pstate->cn_outstream); + } + } + + nsh_telnetecho(pstate, TELNET_USE_ECHO); + } + + /* Too many failed login attempts */ + + fputs(g_loginfailure, pstate->cn_outstream); + fflush(pstate->cn_outstream); + return -1; +} + +#endif /* CONFIG_NSH_TELNET_LOGIN */