xiaoxiang781216 commented on code in PR #19767:
URL: https://github.com/apache/nuttx/pull/19767#discussion_r3754955131


##########
sched/group/group_setgroups.c:
##########
@@ -0,0 +1,114 @@
+/****************************************************************************
+ * sched/group/group_setgroups.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 <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sched/sched.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: setgroups
+ *
+ * Description:
+ *   setgroups() sets the supplementary group IDs for the calling process.
+ *   Only a process with an effective user ID of 0 may change the list.
+ *
+ * Input Parameters:
+ *   size - Number of group IDs in list (0 to clear).
+ *   list - Array of supplementary group IDs, or NULL when size is 0.
+ *
+ * Returned Value:
+ *   Zero on success; -1 on failure with errno set.
+ *
+ ****************************************************************************/
+
+int setgroups(int size, FAR const gid_t *list)
+{
+  FAR struct tcb_s *rtcb;
+  FAR struct task_group_s *rgroup;
+  int i;
+
+  if (size < 0
+#if CONFIG_SCHED_NGROUPS > 0
+      || size > CONFIG_SCHED_NGROUPS
+#else
+      || size > 0
+#endif
+     )
+    {
+      set_errno(EINVAL);
+      return ERROR;
+    }
+
+  if (size > 0 && list == NULL)
+    {
+      set_errno(EFAULT);
+      return ERROR;
+    }
+
+  rtcb   = this_task();
+  rgroup = rtcb->group;
+  DEBUGASSERT(rgroup != NULL);
+
+  /* Only root (effective UID 0) may install a new supplementary set. */
+
+  if (rgroup->tg_euid != 0)
+    {
+      set_errno(EPERM);
+      return ERROR;
+    }
+
+#if CONFIG_SCHED_NGROUPS > 0
+  for (i = 0; i < size; i++)
+    {
+      if ((uint16_t)list[i] > INT16_MAX)

Review Comment:
   why add this check



##########
binfmt/binfmt_checkexec.c:
##########
@@ -57,6 +57,7 @@
 int binfmt_checkexecperm(FAR struct binary_s *bin)
 {
   FAR struct tcb_s *rtcb;
+  FAR struct task_group_s *tgroup;

Review Comment:
   rgroup or group



##########
sched/group/group_setgroups.c:
##########
@@ -0,0 +1,114 @@
+/****************************************************************************
+ * sched/group/group_setgroups.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 <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sched/sched.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: setgroups
+ *
+ * Description:
+ *   setgroups() sets the supplementary group IDs for the calling process.
+ *   Only a process with an effective user ID of 0 may change the list.
+ *
+ * Input Parameters:
+ *   size - Number of group IDs in list (0 to clear).
+ *   list - Array of supplementary group IDs, or NULL when size is 0.
+ *
+ * Returned Value:
+ *   Zero on success; -1 on failure with errno set.
+ *
+ ****************************************************************************/
+
+int setgroups(int size, FAR const gid_t *list)
+{
+  FAR struct tcb_s *rtcb;
+  FAR struct task_group_s *rgroup;
+  int i;
+
+  if (size < 0
+#if CONFIG_SCHED_NGROUPS > 0
+      || size > CONFIG_SCHED_NGROUPS
+#else
+      || size > 0
+#endif
+     )
+    {
+      set_errno(EINVAL);
+      return ERROR;
+    }
+
+  if (size > 0 && list == NULL)
+    {
+      set_errno(EFAULT);
+      return ERROR;
+    }
+
+  rtcb   = this_task();
+  rgroup = rtcb->group;
+  DEBUGASSERT(rgroup != NULL);
+
+  /* Only root (effective UID 0) may install a new supplementary set. */
+
+  if (rgroup->tg_euid != 0)
+    {
+      set_errno(EPERM);
+      return ERROR;
+    }
+
+#if CONFIG_SCHED_NGROUPS > 0
+  for (i = 0; i < size; i++)
+    {
+      if ((uint16_t)list[i] > INT16_MAX)
+        {
+          set_errno(EINVAL);
+          return ERROR;
+        }
+    }
+
+  if (size > 0)
+    {
+      memcpy(rgroup->tg_groups, list, size * sizeof(gid_t));
+    }
+
+  rgroup->tg_ngroups = size;
+#else

Review Comment:
   move the dummy code to libc too



##########
include/limits.h:
##########
@@ -124,7 +124,11 @@
 #define _POSIX_MAX_CANON      255
 #define _POSIX_MAX_INPUT      255
 #define _POSIX_NAME_MAX       CONFIG_NAME_MAX
-#define _POSIX_NGROUPS_MAX    0
+#if defined(CONFIG_SCHED_USER_IDENTITY) && CONFIG_SCHED_NGROUPS > 0

Review Comment:
   CONFIG_SCHED_USER_IDENTITY->CONFIG_SCHED_NGROUPS 



##########
sched/group/group_setresgid.c:
##########
@@ -0,0 +1,100 @@
+/****************************************************************************
+ * sched/group/group_setresgid.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 <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sched/sched.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: setresgid
+ *
+ * Description:
+ *   setresgid() sets the real, effective, and saved set-group-IDs of the
+ *   calling process.  The value (gid_t)-1
+ *   for any argument leaves that ID unchanged.
+ *
+ ****************************************************************************/
+
+int setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+{
+  FAR struct tcb_s *rtcb;
+  FAR struct task_group_s *rgroup;
+  gid_t old_rgid;
+  gid_t old_egid;
+  gid_t old_sgid;
+  gid_t new_rgid;
+  gid_t new_egid;
+  gid_t new_sgid;
+
+  if ((rgid != (gid_t)-1 && (uint16_t)rgid > INT16_MAX) ||

Review Comment:
   why limit to INT16_MAX



##########
include/nuttx/sched.h:
##########
@@ -562,6 +566,42 @@ struct task_group_s
   rmutex_t   tg_mutex;              /* Mutex for group */
 };
 
+/****************************************************************************
+ * Name: group_has_gid
+ *
+ * Description:
+ *   Return true if the task group matches 'gid' via the effective GID or any
+ *   supplementary group ID.
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_USER_IDENTITY
+static inline_function bool group_has_gid(FAR struct task_group_s *group,

Review Comment:
   ```
   nxsched_has_gid(FAR struct tcb_s *tcb, gid_t gid)
   ```



##########
sched/group/group_getgroups.c:
##########
@@ -0,0 +1,107 @@
+/****************************************************************************
+ * sched/group/group_getgroups.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 <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sched/sched.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: getgroups
+ *
+ * Description:
+ *   getgroups() returns the supplementary group IDs of the calling
+ *   process.  The returned list is exactly the set installed by
+ *   setgroups()/initgroups() (may be empty).  The effective group ID is
+ *   not synthesized into an empty list; callers that need it should use
+ *   getegid().
+ *
+ * Input Parameters:
+ *   gidsetsize - Number of slots in grouplist, or 0 to query the count.
+ *   grouplist  - Buffer for group IDs (unused when gidsetsize is 0).
+ *
+ * Returned Value:
+ *   Number of group IDs on success; -1 on failure with errno set.
+ *
+ ****************************************************************************/
+
+int getgroups(int gidsetsize, FAR gid_t grouplist[])
+{
+  FAR struct tcb_s *rtcb;
+  FAR struct task_group_s *rgroup;
+  int count;
+
+  if (gidsetsize < 0)
+    {
+      set_errno(EINVAL);
+      return ERROR;
+    }
+
+  rtcb   = this_task();
+  rgroup = rtcb->group;
+  DEBUGASSERT(rgroup != NULL);
+
+#if CONFIG_SCHED_NGROUPS > 0

Review Comment:
   should we move the code related to `CONFIG_SCHED_NGROUPS == 0` to libc?



##########
include/nuttx/sched.h:
##########
@@ -120,7 +120,7 @@
 #define GROUP_FLAG_FD_BACKTRACE    (1 << 4)                      /* Bit 4: 
Enable FD backtrace for the group */
 #define GROUP_FLAG_SECURE_EXEC     (1 << 5)                      /* Bit 5: 
Secure (setuid/setgid) executable */
 #define GROUP_FLAG_DUMPABLE        (1 << 6)                      /* Bit 6: 
Process may be traced / coredumped */
-                                                                 /* Bit 7: 
Available */
+#define GROUP_FLAG_NSHCRED         (1 << 7)                      /* Bit 7: NSH 
credential agent (login/su) */

Review Comment:
   where use this flag



##########
include/sys/prctl.h:
##########
@@ -79,6 +79,20 @@
 #define PR_SET_DUMPABLE 5
 #define PR_GET_DUMPABLE 6
 
+/* PR_NSHCRED_ENABLE — set GROUP_FLAG_NSHCRED on this task group.
+ * Requires euid == 0.  Not inherited by child task groups.
+ * Required for PR_NSHCRED_AUTHSETEID.
+ *
+ * PR_NSHCRED_AUTHSETEID — verify username/password against the passwd

Review Comment:
   but why move the verify into kernel? it's better to keep it in userspace



##########
fs/inode/fs_inode.c:
##########
@@ -66,9 +66,9 @@ static rw_semaphore_t g_inode_lock = RWSEM_INITIALIZER;
 int fs_checkmode(uid_t owner, gid_t group, mode_t mode, int amode)
 {
   FAR struct tcb_s *rtcb;
+  FAR struct task_group_s *tgroup;

Review Comment:
   ditto



##########
sched/group/group_setresuid.c:
##########
@@ -0,0 +1,101 @@
+/****************************************************************************
+ * sched/group/group_setresuid.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 <sys/types.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sched/sched.h>
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: setresuid
+ *
+ * Description:
+ *   setresuid() sets the real, effective, and saved set-user-IDs of the
+ *   calling process.  The value (uid_t)-1 for any argument leaves that
+ *   ID unchanged.
+ *
+ ****************************************************************************/
+
+int setresuid(uid_t ruid, uid_t euid, uid_t suid)
+{
+  FAR struct tcb_s *rtcb;
+  FAR struct task_group_s *rgroup;
+  uid_t old_ruid;
+  uid_t old_euid;
+  uid_t old_suid;
+  uid_t new_ruid;
+  uid_t new_euid;
+  uid_t new_suid;
+
+  if ((ruid != (uid_t)-1 && (uint16_t)ruid > INT16_MAX) ||

Review Comment:
   ditto



##########
sched/task/task_nshcred_auth.c:
##########
@@ -0,0 +1,515 @@
+/****************************************************************************
+ * sched/task/task_nshcred_auth.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 <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef CONFIG_CRYPTO
+#include <crypto/cryptodev.h>
+#endif
+
+#include <nuttx/fs/fs.h>
+#include <nuttx/kmalloc.h>
+#include <nuttx/sched.h>
+
+#include "sched/sched.h"
+#include "task/task.h"
+
+#ifdef CONFIG_SCHED_USER_IDENTITY
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define NSHCRED_MCF_PREFIX        "$pbkdf2-sha256$"
+#define NSHCRED_SALT_BYTES        16
+#define NSHCRED_HASH_BYTES        32
+#define NSHCRED_MAX_PASSWORD      256
+#define NSHCRED_MAX_USER          64
+#define NSHCRED_IOBUF             512
+
+#if defined(CONFIG_FSUTILS_PASSWD_PATH)
+#  define NSHCRED_PASSWD_PATH CONFIG_FSUTILS_PASSWD_PATH
+#elif defined(CONFIG_LIBC_PASSWD_FILEPATH)
+#  define NSHCRED_PASSWD_PATH CONFIG_LIBC_PASSWD_FILEPATH
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+#ifdef NSHCRED_PASSWD_PATH
+
+/****************************************************************************
+ * Name: nshcred_b64url_decode
+ ****************************************************************************/
+
+static int nshcred_b64url_decode(FAR const char *in, FAR uint8_t *out,
+                                 size_t outlen, FAR size_t *decoded)
+{
+  static const int8_t table[256] =
+  {
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1,
+    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
+    -1,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63,
+    -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+  };
+
+  uint32_t acc = 0;
+  int bits = 0;
+  size_t o = 0;
+  int v;
+
+  while (*in != '\0' && *in != '$' && *in != ':' &&
+         !isspace((unsigned char)*in))
+    {
+      v = table[(uint8_t)*in++];
+      if (v < 0)
+        {
+          return -EINVAL;
+        }
+
+      acc = (acc << 6) | (uint32_t)v;
+      bits += 6;
+      if (bits >= 8)
+        {
+          bits -= 8;
+          if (o >= outlen)
+            {
+              return -E2BIG;
+            }
+
+          out[o++] = (uint8_t)((acc >> bits) & 0xff);
+        }
+    }
+
+  *decoded = o;
+  return OK;
+}
+
+/****************************************************************************
+ * Name: nshcred_ct_equal
+ ****************************************************************************/
+
+static bool nshcred_ct_equal(FAR const uint8_t *a, FAR const uint8_t *b,
+                             size_t n)
+{
+  uint8_t diff = 0;
+  size_t i;
+
+  for (i = 0; i < n; i++)
+    {
+      diff |= a[i] ^ b[i];
+    }
+
+  return diff == 0;
+}
+
+#ifdef CONFIG_CRYPTO
+
+/****************************************************************************
+ * Name: nshcred_pbkdf2
+ *
+ * Description:
+ *   Compute PBKDF2-HMAC-SHA256 via the in-kernel crypto soft backend.
+ *
+ ****************************************************************************/
+
+static int nshcred_pbkdf2(FAR const uint8_t *pass, size_t passlen,
+                          FAR const uint8_t *salt, size_t saltlen,
+                          uint32_t iterations,
+                          FAR uint8_t *out, size_t outlen)
+{
+  struct cryptoini cria;
+  struct cryptodesc crda;
+  struct cryptop crp;
+  uint64_t sid = 0;
+  FAR uint8_t *key = NULL;
+  int ret;
+
+  if (pass == NULL || salt == NULL || out == NULL || passlen == 0 ||
+      saltlen == 0 || iterations == 0 || outlen == 0)
+    {
+      return -EINVAL;
+    }
+
+  key = kmm_malloc(passlen);
+  if (key == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  memcpy(key, pass, passlen);
+
+  memset(&cria, 0, sizeof(cria));
+  cria.cri_alg  = CRYPTO_PBKDF2_HMAC_SHA256;
+  cria.cri_klen = (int)(passlen * 8);
+  cria.cri_key  = (caddr_t)key;
+  cria.cri_sid  = -1;
+
+  ret = crypto_newsession(&sid, &cria, 0);
+  if (ret != 0)
+    {
+      explicit_bzero(key, passlen);
+      kmm_free(key);
+      return ret;
+    }
+
+  memset(&crda, 0, sizeof(crda));
+  memset(&crp, 0, sizeof(crp));
+  crda.crd_skip  = 0;
+  crda.crd_len   = (int)saltlen;
+  crda.crd_inject = 0;
+  crda.crd_alg   = CRYPTO_PBKDF2_HMAC_SHA256;
+  crda.crd_key   = (caddr_t)key;
+  crda.crd_klen  = (int)(passlen * 8);
+
+  crp.crp_desc   = &crda;
+  crp.crp_ilen   = (int)saltlen;
+  crp.crp_olen   = (int)outlen;
+  crp.crp_buf    = (FAR void *)salt;
+  crp.crp_mac    = (caddr_t)out;
+  crp.crp_sid    = sid;
+  crp.crp_iter   = (int)iterations;
+  crp.crp_flags  = CRYPTO_F_IOV | CRYPTO_F_NOQUEUE;
+
+  ret = crypto_invoke(&crp);
+  if (ret == 0 && crp.crp_etype != 0)
+    {
+      ret = crp.crp_etype;
+    }
+
+  crypto_freesession(sid);
+  explicit_bzero(key, passlen);
+  kmm_free(key);
+  return ret;
+}
+#endif /* CONFIG_CRYPTO */
+
+/****************************************************************************
+ * Name: nshcred_find_hash
+ ****************************************************************************/
+
+static int nshcred_find_hash(FAR const char *username,
+                             FAR char *hash, size_t hashlen)
+{
+  struct file f;
+  FAR char *iobuf;
+  FAR char *line;
+  FAR char *colon;
+  FAR char *hash_start;
+  FAR char *hash_end;
+  size_t userlen;
+  size_t used = 0;
+  ssize_t nread;
+  int ret;
+
+  userlen = strlen(username);
+  if (userlen == 0 || userlen >= NSHCRED_MAX_USER)
+    {
+      return -EINVAL;
+    }
+
+  iobuf = kmm_malloc(NSHCRED_IOBUF);
+  if (iobuf == NULL)
+    {
+      return -ENOMEM;
+    }
+
+  ret = file_open(&f, NSHCRED_PASSWD_PATH, O_RDONLY | O_CLOEXEC);
+  if (ret < 0)
+    {
+      kmm_free(iobuf);
+      return ret;
+    }
+
+  hash[0] = '\0';
+  ret = -ENOENT;
+
+  for (; ; )
+    {
+      nread = file_read(&f, iobuf + used, NSHCRED_IOBUF - used - 1);
+      if (nread < 0)
+        {
+          ret = (int)nread;
+          break;
+        }
+
+      if (nread == 0 && used == 0)
+        {
+          break;
+        }
+
+      used += (size_t)nread;
+      iobuf[used] = '\0';
+
+      while ((line = strchr(iobuf, '\n')) != NULL ||
+             (nread == 0 && used > 0))
+        {
+          size_t linelen;
+          size_t rest;
+
+          if (line != NULL)
+            {
+              *line = '\0';
+              linelen = (size_t)(line - iobuf);
+            }
+          else
+            {
+              linelen = used;
+              line = iobuf + used;
+            }
+
+          colon = strchr(iobuf, ':');
+          if (colon != NULL &&
+              (size_t)(colon - iobuf) == userlen &&
+              memcmp(iobuf, username, userlen) == 0)
+            {
+              hash_start = colon + 1;
+              hash_end = strchr(hash_start, ':');
+              if (hash_end == NULL)
+                {
+                  hash_end = hash_start + strlen(hash_start);
+                }
+
+              if ((size_t)(hash_end - hash_start) >= hashlen)
+                {
+                  ret = -ENAMETOOLONG;
+                }
+              else
+                {
+                  memcpy(hash, hash_start, (size_t)(hash_end - hash_start));
+                  hash[hash_end - hash_start] = '\0';
+                  ret = OK;
+                }
+
+              goto done;
+            }
+
+          rest = used - (linelen + (line < iobuf + used ? 1 : 0));
+          if (rest > 0)
+            {
+              memmove(iobuf, line + 1, rest);
+            }
+
+          used = rest;
+          iobuf[used] = '\0';
+
+          if (nread == 0 && used == 0)
+            {
+              break;
+            }
+
+          if (line == NULL)
+            {
+              break;
+            }
+        }
+
+      if (nread == 0)
+        {
+          break;
+        }
+
+      if (used >= NSHCRED_IOBUF - 1)
+        {
+          ret = -E2BIG;
+          break;
+        }
+    }
+
+done:
+  file_close(&f);
+  kmm_free(iobuf);
+  return ret;
+}
+
+/****************************************************************************
+ * Name: nshcred_verify_hash
+ ****************************************************************************/
+
+static int nshcred_verify_hash(FAR const char *stored,
+                               FAR const char *password)
+{
+#ifndef CONFIG_CRYPTO
+  UNUSED(stored);
+  UNUSED(password);
+  return -ENOSYS;
+#else
+  FAR const char *p;
+  FAR const char *salt_b64;
+  FAR const char *hash_b64;
+  FAR char *endptr;
+  uint8_t salt[NSHCRED_SALT_BYTES];
+  uint8_t expected[NSHCRED_HASH_BYTES];
+  uint8_t actual[NSHCRED_HASH_BYTES];
+  size_t saltlen;
+  size_t hashlen;
+  size_t passlen;
+  unsigned long iterations;
+  int ret;
+
+  if (strncmp(stored, NSHCRED_MCF_PREFIX, strlen(NSHCRED_MCF_PREFIX)) != 0)
+    {
+      return -EPERM;
+    }
+
+  p = stored + strlen(NSHCRED_MCF_PREFIX);
+  iterations = strtoul(p, &endptr, 10);
+  if (endptr == p || *endptr != '$' || iterations < 1 ||
+      iterations > 200000)
+    {
+      return -EPERM;
+    }
+
+  salt_b64 = endptr + 1;
+  hash_b64 = strchr(salt_b64, '$');
+  if (hash_b64 == NULL)
+    {
+      return -EPERM;
+    }
+
+  ret = nshcred_b64url_decode(salt_b64, salt, sizeof(salt), &saltlen);
+  if (ret < 0 || saltlen == 0)
+    {
+      return -EPERM;
+    }
+
+  ret = nshcred_b64url_decode(hash_b64 + 1, expected, sizeof(expected),
+                              &hashlen);
+  if (ret < 0 || hashlen != NSHCRED_HASH_BYTES)
+    {
+      return -EPERM;
+    }
+
+  passlen = strlen(password);
+  if (passlen == 0 || passlen > NSHCRED_MAX_PASSWORD)
+    {
+      return -EPERM;
+    }
+
+  ret = nshcred_pbkdf2((FAR const uint8_t *)password, passlen,
+                       salt, saltlen, (uint32_t)iterations,
+                       actual, sizeof(actual));
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  if (!nshcred_ct_equal(actual, expected, sizeof(expected)))
+    {
+      return -EPERM;
+    }
+
+  return OK;
+#endif
+}
+
+#endif /* NSHCRED_PASSWD_PATH */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nshcred_auth_seteid
+ *
+ * Description:
+ *   Verify username/password against the passwd file and, on success,
+ *   set the calling task group's effective UID/GID.  Requires
+ *   GROUP_FLAG_NSHCRED.
+ *
+ * Returned Value:
+ *   0 on success, negated errno on failure.
+ *
+ ****************************************************************************/
+
+int nshcred_auth_seteid(FAR struct task_group_s *group,
+                        FAR const char *username,
+                        FAR const char *password,
+                        uid_t euid, gid_t egid)
+{
+#ifdef NSHCRED_PASSWD_PATH
+  char hash[96];
+  int ret;
+#endif
+
+  if (group == NULL || username == NULL || password == NULL)
+    {
+      return -EINVAL;
+    }
+
+  if ((group->tg_flags & GROUP_FLAG_NSHCRED) == 0)
+    {
+      return -EPERM;
+    }
+
+  if ((uint16_t)euid > INT16_MAX || (uint16_t)egid > INT16_MAX)

Review Comment:
   ditto



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to