This is an automated email from the ASF dual-hosted git repository.
xiaoxiang781216 pushed a commit to branch releases/13.0
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/releases/13.0 by this push:
new 78ccf6a7e nshlib: Add su, id, and whoami identity commands
78ccf6a7e is described below
commit 78ccf6a7e16f3ce54c05c065863ca78454689db2
Author: Abhishek Mishra <[email protected]>
AuthorDate: Thu Jun 18 07:08:09 2026 +0000
nshlib: Add su, id, and whoami identity commands
Add NSH commands for switching effective credentials and inspecting
session identity. Update login and prompt to reflect effective user.
Signed-off-by: Abhishek Mishra <[email protected]>
---
nshlib/CMakeLists.txt | 4 +
nshlib/Kconfig | 46 +++++
nshlib/Makefile | 4 +
nshlib/nsh.h | 13 ++
nshlib/nsh_command.c | 12 ++
nshlib/nsh_fscmds.c | 48 ++++-
nshlib/nsh_identity.c | 453 +++++++++++++++++++++++++++++++++++++++++++++++
nshlib/nsh_login.c | 11 ++
nshlib/nsh_parse.c | 1 +
nshlib/nsh_prompt.c | 24 +++
nshlib/nsh_telnetlogin.c | 11 ++
11 files changed, 625 insertions(+), 2 deletions(-)
diff --git a/nshlib/CMakeLists.txt b/nshlib/CMakeLists.txt
index 86b1b06ae..8adab3168 100644
--- a/nshlib/CMakeLists.txt
+++ b/nshlib/CMakeLists.txt
@@ -42,6 +42,10 @@ if(CONFIG_NSH_LIBRARY)
nsh_syscmds.c
nsh_dbgcmds.c)
+ if(CONFIG_SCHED_USER_IDENTITY)
+ list(APPEND CSRCS nsh_identity.c)
+ endif()
+
list(APPEND CSRCS nsh_session.c)
if(CONFIG_NSH_CONSOLE_LOGIN)
diff --git a/nshlib/Kconfig b/nshlib/Kconfig
index 2d1570b87..80476e7f5 100644
--- a/nshlib/Kconfig
+++ b/nshlib/Kconfig
@@ -69,6 +69,24 @@ config NSH_PROMPT_STRING
Provide the shell prompt string with size limit NSH_PROMPT_MAX.
default is "nsh> ".
+config NSH_PROMPT_STRING_ROOT
+ string "Prompt string for effective root (euid=0)"
+ default ""
+ depends on SCHED_USER_IDENTITY
+ ---help---
+ If non-empty, NSH uses this prompt when the effective UID is
zero.
+ If empty, the prompt from NSH_PROMPT_STRING (or ENV/HOSTNAME)
is used.
+ Set explicitly for multi-user shells (for example, "nsh# ").
+
+config NSH_PROMPT_STRING_USER
+ string "Prompt string for non-root effective UID"
+ default ""
+ depends on SCHED_USER_IDENTITY
+ ---help---
+ If non-empty, NSH uses this prompt when the effective UID is
non-zero.
+ If empty, the prompt from NSH_PROMPT_STRING (or ENV/HOSTNAME)
is used.
+ Set explicitly for multi-user shells (for example, "nsh$ ").
+
config NSH_PROMPT_MAX
int "Maximum Size of Prompt String"
default NAME_MAX
@@ -351,6 +369,21 @@ config NSH_DISABLE_CHOWN
default DEFAULT_SMALL
depends on FS_PERMISSION
+config NSH_DISABLE_SU
+ bool "Disable su"
+ default DEFAULT_SMALL
+ depends on SCHED_USER_IDENTITY
+
+config NSH_DISABLE_ID
+ bool "Disable id"
+ default DEFAULT_SMALL
+ depends on SCHED_USER_IDENTITY
+
+config NSH_DISABLE_WHOAMI
+ bool "Disable whoami"
+ default DEFAULT_SMALL
+ depends on SCHED_USER_IDENTITY
+
config NSH_DISABLE_CP
bool "Disable cp"
default DEFAULT_SMALL
@@ -1259,6 +1292,19 @@ config NSH_LOGIN_FAILCOUNT
---help---
Number of login retry attempts.
+config NSH_LOGIN_SETUID
+ bool "Set user identity after successful login"
+ default y
+ depends on SCHED_USER_IDENTITY
+ ---help---
+ After a successful NSH login, look up the authenticated user
name
+ in the passwd database and call setuid()/setgid() so that the
shell
+ session runs with that user's credentials.
+
+ When CONFIG_LIBC_PASSWD_FILE is enabled, any user listed in the
+ passwd file may be selected. Otherwise only the built-in "root"
+ account is supported.
+
config NSH_PLATFORM_CHALLENGE
bool "Platform challenge"
default n
diff --git a/nshlib/Makefile b/nshlib/Makefile
index 26dbbd0de..d15ca4aa3 100644
--- a/nshlib/Makefile
+++ b/nshlib/Makefile
@@ -28,6 +28,10 @@ CSRCS = nsh_init.c nsh_parse.c nsh_console.c nsh_script.c
nsh_system.c
CSRCS += nsh_command.c nsh_fscmds.c nsh_proccmds.c nsh_mmcmds.c
CSRCS += nsh_timcmds.c nsh_envcmds.c nsh_syscmds.c nsh_dbgcmds.c nsh_prompt.c
+ifeq ($(CONFIG_SCHED_USER_IDENTITY),y)
+CSRCS += nsh_identity.c
+endif
+
CSRCS += nsh_session.c
ifeq ($(CONFIG_NSH_CONSOLE_LOGIN),y)
CSRCS += nsh_login.c
diff --git a/nshlib/nsh.h b/nshlib/nsh.h
index 7abb7c38f..f20fcf773 100644
--- a/nshlib/nsh.h
+++ b/nshlib/nsh.h
@@ -750,6 +750,7 @@ extern const char g_userprompt[];
extern const char g_passwordprompt[];
extern const char g_loginsuccess[];
extern const char g_badcredentials[];
+extern const char g_badidentity[];
extern const char g_loginfailure[];
#endif
extern const char g_fmtsyntax[];
@@ -969,6 +970,18 @@ int cmd_irqinfo(FAR struct nsh_vtbl_s *vtbl, int argc, FAR
char **argv);
#if defined(CONFIG_FS_PERMISSION) && !defined(CONFIG_NSH_DISABLE_CHOWN)
int cmd_chown(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
#endif
+#ifdef CONFIG_SCHED_USER_IDENTITY
+ int nsh_setuser_identity(FAR const char *username);
+# ifndef CONFIG_NSH_DISABLE_SU
+ int cmd_su(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_ID
+ int cmd_id(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
+# endif
+# ifndef CONFIG_NSH_DISABLE_WHOAMI
+ int cmd_whoami(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
+# endif
+#endif
#ifndef CONFIG_NSH_DISABLE_CP
int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv);
#endif
diff --git a/nshlib/nsh_command.c b/nshlib/nsh_command.c
index 23534fbe5..a50e223c9 100644
--- a/nshlib/nsh_command.c
+++ b/nshlib/nsh_command.c
@@ -256,6 +256,10 @@ static const struct cmdmap_s g_cmdmap[] =
CMD_MAP("free", cmd_free, 1, 1, NULL),
#endif
+#if defined(CONFIG_SCHED_USER_IDENTITY) && !defined(CONFIG_NSH_DISABLE_ID)
+ CMD_MAP("id", cmd_id, 1, 1, NULL),
+#endif
+
#ifdef CONFIG_DEBUG_MM
# ifndef CONFIG_NSH_DISABLE_MEMDUMP
CMD_MAP("memdump", cmd_memdump,
@@ -571,6 +575,10 @@ static const struct cmdmap_s g_cmdmap[] =
#endif
#endif /* CONFIG_NSH_DISABLE_SET */
+#if defined(CONFIG_SCHED_USER_IDENTITY) && !defined(CONFIG_NSH_DISABLE_SU)
+ CMD_MAP("su", cmd_su, 1, 2, "[<username>]"),
+#endif
+
#ifndef CONFIG_NSH_DISABLE_SHUTDOWN
#if defined(CONFIG_BOARDCTL_POWEROFF) && defined(CONFIG_BOARDCTL_RESET)
CMD_MAP("shutdown", cmd_shutdown, 1, 2, "[--reboot]"),
@@ -635,6 +643,10 @@ static const struct cmdmap_s g_cmdmap[] =
# endif
#endif
+#if defined(CONFIG_SCHED_USER_IDENTITY) && !defined(CONFIG_NSH_DISABLE_WHOAMI)
+ CMD_MAP("whoami", cmd_whoami, 1, 1, NULL),
+#endif
+
#ifndef CONFIG_NSH_DISABLE_UNAME
# ifdef CONFIG_NET
CMD_MAP("uname", cmd_uname, 1, 7, "[-a | -imnoprsv]"),
diff --git a/nshlib/nsh_fscmds.c b/nshlib/nsh_fscmds.c
index 13daa8258..797048f6c 100644
--- a/nshlib/nsh_fscmds.c
+++ b/nshlib/nsh_fscmds.c
@@ -45,6 +45,13 @@
#include <errno.h>
#include <nuttx/debug.h>
+#ifdef CONFIG_LIBC_PASSWD_FILE
+# include <pwd.h>
+#endif
+#ifdef CONFIG_LIBC_GROUP_FILE
+# include <grp.h>
+#endif
+
#include "nsh.h"
#if !defined(CONFIG_DISABLE_MOUNTPOINT)
@@ -340,6 +347,44 @@ static inline int ls_specialdir(FAR const char *dir)
return (strcmp(dir, ".") == 0 || strcmp(dir, "..") == 0);
}
+
+#ifdef CONFIG_SCHED_USER_IDENTITY
+/****************************************************************************
+ * Name: nsh_ls_printowner
+ ****************************************************************************/
+
+static void nsh_ls_printowner(FAR struct nsh_vtbl_s *vtbl, uid_t uid,
+ gid_t gid)
+{
+#ifdef CONFIG_LIBC_PASSWD_FILE
+ FAR struct passwd *pwd;
+
+ pwd = getpwuid(uid);
+ if (pwd != NULL && pwd->pw_name != NULL)
+ {
+ nsh_output(vtbl, "%8s", pwd->pw_name);
+ }
+ else
+#endif
+ {
+ nsh_output(vtbl, "%8d", (int)uid);
+ }
+
+#ifdef CONFIG_LIBC_GROUP_FILE
+ FAR struct group *grp;
+
+ grp = getgrgid(gid);
+ if (grp != NULL && grp->gr_name != NULL)
+ {
+ nsh_output(vtbl, "%8s", grp->gr_name);
+ }
+ else
+#endif
+ {
+ nsh_output(vtbl, "%8d", (int)gid);
+ }
+}
+#endif /* CONFIG_SCHED_USER_IDENTITY */
#endif
/****************************************************************************
@@ -511,8 +556,7 @@ static int ls_handler(FAR struct nsh_vtbl_s *vtbl, FAR
const char *dirpath,
#ifdef CONFIG_SCHED_USER_IDENTITY
if ((lsflags & LSFLAGS_UID_GID) != 0)
{
- nsh_output(vtbl, "%8d", buf.st_uid);
- nsh_output(vtbl, "%8d", buf.st_gid);
+ nsh_ls_printowner(vtbl, buf.st_uid, buf.st_gid);
}
#endif
diff --git a/nshlib/nsh_identity.c b/nshlib/nsh_identity.c
new file mode 100644
index 000000000..e69fd92e2
--- /dev/null
+++ b/nshlib/nsh_identity.c
@@ -0,0 +1,453 @@
+/****************************************************************************
+ * apps/nshlib/nsh_identity.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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 <errno.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+
+#ifdef CONFIG_NSH_CLE
+# include "system/cle.h"
+#else
+# include "system/readline.h"
+#endif
+
+#ifdef CONFIG_NSH_LOGIN_PASSWD
+# include "fsutils/passwd.h"
+#endif
+
+#include "nshlib/nshlib.h"
+#include "nsh.h"
+#include "nsh_console.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_is_privileged
+ *
+ * Description:
+ * Return true if the caller has root privileges (effective UID or GID is
+ * zero). NuttX does not support supplementary groups; membership in the
+ * root group is indicated by a primary GID of zero.
+ *
+ ****************************************************************************/
+
+static bool nsh_is_privileged(void)
+{
+ return geteuid() == 0 || getegid() == 0;
+}
+
+#ifdef CONFIG_LIBC_PASSWD_FILE
+
+/****************************************************************************
+ * Name: nsh_lookup_user
+ *
+ * Description:
+ * Look up a passwd entry by name using re-entrant libc helpers.
+ *
+ ****************************************************************************/
+
+static int nsh_lookup_user(FAR const char *username, uid_t *uid, gid_t *gid)
+{
+ struct passwd pwd;
+ struct passwd *result;
+ char buf[CONFIG_LIBC_PASSWD_LINESIZE];
+ int ret;
+
+ ret = getpwnam_r(username, &pwd, buf, sizeof(buf), &result);
+ if (ret != 0)
+ {
+ return -ret;
+ }
+
+ if (result == NULL)
+ {
+ return -ENOENT;
+ }
+
+ *uid = result->pw_uid;
+ *gid = result->pw_gid;
+ return OK;
+}
+#endif /* CONFIG_LIBC_PASSWD_FILE */
+
+#ifdef CONFIG_NSH_LOGIN
+
+/****************************************************************************
+ * Name: nsh_read_password
+ ****************************************************************************/
+
+static int nsh_read_password(FAR struct nsh_vtbl_s *vtbl,
+ FAR char *password, size_t buflen)
+{
+ FAR struct console_stdio_s *pstate = (FAR struct console_stdio_s *)vtbl;
+ struct termios cfg;
+ int ret;
+
+ write(OUTFD(pstate), g_passwordprompt, strlen(g_passwordprompt));
+
+ if (isatty(INFD(pstate)))
+ {
+ if (tcgetattr(INFD(pstate), &cfg) == 0)
+ {
+ cfg.c_lflag &= ~ECHO;
+ tcsetattr(INFD(pstate), TCSANOW, &cfg);
+ }
+ }
+
+ password[0] = '\0';
+ pstate->cn_line[0] = '\0';
+
+#ifdef CONFIG_NSH_CLE
+ ret = cle_fd(pstate->cn_line, "", LINE_MAX,
+ INFD(pstate), OUTFD(pstate));
+#else
+ ret = readline_fd(pstate->cn_line, LINE_MAX, INFD(pstate), -1);
+#endif
+
+ if (isatty(INFD(pstate)))
+ {
+ if (tcgetattr(INFD(pstate), &cfg) == 0)
+ {
+ cfg.c_lflag |= ECHO;
+ tcsetattr(INFD(pstate), TCSANOW, &cfg);
+ }
+ }
+
+ if (ret > 0)
+ {
+ strlcpy(password, pstate->cn_line, buflen);
+ write(OUTFD(pstate), "\n", 1);
+ return OK;
+ }
+
+ return ERROR;
+}
+
+/****************************************************************************
+ * Name: nsh_verify_credentials
+ ****************************************************************************/
+
+static bool nsh_verify_credentials(FAR const char *username,
+ FAR const char *password)
+{
+#ifdef CONFIG_NSH_LOGIN_PASSWD
+ return PASSWORD_VERIFY_MATCH(passwd_verify(username, password));
+#elif defined(CONFIG_NSH_LOGIN_PLATFORM)
+ return PASSWORD_VERIFY_MATCH(platform_user_verify(username, password));
+#elif defined(CONFIG_NSH_LOGIN_FIXED)
+ return strcmp(password, CONFIG_NSH_LOGIN_PASSWORD) == 0 &&
+ strcmp(username, CONFIG_NSH_LOGIN_USERNAME) == 0;
+#else
+ UNUSED(username);
+ UNUSED(password);
+ return false;
+#endif
+}
+#endif /* CONFIG_NSH_LOGIN */
+
+/****************************************************************************
+ * Name: nsh_switch_credentials
+ *
+ * Description:
+ * Switch the session to the given UID/GID. NSH starts with real UID/GID
+ * zero; file permission checks use the effective identity. When the real
+ * UID is still zero, only the effective UID/GID are changed so that a
+ * later 'su' can regain root via seteuid(0) after password verification.
+ *
+ ****************************************************************************/
+
+static int nsh_switch_credentials(uid_t uid, gid_t gid)
+{
+ if (getuid() == 0)
+ {
+ if (geteuid() != 0 || getegid() != 0)
+ {
+ if (seteuid(0) != 0 || setegid(0) != 0)
+ {
+ return -errno;
+ }
+ }
+
+ if (seteuid(uid) != 0 || setegid(gid) != 0)
+ {
+ return -errno;
+ }
+
+ return OK;
+ }
+
+ if (setuid(uid) != 0 || setgid(gid) != 0)
+ {
+ return -errno;
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nsh_setuser_identity
+ *
+ * Description:
+ * Look up 'username' in the passwd database and set the calling task's
+ * session identity. When NSH still has real UID zero, only the effective
+ * UID/GID are updated so that 'su' can switch users later.
+ *
+ * Input Parameters:
+ * username - Login name to assume
+ *
+ * Returned Value:
+ * OK on success; negated errno on failure.
+ *
+ ****************************************************************************/
+
+int nsh_setuser_identity(FAR const char *username)
+{
+#ifdef CONFIG_LIBC_PASSWD_FILE
+ FAR struct passwd *pwd;
+ uid_t uid;
+ gid_t gid;
+
+ /* getpwnam() uses libc static storage; NSH is single-threaded here. */
+
+ pwd = getpwnam(username);
+ if (pwd == NULL)
+ {
+ return -ENOENT;
+ }
+
+ uid = pwd->pw_uid;
+ gid = pwd->pw_gid;
+#else
+ uid_t uid;
+ gid_t gid;
+
+ if (strcmp(username, "root") != 0)
+ {
+ return -ENOENT;
+ }
+
+ uid = 0;
+ gid = 0;
+#endif
+
+ return nsh_switch_credentials(uid, gid);
+}
+
+/****************************************************************************
+ * Name: cmd_su
+ *
+ * Description:
+ * su [username]
+ *
+ * Switch the NSH session to the credentials of 'username'. Callers with
+ * root privileges (effective UID or GID zero) may switch to any user
+ * without a password. Other users may switch to their own identity
+ * without a password, or to another user after entering that user's
+ * password.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_SU
+int cmd_su(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
+{
+ char username_buf[48];
+ FAR const char *username;
+ uid_t target_uid;
+ gid_t target_gid;
+ int ret;
+ bool need_password = false;
+
+ if (argc > 2)
+ {
+ nsh_error(vtbl, g_fmtarginvalid, argv[0]);
+ return ERROR;
+ }
+
+ if (argc == 1)
+ {
+ username = "root";
+ }
+ else
+ {
+ /* argv[1] points into cn_line; copy it before readline reuses that
+ * buffer for the password prompt.
+ */
+
+ strlcpy(username_buf, argv[1], sizeof(username_buf));
+ username = username_buf;
+ }
+
+#ifdef CONFIG_LIBC_PASSWD_FILE
+ ret = nsh_lookup_user(username, &target_uid, &target_gid);
+ if (ret == -ENOENT)
+ {
+ nsh_error(vtbl, "su: Unknown user '%s'\n", username);
+ return ERROR;
+ }
+ else if (ret < 0)
+ {
+ nsh_error(vtbl, "su: Permission denied\n");
+ return ERROR;
+ }
+#else
+ if (strcmp(username, "root") != 0)
+ {
+ nsh_error(vtbl, "su: Unknown user '%s'\n", username);
+ return ERROR;
+ }
+
+ target_uid = 0;
+ target_gid = 0;
+#endif
+
+ if (!nsh_is_privileged())
+ {
+#ifdef CONFIG_LIBC_PASSWD_FILE
+ if (target_uid != geteuid())
+ {
+ need_password = true;
+ }
+#else
+ need_password = true;
+#endif
+ }
+
+#ifdef CONFIG_NSH_LOGIN
+ if (need_password)
+ {
+ char password[LINE_MAX];
+
+ ret = nsh_read_password(vtbl, password, sizeof(password));
+ if (ret < 0)
+ {
+ return ERROR;
+ }
+
+ if (!nsh_verify_credentials(username, password))
+ {
+ nsh_error(vtbl, "su: Authentication failure\n");
+ return ERROR;
+ }
+ }
+#else
+ if (need_password)
+ {
+ nsh_error(vtbl, "su: Permission denied\n");
+ return ERROR;
+ }
+#endif
+
+ ret = nsh_switch_credentials(target_uid, target_gid);
+ if (ret < 0)
+ {
+ nsh_error(vtbl, "su: Permission denied\n");
+ return ERROR;
+ }
+
+ nsh_update_prompt();
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_id
+ *
+ * Description:
+ * Print real and effective UID/GID for the current session.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_ID
+int cmd_id(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
+{
+ if (argc != 1)
+ {
+ nsh_error(vtbl, g_fmtarginvalid, argv[0]);
+ return ERROR;
+ }
+
+ nsh_output(vtbl, "uid=%d euid=%d gid=%d egid=%d\n",
+ getuid(), geteuid(), getgid(), getegid());
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: cmd_whoami
+ *
+ * Description:
+ * Print the user name for the effective UID.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_WHOAMI
+int cmd_whoami(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
+{
+ uid_t euid;
+
+ if (argc != 1)
+ {
+ nsh_error(vtbl, g_fmtarginvalid, argv[0]);
+ return ERROR;
+ }
+
+ euid = geteuid();
+
+#ifdef CONFIG_LIBC_PASSWD_FILE
+ FAR struct passwd *pwd;
+
+ pwd = getpwuid(euid);
+ if (pwd != NULL && pwd->pw_name != NULL)
+ {
+ nsh_output(vtbl, "%s\n", pwd->pw_name);
+ return OK;
+ }
+#endif
+
+ if (euid == 0)
+ {
+ nsh_output(vtbl, "root\n");
+ }
+ else
+ {
+ nsh_output(vtbl, "%d\n", (int)euid);
+ }
+
+ return OK;
+}
+#endif
diff --git a/nshlib/nsh_login.c b/nshlib/nsh_login.c
index cde17f55c..6630a1689 100644
--- a/nshlib/nsh_login.c
+++ b/nshlib/nsh_login.c
@@ -30,6 +30,7 @@
#include <ctype.h>
#include <unistd.h>
#include <termios.h>
+#include <errno.h>
#include "fsutils/passwd.h"
#ifdef CONFIG_NSH_CLE
@@ -250,6 +251,16 @@ int nsh_login(FAR struct console_stdio_s *pstate)
#endif
{
write(OUTFD(pstate), g_loginsuccess, strlen(g_loginsuccess));
+
+#if defined(CONFIG_NSH_LOGIN_SETUID) && defined(CONFIG_SCHED_USER_IDENTITY)
+ if (nsh_setuser_identity(username) < 0)
+ {
+ write(OUTFD(pstate), g_badidentity, strlen(g_badidentity));
+ return -1;
+ }
+
+ nsh_update_prompt();
+#endif
return OK;
}
else
diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c
index 61ed7de55..9de45b887 100644
--- a/nshlib/nsh_parse.c
+++ b/nshlib/nsh_parse.c
@@ -316,6 +316,7 @@ 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_badidentity[] = "\nUnknown user identity\n";
const char g_loginfailure[] = "Login failed!\n";
#endif
diff --git a/nshlib/nsh_prompt.c b/nshlib/nsh_prompt.c
index 4dfe24c3c..04f110a83 100644
--- a/nshlib/nsh_prompt.c
+++ b/nshlib/nsh_prompt.c
@@ -30,6 +30,10 @@
#include <stdlib.h>
#include <assert.h>
+#ifdef CONFIG_SCHED_USER_IDENTITY
+# include <unistd.h>
+#endif
+
#include "nsh.h"
/****************************************************************************
@@ -59,6 +63,10 @@ static char g_nshprompt[CONFIG_NSH_PROMPT_MAX] =
CONFIG_NSH_PROMPT_STRING;
* - non-empty NSH_PROMPT_STRING
* - non-empty HOSTNAME and suffix
*
+ * When SCHED_USER_IDENTITY is enabled and NSH_PROMPT_STRING_ROOT or
+ * NSH_PROMPT_STRING_USER are non-empty, the prompt for the current
+ * effective UID replaces the value from the sources above.
+ *
* Note that suffix has higher priority when used to help clearly separate
* prompts from command line inputs.
*
@@ -90,6 +98,22 @@ void nsh_update_prompt(void)
gethostname(g_nshprompt, NSH_PROMPT_SIZE);
strcat(g_nshprompt, CONFIG_NSH_PROMPT_SUFFIX);
}
+
+#ifdef CONFIG_SCHED_USER_IDENTITY
+ if (geteuid() == 0)
+ {
+ if (CONFIG_NSH_PROMPT_STRING_ROOT[0] != '\0')
+ {
+ strlcpy(g_nshprompt, CONFIG_NSH_PROMPT_STRING_ROOT,
+ CONFIG_NSH_PROMPT_MAX);
+ }
+ }
+ else if (CONFIG_NSH_PROMPT_STRING_USER[0] != '\0')
+ {
+ strlcpy(g_nshprompt, CONFIG_NSH_PROMPT_STRING_USER,
+ CONFIG_NSH_PROMPT_MAX);
+ }
+#endif
}
/****************************************************************************
diff --git a/nshlib/nsh_telnetlogin.c b/nshlib/nsh_telnetlogin.c
index 417ffda68..c796b2a36 100644
--- a/nshlib/nsh_telnetlogin.c
+++ b/nshlib/nsh_telnetlogin.c
@@ -30,6 +30,7 @@
#include <ctype.h>
#include <unistd.h>
#include <termios.h>
+#include <errno.h>
#include "fsutils/passwd.h"
@@ -255,6 +256,16 @@ int nsh_telnetlogin(FAR struct console_stdio_s *pstate)
#endif
{
write(OUTFD(pstate), g_loginsuccess, strlen(g_loginsuccess));
+
+#if defined(CONFIG_NSH_LOGIN_SETUID) && defined(CONFIG_SCHED_USER_IDENTITY)
+ if (nsh_setuser_identity(username) < 0)
+ {
+ write(OUTFD(pstate), g_badidentity, strlen(g_badidentity));
+ return -1;
+ }
+
+ nsh_update_prompt();
+#endif
return OK;
}
else