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

Reply via email to