From 9c58ee4a6fa57d629454e64fb0e2b418fd9819e8 Mon Sep 17 00:00:00 2001 From: patacongo Date: Fri, 12 Oct 2012 16:59:17 +0000 Subject: [PATCH] You can now configure a login for Telnet NSH session -- from Darcy Gong git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5231 42af7a65-404d-4744-a932-0658087f49c3 --- nshlib/Kconfig | 58 +++++++++++++++++------ nshlib/nsh.h | 35 +++++++++++++- nshlib/nsh_console.c | 15 ++++-- nshlib/nsh_console.h | 2 +- nshlib/nsh_parse.c | 11 +++++ nshlib/nsh_telnetd.c | 110 ++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 208 insertions(+), 23 deletions(-) diff --git a/nshlib/Kconfig b/nshlib/Kconfig index c0f7d6a92..d12a32973 100644 --- a/nshlib/Kconfig +++ b/nshlib/Kconfig @@ -291,19 +291,18 @@ config NSH_CONSOLE console front-end is selected (/dev/console). Normally, the serial console device is a UART and RS-232 - interface. However, if CONFIG_USBDEV is defined, then a USB + interface. However, if USBDEV is defined, then a USB serial device may, instead, be used if the one of the following are defined: - CONFIG_PL2303 and CONFIG_PL2303_CONSOLE - Sets up the - Prolifics PL2303 emulation as a console device at /dev/console. + PL2303 and PL2303_CONSOLE - Set up the Prolifics PL2303 + emulation as a console device at /dev/console. - CONFIG_CDCACM and CONFIG_CDCACM_CONSOLE - Sets up the - CDC/ACM serial device as a console device at dev/console. + CDCACM and CDCACM_CONSOLE - Set up the CDC/ACM serial + device as a console device at dev/console. - CONFIG_NSH_USBCONSOLE and CONFIG_NSH_USBCONDEV - Sets up the - some other USB serial device as the NSH console (not necessarily - dev/console). + NSH_USBCONSOLE and NSH_USBCONDEV - Sets up some other USB + serial device as the NSH console (not necessarily dev/console). config NSH_USBCONSOLE bool "Use a USB console" @@ -311,20 +310,20 @@ config NSH_USBCONSOLE depends on NSH_CONSOLE && USBDEV ---help--- If defined, then the an arbitrary USB device may be used - to as the NSH console. In this case, CONFIG_NSH_USBCONDEV - must be defined to indicate which USB device to use as - the console. + to as the NSH console. In this case, NSH_USBCONDEV must + be defined to indicate which USB device to use as the + console. config NSH_USBCONDEV string "USB console device" default "/dev/ttyACM0" depends on NSH_USBCONSOLE ---help--- - If CONFIG_NSH_USBCONSOLE is set to 'y', then CONFIG_NSH_USBCONDEV - must also be set to select the USB device used to support - the NSH console. This should be set to the quoted name of a + If NSH_USBCONSOLE is set to 'y', then NSH_USBCONDEV must + also be set to select the USB device used to support the + NSH console. This should be set to the quoted name of a readable/write-able USB driver such as: - CONFIG_NSH_USBCONDEV="/dev/ttyACM0". + NSH_USBCONDEV="/dev/ttyACM0". config UBSDEV_MINOR int "USB console device minor number" @@ -448,6 +447,35 @@ config NSH_IOBUFFER_SIZE ---help--- Determines the size of the I/O buffer to use for sending/ receiving TELNET commands/reponses. Default: 512 + +config NSH_TELNET_LOGIN + bool "Telnet Login" + default n + ---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 + +config NSH_TELNET_USERNAME + string "Login Username" + default "admin" + ---help--- + Login user name. Default: "admin" + +config NSH_TELNET_PASSWORD + string "Login Password" + default "nuttx" + ---help--- + Login password: Default: "nuttx" + +config NSH_TELNET_FAILCOUNT + int "Login Retry Count" + default 3 + ---help--- + Number of login retry attempts. + +endif endif config NSH_DHCPC diff --git a/nshlib/nsh.h b/nshlib/nsh.h index dac91ba05..cfab26271 100644 --- a/nshlib/nsh.h +++ b/nshlib/nsh.h @@ -164,10 +164,19 @@ * Default: SCHED_PRIORITY_DEFAULT * CONFIG_NSH_TELNETD_DAEMONSTACKSIZE - Stack size allocated for the * Telnet daemon. Default: 2048 - * CONFIG_NSH_TELNETD_CLIENTPRIO- Priority of the Telnet client. + * CONFIG_NSH_TELNETD_CLIENTPRIO - Priority of the Telnet client. * Default: SCHED_PRIORITY_DEFAULT * CONFIG_NSH_TELNETD_CLIENTSTACKSIZE - Stack size allocated for the * Telnet client. Default: 2048 + * CONFIG_NSH_TELNET_LOGIN - Support a simple Telnet login. + * + * 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. + * Default 3. */ #ifndef CONFIG_NSH_TELNETD_PORT @@ -190,6 +199,22 @@ # define CONFIG_NSH_TELNETD_CLIENTSTACKSIZE 2048 #endif +#ifdef CONFIG_NSH_TELNET_LOGIN + +# ifndef CONFIG_NSH_TELNET_USERNAME +# define CONFIG_NSH_TELNET_USERNAME "admin" +# endif + +# ifndef CONFIG_NSH_TELNET_PASSWORD +# define CONFIG_NSH_TELNET_PASSWORD "nuttx" +# endif + +# ifndef CONFIG_NSH_TELNET_FAILCOUNT +# define CONFIG_NSH_TELNET_FAILCOUNT 3 +# endif + +#endif /* CONFIG_NSH_TELNET_LOGIN */ + /* Verify support for ROMFS /etc directory support options */ #ifdef CONFIG_NSH_ROMFSETC @@ -362,6 +387,14 @@ typedef int (*cmd_t)(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv); ****************************************************************************/ extern const char g_nshgreeting[]; +#if defined(CONFIG_NSH_TELNET_LOGIN) && defined(CONFIG_NSH_TELNET) +extern const char g_telnetgreeting[]; +extern const char g_userprompt[]; +extern const char g_passwordprompt[]; +extern const char g_loginsuccess[]; +extern const char g_badcredentials[]; +extern const char g_loginfailure[]; +#endif extern const char g_nshprompt[]; extern const char g_nshsyntax[]; extern const char g_fmtargrequired[]; diff --git a/nshlib/nsh_console.c b/nshlib/nsh_console.c index b066e71f5..1b8f5f6ac 100644 --- a/nshlib/nsh_console.c +++ b/nshlib/nsh_console.c @@ -75,12 +75,17 @@ struct serialsave_s static FAR struct nsh_vtbl_s *nsh_consoleclone(FAR struct nsh_vtbl_s *vtbl); #endif static void nsh_consolerelease(FAR struct nsh_vtbl_s *vtbl); -static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl, FAR const void *buffer, size_t nbytes); -static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, const char *fmt, ...); +static ssize_t nsh_consolewrite(FAR struct nsh_vtbl_s *vtbl, + FAR const void *buffer, size_t nbytes); +static int nsh_consoleoutput(FAR struct nsh_vtbl_s *vtbl, + FAR const char *fmt, ...); static FAR char *nsh_consolelinebuffer(FAR struct nsh_vtbl_s *vtbl); -static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save); -static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save); -static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl, int exitstatus); +static void nsh_consoleredirect(FAR struct nsh_vtbl_s *vtbl, int fd, + FAR uint8_t *save); +static void nsh_consoleundirect(FAR struct nsh_vtbl_s *vtbl, + FAR uint8_t *save); +static void nsh_consoleexit(FAR struct nsh_vtbl_s *vtbl, int exitstatus) + noreturn_function; /**************************************************************************** * Private Data diff --git a/nshlib/nsh_console.h b/nshlib/nsh_console.h index 53e8c7897..4dc2938cb 100644 --- a/nshlib/nsh_console.h +++ b/nshlib/nsh_console.h @@ -109,7 +109,7 @@ struct nsh_vtbl_s FAR char *(*linebuffer)(FAR struct nsh_vtbl_s *vtbl); void (*redirect)(FAR struct nsh_vtbl_s *vtbl, int fd, FAR uint8_t *save); void (*undirect)(FAR struct nsh_vtbl_s *vtbl, FAR uint8_t *save); - void (*exit)(FAR struct nsh_vtbl_s *vtbl, int exitstatus); + void (*exit)(FAR struct nsh_vtbl_s *vtbl, int exitstatus) noreturn_function; /* Parser state data */ diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c index ba597a062..df2f7c3e3 100644 --- a/nshlib/nsh_parse.c +++ b/nshlib/nsh_parse.c @@ -395,6 +395,17 @@ const char g_nshgreeting[] = "\nNuttShell (NSH) NuttX-" CONFIG_VERSION_STR const char g_nshgreeting[] = "\nNuttShell (NSH)\n"; #endif +/* Telnet login prompts */ + +#if defined(CONFIG_NSH_TELNET_LOGIN) && defined(CONFIG_NSH_TELNET) +const char g_telnetgreeting[] = "\nWelcome to NuttShell(NSH) Telnet Server...\n"; +const char g_userprompt[] = "login: "; +const char g_passwordprompt[] = "password: "; +const char g_loginsuccess[] = "\nUser Logged-in!\n"; +const char g_badcredentials[] = "\nInvalid username or password\n"; +const char g_loginfailure[] = "Login failed!\n"; +#endif + /* The NSH prompt */ const char g_nshprompt[] = "nsh> "; diff --git a/nshlib/nsh_telnetd.c b/nshlib/nsh_telnetd.c index 0117aad04..478935d7f 100644 --- a/nshlib/nsh_telnetd.c +++ b/nshlib/nsh_telnetd.c @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -55,6 +56,18 @@ * 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 ****************************************************************************/ @@ -75,6 +88,91 @@ * Private Functions ****************************************************************************/ +/**************************************************************************** + * Name: nsh_telnetecho + ****************************************************************************/ + +#ifdef CONFIG_NSH_TELNET_LOGIN +void nsh_telnetecho(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_telnetlogin + ****************************************************************************/ + +#ifdef CONFIG_NSH_TELNET_LOGIN +int nsh_telnetlogin(struct console_stdio_s *pstate) +{ + char username[16]; + char password[16]; + uint8_t 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_TELNET_FAILCOUNT; i++) + { + /* Ask for the login username */ + + fputs(g_userprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); + if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) + { + strcpy(username, pstate->cn_line); + username[strlen(pstate->cn_line) - 1] = 0; + } + + /* Ask for the login password */ + + fputs(g_passwordprompt, pstate->cn_outstream); + fflush(pstate->cn_outstream); + nsh_telnetecho(pstate, TELNET_NOTUSE_ECHO); + if (fgets(pstate->cn_line, CONFIG_NSH_LINELEN, INSTREAM(pstate)) != NULL) + { + /* Verify the username and password */ + + strcpy(password,pstate->cn_line); + password[strlen(pstate->cn_line) - 1] = 0; + + if (strcmp(password, CONFIG_NSH_TELNET_PASSWORD) == 0 && + strcmp(username, CONFIG_NSH_TELNET_USERNAME) == 0) + { + 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 ****************************************************************************/ @@ -90,7 +188,17 @@ int nsh_telnetmain(int argc, char *argv[]) dbg("Session [%d] Started\n", getpid()); - /* Present a greeting */ + /* Login User and Password Check */ + +#ifdef CONFIG_NSH_TELNET_LOGIN + if (nsh_telnetlogin(pstate) != OK) + { + nsh_exit(&pstate->cn_vtbl, 1); + return -1; /* nsh_exit does not return */ + } +#endif /* CONFIG_NSH_TELNET_LOGIN */ + + /* Present the NSH greeting */ fputs(g_nshgreeting, pstate->cn_outstream); fflush(pstate->cn_outstream);