| /**************************************************************************** |
| * apps/nshlib/nsh_telnetlogin.c |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. The |
| * ASF licenses this file to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance with the |
| * License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| * License for the specific language governing permissions and limitations |
| * under the License. |
| * |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Included Files |
| ****************************************************************************/ |
| |
| #include <nuttx/config.h> |
| |
| #include <string.h> |
| #include <ctype.h> |
| #include <unistd.h> |
| #include <termios.h> |
| |
| #include "fsutils/passwd.h" |
| |
| #include "nsh.h" |
| #include "nsh_console.h" |
| #include "nshlib/nshlib.h" |
| #include "system/readline.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_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 */ |
| |
| strlcpy(buffer, start, buflen); |
| } |
| |
| /**************************************************************************** |
| * Public Functions |
| ****************************************************************************/ |
| |
| /**************************************************************************** |
| * Name: nsh_telnetlogin |
| ****************************************************************************/ |
| |
| int nsh_telnetlogin(FAR struct console_stdio_s *pstate) |
| { |
| char username[16]; |
| char password[128]; |
| #ifdef CONFIG_NSH_PLATFORM_CHALLENGE |
| char challenge[128]; |
| #endif |
| struct termios cfg; |
| int i; |
| int ret; |
| |
| #ifdef CONFIG_NSH_PLATFORM_SKIP_LOGIN |
| if (platform_skip_login() == OK) |
| { |
| return OK; |
| } |
| #endif |
| |
| /* Present the NSH Telnet greeting */ |
| |
| write(OUTFD(pstate), g_telnetgreeting, strlen(g_telnetgreeting)); |
| |
| /* Loop for the configured number of retries */ |
| |
| for (i = 0; i < CONFIG_NSH_LOGIN_FAILCOUNT; i++) |
| { |
| /* Ask for the login username */ |
| |
| write(OUTFD(pstate), g_userprompt, strlen(g_userprompt)); |
| |
| username[0] = '\0'; |
| if (readline_fd(pstate->cn_line, CONFIG_NSH_LINELEN, |
| INFD(pstate), OUTFD(pstate)) >= 0) |
| |
| { |
| /* Parse out the username */ |
| |
| nsh_telnettoken(pstate, username, sizeof(username)); |
| } |
| |
| if (username[0] == '\0') |
| { |
| i--; |
| continue; |
| } |
| |
| #ifdef CONFIG_NSH_PLATFORM_CHALLENGE |
| platform_challenge(challenge, sizeof(challenge)); |
| write(OUTFD(pstate), challenge, strlen(challenge)); |
| #endif |
| |
| /* Ask for the login password */ |
| |
| write(OUTFD(pstate), g_passwordprompt, strlen(g_passwordprompt)); |
| |
| /* Disable ECHO if its a tty device */ |
| |
| if (isatty(INFD(pstate))) |
| { |
| if (tcgetattr(INFD(pstate), &cfg) == 0) |
| { |
| cfg.c_lflag &= ~ECHO; |
| tcsetattr(INFD(pstate), TCSANOW, &cfg); |
| } |
| } |
| |
| password[0] = '\0'; |
| ret = readline_fd(pstate->cn_line, CONFIG_NSH_LINELEN, |
| INFD(pstate), OUTFD(pstate)); |
| |
| /* Enable echo again after password */ |
| |
| if (isatty(INFD(pstate))) |
| { |
| if (tcgetattr(INFD(pstate), &cfg) == 0) |
| { |
| cfg.c_lflag |= ECHO; |
| tcsetattr(INFD(pstate), TCSANOW, &cfg); |
| } |
| } |
| |
| if (ret >= 0) |
| { |
| /* Parse out the password */ |
| |
| nsh_telnettoken(pstate, password, sizeof(password)); |
| |
| /* Verify the username and password */ |
| |
| #if defined(CONFIG_NSH_LOGIN_PASSWD) |
| if (PASSWORD_VERIFY_MATCH(passwd_verify(username, password))) |
| #elif defined(CONFIG_NSH_LOGIN_PLATFORM) |
| # ifdef CONFIG_NSH_PLATFORM_CHALLENGE |
| if (PASSWORD_VERIFY_MATCH(platform_user_verify(username, |
| challenge, |
| password))) |
| # else |
| if (PASSWORD_VERIFY_MATCH(platform_user_verify(username, |
| password))) |
| # endif |
| #elif defined(CONFIG_NSH_LOGIN_FIXED) |
| if (strcmp(password, CONFIG_NSH_LOGIN_PASSWORD) == 0 && |
| strcmp(username, CONFIG_NSH_LOGIN_USERNAME) == 0) |
| #else |
| # error No user verification method selected |
| #endif |
| { |
| write(OUTFD(pstate), g_loginsuccess, strlen(g_loginsuccess)); |
| return OK; |
| } |
| else |
| { |
| write(OUTFD(pstate), g_badcredentials, |
| strlen(g_badcredentials)); |
| #if CONFIG_NSH_LOGIN_FAILDELAY > 0 |
| usleep(CONFIG_NSH_LOGIN_FAILDELAY * 1000L); |
| #endif |
| } |
| } |
| } |
| |
| /* Too many failed login attempts */ |
| |
| write(OUTFD(pstate), g_loginfailure, strlen(g_loginfailure)); |
| return -1; |
| } |
| |
| #endif /* CONFIG_NSH_TELNET_LOGIN */ |