Skip to content

Commit 3412e4a

Browse files
boards/sim: enable generated passwd for sim:login
Enable build-time /etc/passwd generation in sim:login by setting\nBOARD_ETC_ROMFS_PASSWD_* defaults in the login defconfig.\n\nAdd password validation for build-time generation:\n- reject empty and quoted-empty passwords\n- enforce minimum length of 8 characters\n- preserve special characters when invoking tools/mkpasswd\n\nApply the same minimum-length validation in the CMake ROMFS path\nand in tools/mkpasswd argument validation.\n\nUpdate Kconfig and documentation to describe the required login\nsetting and password constraints. Signed-off-by: Abhishek Mishra <mishra.abhishek2808@gmail.com>
1 parent d7b5de0 commit 3412e4a

7 files changed

Lines changed: 127 additions & 118 deletions

File tree

Documentation/components/tools/index.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ user-supplied plaintext password at build time, each firmware image carries
3131
unique credentials. The build will fail if the password is left empty,
3232
preventing accidental deployments with no credentials.
3333

34+
For improved baseline security, the configured password must be at least
35+
8 characters long.
36+
3437
How it works
3538
~~~~~~~~~~~~
3639

@@ -52,8 +55,9 @@ Enable the feature and configure credentials via ``make menuconfig``:
5255
.. code:: kconfig
5356
5457
CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y
58+
CONFIG_NSH_CONSOLE_LOGIN=y # required to enforce login prompt
5559
CONFIG_BOARD_ETC_ROMFS_PASSWD_USER="admin" # default: admin
56-
CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD="<secret>" # required, build fails if empty
60+
CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD="<secret>" # required, min length 8
5761
CONFIG_BOARD_ETC_ROMFS_PASSWD_UID=0
5862
CONFIG_BOARD_ETC_ROMFS_PASSWD_GID=0
5963
CONFIG_BOARD_ETC_ROMFS_PASSWD_HOME="/"

Documentation/platforms/sim/sim/boards/sim/index.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2015,8 +2015,9 @@ The ``/etc/passwd`` file is auto-generated at build time when
20152015
credentials via ``make menuconfig``:
20162016

20172017
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y``
2018+
* ``CONFIG_NSH_CONSOLE_LOGIN=y`` (required, otherwise login is not enforced)
20182019
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_USER`` (default: ``admin``)
2019-
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD`` (required, build fails if empty)
2020+
* ``CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD`` (required, build fails if empty or shorter than 8 characters)
20202021

20212022
The password is hashed with TEA at build time by the host tool
20222023
``tools/mkpasswd``; the plaintext is **not** stored in the firmware.

boards/Board.mk

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,35 @@ ifeq ($(CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE),y)
3939
ifeq ($(CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD),)
4040
$(error CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD must be set when BOARD_ETC_ROMFS_PASSWD_ENABLE is enabled. Run 'make menuconfig' to set a password.)
4141
endif
42+
ifeq ($(CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD),"")
43+
$(error CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD must be set when BOARD_ETC_ROMFS_PASSWD_ENABLE is enabled. Run 'make menuconfig' to set a password.)
44+
endif
45+
$(Q) passwd=$(CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD); \
46+
passwd=$${passwd#\"}; \
47+
passwd=$${passwd%\"}; \
48+
if [ $${#passwd} -lt 8 ]; then \
49+
echo "ERROR: CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD must be at least 8 characters."; \
50+
exit 1; \
51+
fi
4252
$(Q) if [ ! -f $(TOPDIR)$(DELIM)tools$(DELIM)mkpasswd$(HOSTEXEEXT) ]; then \
4353
$(MAKE) -C $(TOPDIR)$(DELIM)tools -f Makefile.host mkpasswd$(HOSTEXEEXT); \
4454
fi
4555
$(Q) mkdir -p $(ETCDIR)$(DELIM)$(CONFIG_ETC_ROMFSMOUNTPT)
46-
$(Q) $(TOPDIR)$(DELIM)tools$(DELIM)mkpasswd$(HOSTEXEEXT) \
47-
--user $(CONFIG_BOARD_ETC_ROMFS_PASSWD_USER) \
48-
--password $(CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD) \
56+
$(Q) user=$(CONFIG_BOARD_ETC_ROMFS_PASSWD_USER); \
57+
user=$${user#\"}; \
58+
user=$${user%\"}; \
59+
home=$(CONFIG_BOARD_ETC_ROMFS_PASSWD_HOME); \
60+
home=$${home#\"}; \
61+
home=$${home%\"}; \
62+
passwd=$(CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD); \
63+
passwd=$${passwd#\"}; \
64+
passwd=$${passwd%\"}; \
65+
$(TOPDIR)$(DELIM)tools$(DELIM)mkpasswd$(HOSTEXEEXT) \
66+
--user "$${user}" \
67+
--password "$${passwd}" \
4968
--uid $(CONFIG_BOARD_ETC_ROMFS_PASSWD_UID) \
5069
--gid $(CONFIG_BOARD_ETC_ROMFS_PASSWD_GID) \
51-
--home $(CONFIG_BOARD_ETC_ROMFS_PASSWD_HOME) \
70+
--home "$${home}" \
5271
$(if $(CONFIG_FSUTILS_PASSWD_KEY1),--key1 $(CONFIG_FSUTILS_PASSWD_KEY1)) \
5372
$(if $(CONFIG_FSUTILS_PASSWD_KEY2),--key2 $(CONFIG_FSUTILS_PASSWD_KEY2)) \
5473
$(if $(CONFIG_FSUTILS_PASSWD_KEY3),--key3 $(CONFIG_FSUTILS_PASSWD_KEY3)) \

boards/Kconfig

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5434,7 +5434,8 @@ config BOARD_ETC_ROMFS_PASSWD_PASSWORD
54345434
The plaintext password for the auto-generated /etc/passwd entry.
54355435
This value is hashed with TEA at build time; the plaintext is NOT
54365436
stored in the firmware image. The build will fail if this is left
5437-
empty. Set this via 'make menuconfig'.
5437+
empty or shorter than 8 characters. Set this via
5438+
'make menuconfig'.
54385439

54395440
config BOARD_ETC_ROMFS_PASSWD_UID
54405441
int "Admin user ID"

boards/sim/sim/sim/configs/login/defconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ CONFIG_ARCH_BOARD="sim"
1111
CONFIG_ARCH_BOARD_SIM=y
1212
CONFIG_ARCH_CHIP="sim"
1313
CONFIG_ARCH_SIM=y
14+
CONFIG_BOARD_ETC_ROMFS_PASSWD_ENABLE=y
15+
CONFIG_BOARD_ETC_ROMFS_PASSWD_USER="admin"
16+
CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD="Administrator"
1417
CONFIG_BOARDCTL_APP_SYMTAB=y
1518
CONFIG_BOARDCTL_POWEROFF=y
1619
CONFIG_BOARD_LOOPSPERMSEC=0

cmake/nuttx_add_romfs.cmake

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,13 @@ function(process_all_directory_romfs)
292292
" Run 'make menuconfig' to set a password.")
293293
endif()
294294
295+
string(LENGTH "${CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD}" PASSWD_LEN)
296+
if(PASSWD_LEN LESS 8)
297+
message(
298+
FATAL_ERROR
299+
"CONFIG_BOARD_ETC_ROMFS_PASSWD_PASSWORD must be at least 8 characters.")
300+
endif()
301+
295302
# Determine host executable suffix (.exe on Windows, empty elsewhere)
296303
if(CMAKE_HOST_WIN32)
297304
set(HOST_EXE_SUFFIX .exe)

tools/mkpasswd.c

Lines changed: 85 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
/****************************************************************************
2424
* Description:
2525
* Host build tool that generates a NuttX /etc/passwd entry with a
26-
* TEA-encrypted password hash.
26+
* TEA-encrypted password hash. This is a pure C replacement for the
27+
* former tools/mkpasswd.py, removing the Python dependency from the build.
2728
*
2829
* The encryption algorithm and base64 encoding are identical to those
2930
* used at runtime by:
@@ -68,7 +69,6 @@
6869
#include <stdlib.h>
6970
#include <string.h>
7071
#include <errno.h>
71-
#include <getopt.h>
7272
#include <sys/stat.h>
7373

7474
/****************************************************************************
@@ -79,15 +79,13 @@
7979

8080
#define TEA_KEY_SCHEDULE_CONSTANT 0x9e3779b9u
8181

82-
/* Password size limits – must match apps/fsutils/passwd/passwd.h.
83-
* MAX_ENCRYPTED is the max length of the encrypted hash (ASCII chars).
84-
* MAX_PASSWORD is the max length of the plaintext password.
85-
*/
82+
/* Password size limits – must match apps/fsutils/passwd/passwd.h */
8683

87-
#define MAX_ENCRYPTED 48
88-
#define MAX_PASSWORD (3 * MAX_ENCRYPTED / 4)
84+
#define MAX_ENCRYPTED 48 /* Max size of encrypted password (ASCII) */
85+
#define MAX_PASSWORD (3 * MAX_ENCRYPTED / 4) /* Max plaintext length */
86+
#define MIN_PASSWORD 8 /* Minimum plaintext length for security */
8987

90-
/* Default TEA key values - must match CONFIG_FSUTILS_PASSWD_KEY1-4 defaults
88+
/* Default TEA key values must match CONFIG_FSUTILS_PASSWD_KEY1-4 defaults
9189
* in apps/fsutils/passwd/Kconfig so that the generated hash verifies
9290
* correctly at runtime when the user has not changed the key config.
9391
*/
@@ -364,20 +362,12 @@ static int mkdir_p(const char *path)
364362
if (*p == '/')
365363
{
366364
*p = '\0';
367-
#ifdef CONFIG_WINDOWS_NATIVE
368-
mkdir(tmp);
369-
#else
370365
mkdir(tmp, 0755);
371-
#endif
372366
*p = '/';
373367
}
374368
}
375369

376-
#ifdef CONFIG_WINDOWS_NATIVE
377-
mkdir(tmp);
378-
#else
379370
mkdir(tmp, 0755);
380-
#endif
381371
free(tmp);
382372
return 0;
383373
}
@@ -427,105 +417,81 @@ int main(int argc, char **argv)
427417

428418
char encrypted[MAX_ENCRYPTED + 1];
429419
FILE *out;
430-
int opt;
420+
int i;
431421
int ret;
432422

433-
static const struct option g_long_options[] =
434-
{
435-
{ "user", required_argument, NULL, 'u' },
436-
{ "password", required_argument, NULL, 'p' },
437-
{ "uid", required_argument, NULL, 'i' },
438-
{ "gid", required_argument, NULL, 'g' },
439-
{ "home", required_argument, NULL, 'd' },
440-
{ "key1", required_argument, NULL, '1' },
441-
{ "key2", required_argument, NULL, '2' },
442-
{ "key3", required_argument, NULL, '3' },
443-
{ "key4", required_argument, NULL, '4' },
444-
{ "output", required_argument, NULL, 'o' },
445-
{ "help", no_argument, NULL, 'h' },
446-
{ NULL, 0, NULL, 0 },
447-
};
423+
/* Simple long-option parser (avoids getopt_long portability concerns) */
448424

449-
while ((opt = getopt_long(argc, argv, "u:p:i:g:d:o:h",
450-
g_long_options, NULL)) != -1)
425+
for (i = 1; i < argc; i++)
451426
{
452-
switch (opt)
427+
if (strcmp(argv[i], "--user") == 0 && i + 1 < argc)
428+
{
429+
user = argv[++i];
430+
}
431+
else if (strcmp(argv[i], "--password") == 0 && i + 1 < argc)
432+
{
433+
password = argv[++i];
434+
}
435+
else if (strcmp(argv[i], "--uid") == 0 && i + 1 < argc)
436+
{
437+
uid = atoi(argv[++i]);
438+
}
439+
else if (strcmp(argv[i], "--gid") == 0 && i + 1 < argc)
440+
{
441+
gid = atoi(argv[++i]);
442+
}
443+
else if (strcmp(argv[i], "--home") == 0 && i + 1 < argc)
444+
{
445+
home = argv[++i];
446+
}
447+
else if (strcmp(argv[i], "--key1") == 0 && i + 1 < argc)
448+
{
449+
if (parse_uint32_hex(argv[++i], &key[0]) < 0)
450+
{
451+
fprintf(stderr, "mkpasswd: invalid --key1 value: %s\n", argv[i]);
452+
return 1;
453+
}
454+
}
455+
else if (strcmp(argv[i], "--key2") == 0 && i + 1 < argc)
456+
{
457+
if (parse_uint32_hex(argv[++i], &key[1]) < 0)
458+
{
459+
fprintf(stderr, "mkpasswd: invalid --key2 value: %s\n", argv[i]);
460+
return 1;
461+
}
462+
}
463+
else if (strcmp(argv[i], "--key3") == 0 && i + 1 < argc)
464+
{
465+
if (parse_uint32_hex(argv[++i], &key[2]) < 0)
466+
{
467+
fprintf(stderr, "mkpasswd: invalid --key3 value: %s\n", argv[i]);
468+
return 1;
469+
}
470+
}
471+
else if (strcmp(argv[i], "--key4") == 0 && i + 1 < argc)
472+
{
473+
if (parse_uint32_hex(argv[++i], &key[3]) < 0)
474+
{
475+
fprintf(stderr, "mkpasswd: invalid --key4 value: %s\n", argv[i]);
476+
return 1;
477+
}
478+
}
479+
else if ((strcmp(argv[i], "-o") == 0 ||
480+
strcmp(argv[i], "--output") == 0) && i + 1 < argc)
481+
{
482+
outpath = argv[++i];
483+
}
484+
else if (strcmp(argv[i], "--help") == 0 ||
485+
strcmp(argv[i], "-h") == 0)
486+
{
487+
show_usage(argv[0]);
488+
return 0;
489+
}
490+
else
453491
{
454-
case 'u':
455-
user = optarg;
456-
break;
457-
458-
case 'p':
459-
password = optarg;
460-
break;
461-
462-
case 'i':
463-
uid = atoi(optarg);
464-
break;
465-
466-
case 'g':
467-
gid = atoi(optarg);
468-
break;
469-
470-
case 'd':
471-
home = optarg;
472-
break;
473-
474-
case '1':
475-
if (parse_uint32_hex(optarg, &key[0]) < 0)
476-
{
477-
fprintf(stderr,
478-
"mkpasswd: invalid --key1 value: %s\n",
479-
optarg);
480-
return 1;
481-
}
482-
483-
break;
484-
485-
case '2':
486-
if (parse_uint32_hex(optarg, &key[1]) < 0)
487-
{
488-
fprintf(stderr,
489-
"mkpasswd: invalid --key2 value: %s\n",
490-
optarg);
491-
return 1;
492-
}
493-
494-
break;
495-
496-
case '3':
497-
if (parse_uint32_hex(optarg, &key[2]) < 0)
498-
{
499-
fprintf(stderr,
500-
"mkpasswd: invalid --key3 value: %s\n",
501-
optarg);
502-
return 1;
503-
}
504-
505-
break;
506-
507-
case '4':
508-
if (parse_uint32_hex(optarg, &key[3]) < 0)
509-
{
510-
fprintf(stderr,
511-
"mkpasswd: invalid --key4 value: %s\n",
512-
optarg);
513-
return 1;
514-
}
515-
516-
break;
517-
518-
case 'o':
519-
outpath = optarg;
520-
break;
521-
522-
case 'h':
523-
show_usage(argv[0]);
524-
return 0;
525-
526-
default:
527-
show_usage(argv[0]);
528-
return 1;
492+
fprintf(stderr, "mkpasswd: unknown option: %s\n", argv[i]);
493+
show_usage(argv[0]);
494+
return 1;
529495
}
530496
}
531497

@@ -551,6 +517,14 @@ int main(int argc, char **argv)
551517
return 1;
552518
}
553519

520+
if (strlen(password) < MIN_PASSWORD)
521+
{
522+
fprintf(stderr,
523+
"mkpasswd: --password must be at least %d characters\n",
524+
MIN_PASSWORD);
525+
return 1;
526+
}
527+
554528
/* Encrypt the password using TEA + custom base64.
555529
* Only the hash is written to the output file; the plaintext is never
556530
* stored in firmware.

0 commit comments

Comments
 (0)