aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Config.in9
-rw-r--r--Makefile7
-rw-r--r--Makefile.flags11
-rw-r--r--archival/Config.src11
-rw-r--r--archival/bbunzip.c6
-rw-r--r--archival/cpio.c7
-rw-r--r--archival/libarchive/data_extract_all.c8
-rw-r--r--archival/libarchive/open_transformer.c26
-rw-r--r--archival/libarchive/unsafe_prefix.c6
-rw-r--r--archival/rpm.c9
-rw-r--r--archival/tar.c2
-rw-r--r--configs/mingw32_defconfig15
-rw-r--r--configs/mingw64_defconfig15
-rw-r--r--configs/mingw64a_defconfig15
-rw-r--r--configs/mingw64u_defconfig15
-rw-r--r--coreutils/cut.c455
-rw-r--r--coreutils/df.c33
-rw-r--r--coreutils/expr.c4
-rw-r--r--coreutils/stty.c148
-rw-r--r--coreutils/truncate.c6
-rw-r--r--editors/diff.c2
-rw-r--r--editors/sed.c7
-rw-r--r--findutils/xargs.c6
-rw-r--r--include/libbb.h228
-rw-r--r--include/mingw.h3
-rw-r--r--include/usage.src.h6
-rw-r--r--init/bootchartd.c2
-rw-r--r--init/init.c18
-rw-r--r--libbb/Config.src14
-rw-r--r--libbb/appletlib.c2
-rw-r--r--libbb/bitops.c128
-rw-r--r--libbb/const_hack.c29
-rw-r--r--libbb/dump.c16
-rw-r--r--libbb/getopt32.c17
-rw-r--r--libbb/hash_hmac.c154
-rw-r--r--libbb/hash_md5_sha.c78
-rw-r--r--libbb/hash_sha256_block.c19
-rw-r--r--libbb/hash_sha256_hwaccel_x86-32.S218
-rw-r--r--libbb/hash_sha256_hwaccel_x86-64.S218
-rw-r--r--libbb/lineedit.c112
-rw-r--r--libbb/poll_with_signals.c48
-rw-r--r--libbb/pw_ascii64.c91
-rw-r--r--libbb/pw_encrypt.c113
-rw-r--r--libbb/pw_encrypt_des.c88
-rw-r--r--libbb/pw_encrypt_md5.c4
-rw-r--r--libbb/pw_encrypt_sha.c5
-rw-r--r--libbb/pw_encrypt_yes.c24
-rw-r--r--libbb/read_key.c25
-rw-r--r--libbb/u_signal_names.c4
-rw-r--r--libbb/xfuncs.c2
-rw-r--r--libbb/yescrypt/Kbuild.src9
-rw-r--r--libbb/yescrypt/PARAMETERS196
-rw-r--r--libbb/yescrypt/README4
-rw-r--r--libbb/yescrypt/alg-sha256.c86
-rw-r--r--libbb/yescrypt/alg-yescrypt-common.c408
-rw-r--r--libbb/yescrypt/alg-yescrypt-kdf.c1212
-rw-r--r--libbb/yescrypt/alg-yescrypt.h247
-rw-r--r--libbb/yescrypt/y.c16
-rw-r--r--loginutils/Config.src11
-rw-r--r--loginutils/chpasswd.c2
-rw-r--r--loginutils/cryptpw.c37
-rw-r--r--loginutils/sulogin.c9
-rw-r--r--loginutils/suw32.c18
-rw-r--r--miscutils/crond.c2
-rw-r--r--miscutils/fbsplash.c2
-rw-r--r--miscutils/less.c2
-rw-r--r--miscutils/make.c316
-rw-r--r--miscutils/man.c2
-rw-r--r--networking/Config.src30
-rw-r--r--networking/hostname.c4
-rw-r--r--networking/httpd.c2
-rw-r--r--networking/libiproute/iproute.c16
-rw-r--r--networking/ntpd.c6
-rw-r--r--networking/telnetd.c4
-rw-r--r--networking/tftp.c2
-rw-r--r--networking/tls.c769
-rw-r--r--networking/tls.h7
-rw-r--r--networking/tls_aesgcm.c5
-rw-r--r--networking/udhcp/d6_dhcpc.c193
-rw-r--r--networking/udhcp/d6_packet.c16
-rw-r--r--networking/udhcp/dhcpd.c58
-rw-r--r--runit/chpst.c6
-rw-r--r--scripts/kconfig/libcurses/addch.c36
-rw-r--r--scripts/kconfig/libcurses/addstr.c36
-rw-r--r--scripts/kconfig/libcurses/attr.c62
-rw-r--r--scripts/kconfig/libcurses/beep.c8
-rw-r--r--scripts/kconfig/libcurses/bkgd.c26
-rw-r--r--scripts/kconfig/libcurses/border.c66
-rw-r--r--scripts/kconfig/libcurses/clear.c20
-rw-r--r--scripts/kconfig/libcurses/color.c30
-rw-r--r--scripts/kconfig/libcurses/curses.h35
-rw-r--r--scripts/kconfig/libcurses/getch.c28
-rw-r--r--scripts/kconfig/libcurses/getyx.c32
-rw-r--r--scripts/kconfig/libcurses/inch.c20
-rw-r--r--scripts/kconfig/libcurses/initscr.c24
-rw-r--r--scripts/kconfig/libcurses/inopts.c54
-rw-r--r--scripts/kconfig/libcurses/kernel.c30
-rw-r--r--scripts/kconfig/libcurses/move.c10
-rw-r--r--scripts/kconfig/libcurses/outopts.c36
-rw-r--r--scripts/kconfig/libcurses/overlay.c10
-rw-r--r--scripts/kconfig/libcurses/pad.c18
-rw-r--r--scripts/kconfig/libcurses/pdcclip.c34
-rw-r--r--scripts/kconfig/libcurses/pdcsetsc.c9
-rw-r--r--scripts/kconfig/libcurses/printw.c16
-rw-r--r--scripts/kconfig/libcurses/refresh.c16
-rw-r--r--scripts/kconfig/libcurses/scroll.c10
-rw-r--r--scripts/kconfig/libcurses/slk.c54
-rw-r--r--scripts/kconfig/libcurses/touch.c18
-rw-r--r--scripts/kconfig/libcurses/window.c42
-rwxr-xr-xscripts/kconfig/lxdialog/check-lxdialog.sh2
-rwxr-xr-xscripts/mk_mingw64u_defconfig1
-rw-r--r--shell/Config.src7
-rw-r--r--shell/ash.c39
-rw-r--r--shell/ash_test/ash-read/read_ifs2.right9
-rwxr-xr-xshell/ash_test/ash-read/read_ifs2.tests9
-rw-r--r--shell/ash_test/ash-read/read_t.right8
-rwxr-xr-xshell/ash_test/ash-read/read_t.tests18
-rw-r--r--shell/ash_test/printenv.c4
-rw-r--r--shell/ash_test/recho.c2
-rw-r--r--shell/hush.c56
-rw-r--r--shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.right1
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.tests2
-rw-r--r--shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.right1
-rwxr-xr-xshell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.tests2
-rw-r--r--shell/hush_test/hush-read/read_t.right8
-rwxr-xr-xshell/hush_test/hush-read/read_t.tests18
-rw-r--r--shell/shell_common.c48
-rw-r--r--sysklogd/syslogd.c2
-rwxr-xr-xtestsuite/cpio.tests23
-rwxr-xr-xtestsuite/cryptpw.tests98
-rwxr-xr-xtestsuite/cut.tests140
-rwxr-xr-xtestsuite/hexdump.tests93
-rwxr-xr-xtestsuite/make.tests40
-rwxr-xr-xtestsuite/od.tests13
-rw-r--r--testsuite/wget/wget-handles-https4
-rw-r--r--win32/dirent.c28
-rw-r--r--win32/glob.c2
-rw-r--r--win32/inet_pton.c1
-rw-r--r--win32/ioctl.c49
-rw-r--r--win32/mingw.c31
-rw-r--r--win32/process.c44
-rw-r--r--win32/select.c7
-rw-r--r--win32/strptime.c36
-rw-r--r--win32/termios.c26
-rw-r--r--win32/termios.h29
-rw-r--r--win32/winansi.c2
146 files changed, 6249 insertions, 1620 deletions
diff --git a/Config.in b/Config.in
index f6159b30b..13eb33edc 100644
--- a/Config.in
+++ b/Config.in
@@ -566,6 +566,15 @@ config OVERRIDE_APPLETS
566 environment variable. BB_OVERRIDE_APPLETS is checked first, if it 566 environment variable. BB_OVERRIDE_APPLETS is checked first, if it
567 allows the applet and this list is non-empty it is checked too. 567 allows the applet and this list is non-empty it is checked too.
568 568
569config UNWIND_TABLES
570 bool "Include stack unwind tables in the binary"
571 default y
572 depends on PLATFORM_MINGW32
573 help
574 Binaries can include support for stack unwinding. This isn't
575 normally required in BusyBox, but Windows' Control Flow Guard
576 needs it. Disabling this reduces the size of the binaries.
577
569comment 'Build Options' 578comment 'Build Options'
570 579
571config STATIC 580config STATIC
diff --git a/Makefile b/Makefile
index ae870ecb7..52a2cff87 100644
--- a/Makefile
+++ b/Makefile
@@ -551,6 +551,7 @@ libs-y := \
551 findutils/ \ 551 findutils/ \
552 init/ \ 552 init/ \
553 libbb/ \ 553 libbb/ \
554 libbb/yescrypt/ \
554 libpwdgrp/ \ 555 libpwdgrp/ \
555 loginutils/ \ 556 loginutils/ \
556 mailutils/ \ 557 mailutils/ \
@@ -688,8 +689,12 @@ quiet_cmd_busybox__ ?= LINK $@
688 "$(core-y)" \ 689 "$(core-y)" \
689 "$(libs-y)" \ 690 "$(libs-y)" \
690 "$(LDLIBS)" \ 691 "$(LDLIBS)" \
691 "$(CONFIG_EXTRA_LDLIBS)" \ 692 $(CONFIG_EXTRA_LDLIBS) \
692 && $(srctree)/scripts/generate_BUFSIZ.sh --post include/common_bufsiz.h 693 && $(srctree)/scripts/generate_BUFSIZ.sh --post include/common_bufsiz.h
694# ^^^ note: CONFIG_xyz strings already have double quotes: their value
695# is '"LIB LIB2"', therefore $(CONFIG_EXTRA_LDLIBS) above must NOT be written
696# as "$(CONFIG_EXTRA_LDLIBS)", it would be passed as ""LIB LIB2"",
697# and LIB2 would end up in $9, not $8 (and lost or misinterpreted).
693 698
694# Generate System.map 699# Generate System.map
695quiet_cmd_sysmap = SYSMAP 700quiet_cmd_sysmap = SYSMAP
diff --git a/Makefile.flags b/Makefile.flags
index f24fd9475..29fabcfb5 100644
--- a/Makefile.flags
+++ b/Makefile.flags
@@ -73,8 +73,13 @@ CFLAGS += $(call cc-option,-falign-jumps=1 -falign-labels=1 -falign-loops=1,)
73endif 73endif
74 74
75# Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary): 75# Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary):
76ifneq ($(CONFIG_UNWIND_TABLES),y)
76CFLAGS += $(call cc-option,-fno-unwind-tables,) 77CFLAGS += $(call cc-option,-fno-unwind-tables,)
77CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) 78CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,)
79else
80CFLAGS += $(call cc-option,-funwind-tables,)
81CFLAGS += $(call cc-option,-fasynchronous-unwind-tables,)
82endif
78# No automatic printf->puts,putchar conversions 83# No automatic printf->puts,putchar conversions
79# (try disabling this and comparing assembly, it's instructive) 84# (try disabling this and comparing assembly, it's instructive)
80CFLAGS += $(call cc-option,-fno-builtin-printf,) 85CFLAGS += $(call cc-option,-fno-builtin-printf,)
@@ -151,11 +156,15 @@ ifeq ($(CONFIG_PLATFORM_MINGW32),y)
151CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup 156CFLAGS += -Iwin32 -DHAVE_STRING_H=1 -DHAVE_CONFIG_H=0 -fno-builtin-stpcpy -fno-builtin-stpncpy -fno-ident -fno-builtin-strndup
152# this seems to be necessary for setjmp/longjmp to work with clang 157# this seems to be necessary for setjmp/longjmp to work with clang
153ifeq ($(lastword $(subst -, ,$(CC))),clang) 158ifeq ($(lastword $(subst -, ,$(CC))),clang)
159ifeq ($(CONFIG_UNWIND_TABLES),y)
160CFLAGS += $(call cc-option,-fexceptions,)
161else
154CFLAGS += $(call cc-option,-fsjlj-exceptions,) 162CFLAGS += $(call cc-option,-fsjlj-exceptions,)
155endif 163endif
164endif
156 165
157EXEEXT = .exe 166EXEEXT = .exe
158LDLIBS += ws2_32 167LDLIBS += ws2_32 bcrypt secur32
159endif 168endif
160 169
161ifneq ($(CONFIG_PLATFORM_MINGW32),y) 170ifneq ($(CONFIG_PLATFORM_MINGW32),y)
diff --git a/archival/Config.src b/archival/Config.src
index 6f4f30c43..cbcd7217c 100644
--- a/archival/Config.src
+++ b/archival/Config.src
@@ -35,4 +35,15 @@ config FEATURE_LZMA_FAST
35 This option reduces decompression time by about 25% at the cost of 35 This option reduces decompression time by about 25% at the cost of
36 a 1K bigger binary. 36 a 1K bigger binary.
37 37
38config FEATURE_PATH_TRAVERSAL_PROTECTION
39 bool "Prevent extraction of filenames with /../ path component"
40 default n
41 help
42 busybox tar and unzip remove "PREFIX/../" (if it exists)
43 from extracted names.
44 This option enables this behavior for all other unpacking applets,
45 such as cpio, ar, rpm.
46 GNU cpio 2.15 has NO such sanity check.
47# try other archivers and document their behavior?
48
38endmenu 49endmenu
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index fb5deb0ce..1f1f28b61 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -71,8 +71,8 @@ int FAST_FUNC bbunpack(char **argv,
71 goto err; 71 goto err;
72 } else { 72 } else {
73 /* "clever zcat" with FILE */ 73 /* "clever zcat" with FILE */
74 /* fail_if_not_compressed because zcat refuses uncompressed input */ 74 /* die_if_not_compressed because zcat refuses uncompressed input */
75 int fd = open_zipped(filename, /*fail_if_not_compressed:*/ 1); 75 int fd = open_zipped(filename, /*die_if_not_compressed:*/ 1);
76 if (fd < 0) 76 if (fd < 0)
77 goto err_name; 77 goto err_name;
78 xmove_fd(fd, STDIN_FILENO); 78 xmove_fd(fd, STDIN_FILENO);
@@ -80,7 +80,7 @@ int FAST_FUNC bbunpack(char **argv,
80 } else 80 } else
81 if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) { 81 if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) {
82 /* "clever zcat" on stdin */ 82 /* "clever zcat" on stdin */
83 if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1)) 83 if (setup_unzip_on_fd(STDIN_FILENO, /*die_if_not_compressed*/ 1))
84 goto err; 84 goto err;
85 } 85 }
86 86
diff --git a/archival/cpio.c b/archival/cpio.c
index 167931bdb..38d826a3c 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -354,6 +354,12 @@ static NOINLINE int cpio_o(void)
354#endif 354#endif
355#endif 355#endif
356 356
357 if (sizeof(st.st_size) > 4
358 && st.st_size > (off_t)0xffffffff
359 ) {
360 bb_error_msg_and_die("error: file '%s' is larger than 4GB", name);
361 }
362
357 bytes += printf("070701" 363 bytes += printf("070701"
358 "%08X%08X%08X%08X%08X%08X%08X" 364 "%08X%08X%08X%08X%08X%08X%08X"
359 "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ 365 "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
@@ -425,6 +431,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
425#endif 431#endif
426#endif 432#endif
427 "owner\0" Required_argument "R" 433 "owner\0" Required_argument "R"
434 "file\0" Required_argument "F"
428 "verbose\0" No_argument "v" 435 "verbose\0" No_argument "v"
429 "null\0" No_argument "0" 436 "null\0" No_argument "0"
430 "quiet\0" No_argument "\xff" 437 "quiet\0" No_argument "\xff"
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c
index 049c2c156..8a69711c1 100644
--- a/archival/libarchive/data_extract_all.c
+++ b/archival/libarchive/data_extract_all.c
@@ -65,6 +65,14 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
65 } while (--n != 0); 65 } while (--n != 0);
66 } 66 }
67#endif 67#endif
68#if ENABLE_FEATURE_PATH_TRAVERSAL_PROTECTION
69 /* Strip leading "/" and up to last "/../" path component */
70 dst_name = (char *)strip_unsafe_prefix(dst_name);
71#endif
72// ^^^ This may be a problem if some applets do need to extract absolute names.
73// (Probably will need to invent ARCHIVE_ALLOW_UNSAFE_NAME flag).
74// You might think that rpm needs it, but in my tests rpm's internal cpio
75// archive has names like "./usr/bin/FOO", not "/usr/bin/FOO".
68 76
69 if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { 77 if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) {
70 char *slash = strrchr(dst_name, '/'); 78 char *slash = strrchr(dst_name, '/');
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 3d202ad26..a949c4509 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -164,7 +164,7 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
164/* Used by e.g. rpm which gives us a fd without filename, 164/* Used by e.g. rpm which gives us a fd without filename,
165 * thus we can't guess the format from filename's extension. 165 * thus we can't guess the format from filename's extension.
166 */ 166 */
167static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) 167static transformer_state_t *setup_transformer_on_fd(int fd, int die_if_not_compressed)
168{ 168{
169 transformer_state_t *xstate; 169 transformer_state_t *xstate;
170 170
@@ -211,7 +211,7 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp
211 } 211 }
212 212
213 /* No known magic seen */ 213 /* No known magic seen */
214 if (fail_if_not_compressed) 214 if (die_if_not_compressed)
215 bb_simple_error_msg_and_die("no gzip" 215 bb_simple_error_msg_and_die("no gzip"
216 IF_FEATURE_SEAMLESS_BZ2("/bzip2") 216 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
217 IF_FEATURE_SEAMLESS_XZ("/xz") 217 IF_FEATURE_SEAMLESS_XZ("/xz")
@@ -247,13 +247,15 @@ static void fork_transformer_and_free(transformer_state_t *xstate)
247/* Used by e.g. rpm which gives us a fd without filename, 247/* Used by e.g. rpm which gives us a fd without filename,
248 * thus we can't guess the format from filename's extension. 248 * thus we can't guess the format from filename's extension.
249 */ 249 */
250int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) 250int FAST_FUNC setup_unzip_on_fd(int fd, int die_if_not_compressed)
251{ 251{
252 transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); 252 transformer_state_t *xstate = setup_transformer_on_fd(fd, die_if_not_compressed);
253 253
254 if (!xstate->xformer) { 254 if (!xstate->xformer) {
255 /* Not compressed */
256 int retval = xstate->signature_skipped; /* never zero */
255 free(xstate); 257 free(xstate);
256 return 1; 258 return retval;
257 } 259 }
258 260
259 fork_transformer_and_free(xstate); 261 fork_transformer_and_free(xstate);
@@ -271,7 +273,7 @@ void FAST_FUNC setup_lzma_on_fd(int fd)
271} 273}
272#endif 274#endif
273 275
274static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) 276static transformer_state_t *open_transformer(const char *fname, int die_if_not_compressed)
275{ 277{
276 transformer_state_t *xstate; 278 transformer_state_t *xstate;
277 int fd; 279 int fd;
@@ -291,18 +293,18 @@ static transformer_state_t *open_transformer(const char *fname, int fail_if_not_
291 } 293 }
292 } 294 }
293 295
294 xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); 296 xstate = setup_transformer_on_fd(fd, die_if_not_compressed);
295 297
296 return xstate; 298 return xstate;
297} 299}
298 300
299int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) 301int FAST_FUNC open_zipped(const char *fname, int die_if_not_compressed)
300{ 302{
301 int fd; 303 int fd;
302 transformer_state_t *xstate; 304 transformer_state_t *xstate;
303 305
304 xstate = open_transformer(fname, fail_if_not_compressed); 306 xstate = open_transformer(fname, die_if_not_compressed);
305 if (!xstate) 307 if (!xstate) /* open error */
306 return -1; 308 return -1;
307 309
308 fd = xstate->src_fd; 310 fd = xstate->src_fd;
@@ -333,7 +335,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_
333 transformer_state_t *xstate; 335 transformer_state_t *xstate;
334 char *image; 336 char *image;
335 337
336 xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0); 338 xstate = open_transformer(fname, /*die_if_not_compressed:*/ 0);
337 if (!xstate) /* file open error */ 339 if (!xstate) /* file open error */
338 return NULL; 340 return NULL;
339 341
@@ -378,7 +380,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_
378 int fd; 380 int fd;
379 char *image; 381 char *image;
380 382
381 fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0); 383 fd = open_zipped(fname, /*die_if_not_compressed:*/ 0);
382 if (fd < 0) 384 if (fd < 0)
383 return NULL; 385 return NULL;
384 386
diff --git a/archival/libarchive/unsafe_prefix.c b/archival/libarchive/unsafe_prefix.c
index 33e487bf9..667081195 100644
--- a/archival/libarchive/unsafe_prefix.c
+++ b/archival/libarchive/unsafe_prefix.c
@@ -14,7 +14,11 @@ const char* FAST_FUNC strip_unsafe_prefix(const char *str)
14 cp++; 14 cp++;
15 continue; 15 continue;
16 } 16 }
17 if (is_prefixed_with(cp, "/../"+1)) { 17 /* We are called lots of times.
18 * is_prefixed_with(cp, "../") is slower than open-coding it,
19 * with minimal code growth (~few bytes).
20 */
21 if (cp[0] == '.' && cp[1] == '.' && cp[2] == '/') {
18 cp += 3; 22 cp += 3;
19 continue; 23 continue;
20 } 24 }
diff --git a/archival/rpm.c b/archival/rpm.c
index d83c33137..c2f0550ff 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -330,7 +330,7 @@ static void extract_cpio(int fd, const char *source_rpm)
330 archive_handle->src_fd = fd; 330 archive_handle->src_fd = fd;
331 /*archive_handle->offset = 0; - init_handle() did it */ 331 /*archive_handle->offset = 0; - init_handle() did it */
332 332
333 setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1); 333 setup_unzip_on_fd(archive_handle->src_fd, /*die_if_not_compressed:*/ 1);
334 while (get_header_cpio(archive_handle) == EXIT_SUCCESS) 334 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
335 continue; 335 continue;
336} 336}
@@ -549,6 +549,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
549 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ 549 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */
550 // signal(SIGCHLD, check_errors_in_children); 550 // signal(SIGCHLD, check_errors_in_children);
551 551
552 str = NULL;
552 if (ENABLE_FEATURE_SEAMLESS_LZMA 553 if (ENABLE_FEATURE_SEAMLESS_LZMA
553 && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL 554 && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL
554 && strcmp(str, "lzma") == 0 555 && strcmp(str, "lzma") == 0
@@ -557,7 +558,11 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
557 // set up decompressor without detection 558 // set up decompressor without detection
558 setup_lzma_on_fd(rpm_fd); 559 setup_lzma_on_fd(rpm_fd);
559 } else { 560 } else {
560 setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); 561 int signature_bytes = setup_unzip_on_fd(rpm_fd, /*die_if_not_compressed:*/ 0);
562 if (signature_bytes != 0) {
563 xlseek(rpm_fd, - signature_bytes, SEEK_CUR);
564 bb_error_msg("warning, unknown compression '%s'", str);
565 }
561 } 566 }
562 567
563 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) 568 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
diff --git a/archival/tar.c b/archival/tar.c
index 23ea02b5d..fd20d6ce7 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -1188,7 +1188,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1188 * on e.g. tarball with 1st file named "BZh5". 1188 * on e.g. tarball with 1st file named "BZh5".
1189 */ 1189 */
1190 ) { 1190 ) {
1191 tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); 1191 tar_handle->src_fd = open_zipped(tar_filename, /*die_if_not_compressed:*/ 0);
1192 if (tar_handle->src_fd < 0) 1192 if (tar_handle->src_fd < 0)
1193 bb_perror_msg_and_die("can't open '%s'", tar_filename); 1193 bb_perror_msg_and_die("can't open '%s'", tar_filename);
1194 } else { 1194 } else {
diff --git a/configs/mingw32_defconfig b/configs/mingw32_defconfig
index 6f6bdb14b..6e8f1d5e4 100644
--- a/configs/mingw32_defconfig
+++ b/configs/mingw32_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git 3# Busybox version: 1.38.0.git
4# Fri Jun 14 12:24:50 2024 4# Fri Aug 8 08:27:35 2025
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -62,6 +62,7 @@ CONFIG_TERMINAL_MODE=5
62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y 62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
63CONFIG_FEATURE_EXTRA_FILE_DATA=y 63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64CONFIG_OVERRIDE_APPLETS="" 64CONFIG_OVERRIDE_APPLETS=""
65CONFIG_UNWIND_TABLES=y
65 66
66# 67#
67# Build Options 68# Build Options
@@ -120,6 +121,7 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
120# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set 121# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
121# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set 122# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
122CONFIG_PASSWORD_MINLEN=6 123CONFIG_PASSWORD_MINLEN=6
124# CONFIG_FEATURE_USE_CNG_API is not set
123CONFIG_MD5_SMALL=1 125CONFIG_MD5_SMALL=1
124CONFIG_SHA1_SMALL=3 126CONFIG_SHA1_SMALL=3
125# CONFIG_SHA1_HWACCEL is not set 127# CONFIG_SHA1_HWACCEL is not set
@@ -225,6 +227,7 @@ CONFIG_FEATURE_UNZIP_BZIP2=y
225CONFIG_FEATURE_UNZIP_LZMA=y 227CONFIG_FEATURE_UNZIP_LZMA=y
226CONFIG_FEATURE_UNZIP_XZ=y 228CONFIG_FEATURE_UNZIP_XZ=y
227CONFIG_FEATURE_LZMA_FAST=y 229CONFIG_FEATURE_LZMA_FAST=y
230# CONFIG_FEATURE_PATH_TRAVERSAL_PROTECTION is not set
228 231
229# 232#
230# Coreutils 233# Coreutils
@@ -272,7 +275,7 @@ CONFIG_DD=y
272CONFIG_FEATURE_DD_IBS_OBS=y 275CONFIG_FEATURE_DD_IBS_OBS=y
273CONFIG_FEATURE_DD_STATUS=y 276CONFIG_FEATURE_DD_STATUS=y
274CONFIG_DF=y 277CONFIG_DF=y
275# CONFIG_FEATURE_DF_FANCY is not set 278CONFIG_FEATURE_DF_FANCY=y
276# CONFIG_FEATURE_SKIP_ROOTFS is not set 279# CONFIG_FEATURE_SKIP_ROOTFS is not set
277CONFIG_DIRNAME=y 280CONFIG_DIRNAME=y
278CONFIG_DOS2UNIX=y 281CONFIG_DOS2UNIX=y
@@ -351,7 +354,7 @@ CONFIG_FEATURE_SPLIT_FANCY=y
351CONFIG_STAT=y 354CONFIG_STAT=y
352CONFIG_FEATURE_STAT_FORMAT=y 355CONFIG_FEATURE_STAT_FORMAT=y
353CONFIG_FEATURE_STAT_FILESYSTEM=y 356CONFIG_FEATURE_STAT_FILESYSTEM=y
354# CONFIG_STTY is not set 357CONFIG_STTY=y
355CONFIG_SUM=y 358CONFIG_SUM=y
356CONFIG_SYNC=y 359CONFIG_SYNC=y
357# CONFIG_FEATURE_SYNC_FANCY is not set 360# CONFIG_FEATURE_SYNC_FANCY is not set
@@ -898,7 +901,10 @@ CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
898# CONFIG_FEATURE_ETC_NETWORKS is not set 901# CONFIG_FEATURE_ETC_NETWORKS is not set
899# CONFIG_FEATURE_ETC_SERVICES is not set 902# CONFIG_FEATURE_ETC_SERVICES is not set
900# CONFIG_FEATURE_HWIB is not set 903# CONFIG_FEATURE_HWIB is not set
904CONFIG_FEATURE_TLS_INTERNAL=y
905# CONFIG_FEATURE_TLS_SCHANNEL is not set
901# CONFIG_FEATURE_TLS_SHA1 is not set 906# CONFIG_FEATURE_TLS_SHA1 is not set
907# CONFIG_FEATURE_TLS_SCHANNEL_1_3 is not set
902# CONFIG_ARP is not set 908# CONFIG_ARP is not set
903# CONFIG_ARPING is not set 909# CONFIG_ARPING is not set
904# CONFIG_BRCTL is not set 910# CONFIG_BRCTL is not set
@@ -964,6 +970,7 @@ CONFIG_IFUPDOWN_IFSTATE_PATH=""
964# CONFIG_IPNEIGH is not set 970# CONFIG_IPNEIGH is not set
965# CONFIG_FEATURE_IP_ADDRESS is not set 971# CONFIG_FEATURE_IP_ADDRESS is not set
966# CONFIG_FEATURE_IP_LINK is not set 972# CONFIG_FEATURE_IP_LINK is not set
973CONFIG_FEATURE_IP_LINK_CAN=y
967# CONFIG_FEATURE_IP_ROUTE is not set 974# CONFIG_FEATURE_IP_ROUTE is not set
968CONFIG_FEATURE_IP_ROUTE_DIR="" 975CONFIG_FEATURE_IP_ROUTE_DIR=""
969# CONFIG_FEATURE_IP_TUNNEL is not set 976# CONFIG_FEATURE_IP_TUNNEL is not set
diff --git a/configs/mingw64_defconfig b/configs/mingw64_defconfig
index fbd2bc6e3..3a5d1248a 100644
--- a/configs/mingw64_defconfig
+++ b/configs/mingw64_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git 3# Busybox version: 1.38.0.git
4# Fri Jun 14 12:24:50 2024 4# Fri Aug 8 08:27:35 2025
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -62,6 +62,7 @@ CONFIG_TERMINAL_MODE=5
62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y 62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
63CONFIG_FEATURE_EXTRA_FILE_DATA=y 63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64CONFIG_OVERRIDE_APPLETS="" 64CONFIG_OVERRIDE_APPLETS=""
65CONFIG_UNWIND_TABLES=y
65 66
66# 67#
67# Build Options 68# Build Options
@@ -120,6 +121,7 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
120# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set 121# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
121# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set 122# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
122CONFIG_PASSWORD_MINLEN=6 123CONFIG_PASSWORD_MINLEN=6
124# CONFIG_FEATURE_USE_CNG_API is not set
123CONFIG_MD5_SMALL=1 125CONFIG_MD5_SMALL=1
124CONFIG_SHA1_SMALL=3 126CONFIG_SHA1_SMALL=3
125# CONFIG_SHA1_HWACCEL is not set 127# CONFIG_SHA1_HWACCEL is not set
@@ -225,6 +227,7 @@ CONFIG_FEATURE_UNZIP_BZIP2=y
225CONFIG_FEATURE_UNZIP_LZMA=y 227CONFIG_FEATURE_UNZIP_LZMA=y
226CONFIG_FEATURE_UNZIP_XZ=y 228CONFIG_FEATURE_UNZIP_XZ=y
227CONFIG_FEATURE_LZMA_FAST=y 229CONFIG_FEATURE_LZMA_FAST=y
230# CONFIG_FEATURE_PATH_TRAVERSAL_PROTECTION is not set
228 231
229# 232#
230# Coreutils 233# Coreutils
@@ -272,7 +275,7 @@ CONFIG_DD=y
272CONFIG_FEATURE_DD_IBS_OBS=y 275CONFIG_FEATURE_DD_IBS_OBS=y
273CONFIG_FEATURE_DD_STATUS=y 276CONFIG_FEATURE_DD_STATUS=y
274CONFIG_DF=y 277CONFIG_DF=y
275# CONFIG_FEATURE_DF_FANCY is not set 278CONFIG_FEATURE_DF_FANCY=y
276# CONFIG_FEATURE_SKIP_ROOTFS is not set 279# CONFIG_FEATURE_SKIP_ROOTFS is not set
277CONFIG_DIRNAME=y 280CONFIG_DIRNAME=y
278CONFIG_DOS2UNIX=y 281CONFIG_DOS2UNIX=y
@@ -351,7 +354,7 @@ CONFIG_FEATURE_SPLIT_FANCY=y
351CONFIG_STAT=y 354CONFIG_STAT=y
352CONFIG_FEATURE_STAT_FORMAT=y 355CONFIG_FEATURE_STAT_FORMAT=y
353CONFIG_FEATURE_STAT_FILESYSTEM=y 356CONFIG_FEATURE_STAT_FILESYSTEM=y
354# CONFIG_STTY is not set 357CONFIG_STTY=y
355CONFIG_SUM=y 358CONFIG_SUM=y
356CONFIG_SYNC=y 359CONFIG_SYNC=y
357# CONFIG_FEATURE_SYNC_FANCY is not set 360# CONFIG_FEATURE_SYNC_FANCY is not set
@@ -898,7 +901,10 @@ CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
898# CONFIG_FEATURE_ETC_NETWORKS is not set 901# CONFIG_FEATURE_ETC_NETWORKS is not set
899# CONFIG_FEATURE_ETC_SERVICES is not set 902# CONFIG_FEATURE_ETC_SERVICES is not set
900# CONFIG_FEATURE_HWIB is not set 903# CONFIG_FEATURE_HWIB is not set
904CONFIG_FEATURE_TLS_INTERNAL=y
905# CONFIG_FEATURE_TLS_SCHANNEL is not set
901# CONFIG_FEATURE_TLS_SHA1 is not set 906# CONFIG_FEATURE_TLS_SHA1 is not set
907# CONFIG_FEATURE_TLS_SCHANNEL_1_3 is not set
902# CONFIG_ARP is not set 908# CONFIG_ARP is not set
903# CONFIG_ARPING is not set 909# CONFIG_ARPING is not set
904# CONFIG_BRCTL is not set 910# CONFIG_BRCTL is not set
@@ -964,6 +970,7 @@ CONFIG_IFUPDOWN_IFSTATE_PATH=""
964# CONFIG_IPNEIGH is not set 970# CONFIG_IPNEIGH is not set
965# CONFIG_FEATURE_IP_ADDRESS is not set 971# CONFIG_FEATURE_IP_ADDRESS is not set
966# CONFIG_FEATURE_IP_LINK is not set 972# CONFIG_FEATURE_IP_LINK is not set
973CONFIG_FEATURE_IP_LINK_CAN=y
967# CONFIG_FEATURE_IP_ROUTE is not set 974# CONFIG_FEATURE_IP_ROUTE is not set
968CONFIG_FEATURE_IP_ROUTE_DIR="" 975CONFIG_FEATURE_IP_ROUTE_DIR=""
969# CONFIG_FEATURE_IP_TUNNEL is not set 976# CONFIG_FEATURE_IP_TUNNEL is not set
diff --git a/configs/mingw64a_defconfig b/configs/mingw64a_defconfig
index e9a88bf62..d17737721 100644
--- a/configs/mingw64a_defconfig
+++ b/configs/mingw64a_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git 3# Busybox version: 1.38.0.git
4# Fri Jun 14 12:24:50 2024 4# Fri Aug 8 08:27:35 2025
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -62,6 +62,7 @@ CONFIG_TERMINAL_MODE=5
62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y 62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
63CONFIG_FEATURE_EXTRA_FILE_DATA=y 63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64CONFIG_OVERRIDE_APPLETS="" 64CONFIG_OVERRIDE_APPLETS=""
65CONFIG_UNWIND_TABLES=y
65 66
66# 67#
67# Build Options 68# Build Options
@@ -120,6 +121,7 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
120# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set 121# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
121# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set 122# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
122CONFIG_PASSWORD_MINLEN=6 123CONFIG_PASSWORD_MINLEN=6
124CONFIG_FEATURE_USE_CNG_API=y
123CONFIG_MD5_SMALL=1 125CONFIG_MD5_SMALL=1
124CONFIG_SHA1_SMALL=3 126CONFIG_SHA1_SMALL=3
125# CONFIG_SHA1_HWACCEL is not set 127# CONFIG_SHA1_HWACCEL is not set
@@ -225,6 +227,7 @@ CONFIG_FEATURE_UNZIP_BZIP2=y
225CONFIG_FEATURE_UNZIP_LZMA=y 227CONFIG_FEATURE_UNZIP_LZMA=y
226CONFIG_FEATURE_UNZIP_XZ=y 228CONFIG_FEATURE_UNZIP_XZ=y
227CONFIG_FEATURE_LZMA_FAST=y 229CONFIG_FEATURE_LZMA_FAST=y
230# CONFIG_FEATURE_PATH_TRAVERSAL_PROTECTION is not set
228 231
229# 232#
230# Coreutils 233# Coreutils
@@ -272,7 +275,7 @@ CONFIG_DD=y
272CONFIG_FEATURE_DD_IBS_OBS=y 275CONFIG_FEATURE_DD_IBS_OBS=y
273CONFIG_FEATURE_DD_STATUS=y 276CONFIG_FEATURE_DD_STATUS=y
274CONFIG_DF=y 277CONFIG_DF=y
275# CONFIG_FEATURE_DF_FANCY is not set 278CONFIG_FEATURE_DF_FANCY=y
276# CONFIG_FEATURE_SKIP_ROOTFS is not set 279# CONFIG_FEATURE_SKIP_ROOTFS is not set
277CONFIG_DIRNAME=y 280CONFIG_DIRNAME=y
278CONFIG_DOS2UNIX=y 281CONFIG_DOS2UNIX=y
@@ -351,7 +354,7 @@ CONFIG_FEATURE_SPLIT_FANCY=y
351CONFIG_STAT=y 354CONFIG_STAT=y
352CONFIG_FEATURE_STAT_FORMAT=y 355CONFIG_FEATURE_STAT_FORMAT=y
353CONFIG_FEATURE_STAT_FILESYSTEM=y 356CONFIG_FEATURE_STAT_FILESYSTEM=y
354# CONFIG_STTY is not set 357CONFIG_STTY=y
355CONFIG_SUM=y 358CONFIG_SUM=y
356CONFIG_SYNC=y 359CONFIG_SYNC=y
357# CONFIG_FEATURE_SYNC_FANCY is not set 360# CONFIG_FEATURE_SYNC_FANCY is not set
@@ -898,7 +901,10 @@ CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
898# CONFIG_FEATURE_ETC_NETWORKS is not set 901# CONFIG_FEATURE_ETC_NETWORKS is not set
899# CONFIG_FEATURE_ETC_SERVICES is not set 902# CONFIG_FEATURE_ETC_SERVICES is not set
900# CONFIG_FEATURE_HWIB is not set 903# CONFIG_FEATURE_HWIB is not set
904# CONFIG_FEATURE_TLS_INTERNAL is not set
905CONFIG_FEATURE_TLS_SCHANNEL=y
901# CONFIG_FEATURE_TLS_SHA1 is not set 906# CONFIG_FEATURE_TLS_SHA1 is not set
907# CONFIG_FEATURE_TLS_SCHANNEL_1_3 is not set
902# CONFIG_ARP is not set 908# CONFIG_ARP is not set
903# CONFIG_ARPING is not set 909# CONFIG_ARPING is not set
904# CONFIG_BRCTL is not set 910# CONFIG_BRCTL is not set
@@ -964,6 +970,7 @@ CONFIG_IFUPDOWN_IFSTATE_PATH=""
964# CONFIG_IPNEIGH is not set 970# CONFIG_IPNEIGH is not set
965# CONFIG_FEATURE_IP_ADDRESS is not set 971# CONFIG_FEATURE_IP_ADDRESS is not set
966# CONFIG_FEATURE_IP_LINK is not set 972# CONFIG_FEATURE_IP_LINK is not set
973CONFIG_FEATURE_IP_LINK_CAN=y
967# CONFIG_FEATURE_IP_ROUTE is not set 974# CONFIG_FEATURE_IP_ROUTE is not set
968CONFIG_FEATURE_IP_ROUTE_DIR="" 975CONFIG_FEATURE_IP_ROUTE_DIR=""
969# CONFIG_FEATURE_IP_TUNNEL is not set 976# CONFIG_FEATURE_IP_TUNNEL is not set
diff --git a/configs/mingw64u_defconfig b/configs/mingw64u_defconfig
index 61753699d..adb1552f2 100644
--- a/configs/mingw64u_defconfig
+++ b/configs/mingw64u_defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Busybox version: 1.37.0.git 3# Busybox version: 1.38.0.git
4# Fri Jun 14 12:24:50 2024 4# Fri Aug 8 08:27:35 2025
5# 5#
6CONFIG_HAVE_DOT_CONFIG=y 6CONFIG_HAVE_DOT_CONFIG=y
7# CONFIG_PLATFORM_POSIX is not set 7# CONFIG_PLATFORM_POSIX is not set
@@ -62,6 +62,7 @@ CONFIG_TERMINAL_MODE=5
62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y 62CONFIG_FEATURE_IMPROVED_COLOUR_MAPPING=y
63CONFIG_FEATURE_EXTRA_FILE_DATA=y 63CONFIG_FEATURE_EXTRA_FILE_DATA=y
64CONFIG_OVERRIDE_APPLETS="" 64CONFIG_OVERRIDE_APPLETS=""
65CONFIG_UNWIND_TABLES=y
65 66
66# 67#
67# Build Options 68# Build Options
@@ -120,6 +121,7 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y
120# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set 121# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set
121# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set 122# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set
122CONFIG_PASSWORD_MINLEN=6 123CONFIG_PASSWORD_MINLEN=6
124CONFIG_FEATURE_USE_CNG_API=y
123CONFIG_MD5_SMALL=1 125CONFIG_MD5_SMALL=1
124CONFIG_SHA1_SMALL=3 126CONFIG_SHA1_SMALL=3
125# CONFIG_SHA1_HWACCEL is not set 127# CONFIG_SHA1_HWACCEL is not set
@@ -225,6 +227,7 @@ CONFIG_FEATURE_UNZIP_BZIP2=y
225CONFIG_FEATURE_UNZIP_LZMA=y 227CONFIG_FEATURE_UNZIP_LZMA=y
226CONFIG_FEATURE_UNZIP_XZ=y 228CONFIG_FEATURE_UNZIP_XZ=y
227CONFIG_FEATURE_LZMA_FAST=y 229CONFIG_FEATURE_LZMA_FAST=y
230# CONFIG_FEATURE_PATH_TRAVERSAL_PROTECTION is not set
228 231
229# 232#
230# Coreutils 233# Coreutils
@@ -272,7 +275,7 @@ CONFIG_DD=y
272CONFIG_FEATURE_DD_IBS_OBS=y 275CONFIG_FEATURE_DD_IBS_OBS=y
273CONFIG_FEATURE_DD_STATUS=y 276CONFIG_FEATURE_DD_STATUS=y
274CONFIG_DF=y 277CONFIG_DF=y
275# CONFIG_FEATURE_DF_FANCY is not set 278CONFIG_FEATURE_DF_FANCY=y
276# CONFIG_FEATURE_SKIP_ROOTFS is not set 279# CONFIG_FEATURE_SKIP_ROOTFS is not set
277CONFIG_DIRNAME=y 280CONFIG_DIRNAME=y
278CONFIG_DOS2UNIX=y 281CONFIG_DOS2UNIX=y
@@ -351,7 +354,7 @@ CONFIG_FEATURE_SPLIT_FANCY=y
351CONFIG_STAT=y 354CONFIG_STAT=y
352CONFIG_FEATURE_STAT_FORMAT=y 355CONFIG_FEATURE_STAT_FORMAT=y
353CONFIG_FEATURE_STAT_FILESYSTEM=y 356CONFIG_FEATURE_STAT_FILESYSTEM=y
354# CONFIG_STTY is not set 357CONFIG_STTY=y
355CONFIG_SUM=y 358CONFIG_SUM=y
356CONFIG_SYNC=y 359CONFIG_SYNC=y
357# CONFIG_FEATURE_SYNC_FANCY is not set 360# CONFIG_FEATURE_SYNC_FANCY is not set
@@ -898,7 +901,10 @@ CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y
898# CONFIG_FEATURE_ETC_NETWORKS is not set 901# CONFIG_FEATURE_ETC_NETWORKS is not set
899# CONFIG_FEATURE_ETC_SERVICES is not set 902# CONFIG_FEATURE_ETC_SERVICES is not set
900# CONFIG_FEATURE_HWIB is not set 903# CONFIG_FEATURE_HWIB is not set
904# CONFIG_FEATURE_TLS_INTERNAL is not set
905CONFIG_FEATURE_TLS_SCHANNEL=y
901# CONFIG_FEATURE_TLS_SHA1 is not set 906# CONFIG_FEATURE_TLS_SHA1 is not set
907# CONFIG_FEATURE_TLS_SCHANNEL_1_3 is not set
902# CONFIG_ARP is not set 908# CONFIG_ARP is not set
903# CONFIG_ARPING is not set 909# CONFIG_ARPING is not set
904# CONFIG_BRCTL is not set 910# CONFIG_BRCTL is not set
@@ -964,6 +970,7 @@ CONFIG_IFUPDOWN_IFSTATE_PATH=""
964# CONFIG_IPNEIGH is not set 970# CONFIG_IPNEIGH is not set
965# CONFIG_FEATURE_IP_ADDRESS is not set 971# CONFIG_FEATURE_IP_ADDRESS is not set
966# CONFIG_FEATURE_IP_LINK is not set 972# CONFIG_FEATURE_IP_LINK is not set
973CONFIG_FEATURE_IP_LINK_CAN=y
967# CONFIG_FEATURE_IP_ROUTE is not set 974# CONFIG_FEATURE_IP_ROUTE is not set
968CONFIG_FEATURE_IP_ROUTE_DIR="" 975CONFIG_FEATURE_IP_ROUTE_DIR=""
969# CONFIG_FEATURE_IP_TUNNEL is not set 976# CONFIG_FEATURE_IP_TUNNEL is not set
diff --git a/coreutils/cut.c b/coreutils/cut.c
index f7b501a46..d81f36bcd 100644
--- a/coreutils/cut.c
+++ b/coreutils/cut.c
@@ -27,21 +27,34 @@
27//kbuild:lib-$(CONFIG_CUT) += cut.o 27//kbuild:lib-$(CONFIG_CUT) += cut.o
28 28
29//usage:#define cut_trivial_usage 29//usage:#define cut_trivial_usage
30//usage: "[OPTIONS] [FILE]..." 30//usage: "{-b|c LIST | -f"IF_FEATURE_CUT_REGEX("|F")" LIST [-d SEP] [-s]} [-D] [-O SEP] [FILE]..."
31// --output-delimiter SEP is too long to fit into 80 char-wide help ----------------^^^^^^^^
31//usage:#define cut_full_usage "\n\n" 32//usage:#define cut_full_usage "\n\n"
32//usage: "Print selected fields from FILEs to stdout\n" 33//usage: "Print selected fields from FILEs to stdout\n"
33//usage: "\n -b LIST Output only bytes from LIST" 34//usage: "\n -b LIST Output only bytes from LIST"
34//usage: "\n -c LIST Output only characters from LIST" 35//usage: "\n -c LIST Output only characters from LIST"
35//usage: "\n -d SEP Field delimiter for input (default -f TAB, -F run of whitespace)" 36//usage: IF_FEATURE_CUT_REGEX(
36//usage: "\n -O SEP Field delimeter for output (default = -d for -f, one space for -F)" 37//usage: "\n -d SEP Input field delimiter (default -f TAB, -F run of whitespace)"
37//usage: "\n -D Don't sort/collate sections or match -fF lines without delimeter" 38//usage: ) IF_NOT_FEATURE_CUT_REGEX(
39//usage: "\n -d SEP Input field delimiter (default TAB)"
40//usage: )
38//usage: "\n -f LIST Print only these fields (-d is single char)" 41//usage: "\n -f LIST Print only these fields (-d is single char)"
39//usage: IF_FEATURE_CUT_REGEX( 42//usage: IF_FEATURE_CUT_REGEX(
40//usage: "\n -F LIST Print only these fields (-d is regex)" 43//usage: "\n -F LIST Print only these fields (-d is regex)"
41//usage: ) 44//usage: )
42//usage: "\n -s Output only lines containing delimiter" 45//usage: "\n -s Drop lines with no delimiter (else print them in full)"
46//usage: "\n -D Don't sort ranges; line without delimiters has one field"
47//usage: IF_LONG_OPTS(
48//usage: "\n --output-delimiter SEP Output field delimeter"
49//usage: ) IF_NOT_LONG_OPTS(
50//usage: IF_FEATURE_CUT_REGEX(
51//usage: "\n -O SEP Output field delimeter (default = -d for -f, one space for -F)"
52//usage: ) IF_NOT_FEATURE_CUT_REGEX(
53//usage: "\n -O SEP Output field delimeter (default = -d)"
54//usage: )
55//usage: )
43//usage: "\n -n Ignored" 56//usage: "\n -n Ignored"
44//(manpage:-n with -b: don't split multibyte characters) 57//(manpage:-n with -b: don't split multibyte characters)
45//usage: 58//usage:
46//usage:#define cut_example_usage 59//usage:#define cut_example_usage
47//usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n" 60//usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n"
@@ -53,11 +66,6 @@
53 66
54#if ENABLE_FEATURE_CUT_REGEX 67#if ENABLE_FEATURE_CUT_REGEX
55#include "xregex.h" 68#include "xregex.h"
56#else
57#define regex_t int
58typedef struct { int rm_eo, rm_so; } regmatch_t;
59#define xregcomp(x, ...) *(x) = 0
60#define regexec(...) 0
61#endif 69#endif
62 70
63/* This is a NOEXEC applet. Be very careful! */ 71/* This is a NOEXEC applet. Be very careful! */
@@ -65,265 +73,346 @@ typedef struct { int rm_eo, rm_so; } regmatch_t;
65 73
66/* option vars */ 74/* option vars */
67#define OPT_STR "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" 75#define OPT_STR "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n"
68#define CUT_OPT_BYTE_FLGS (1 << 0) 76#define OPT_BYTE (1 << 0)
69#define CUT_OPT_CHAR_FLGS (1 << 1) 77#define OPT_CHAR (1 << 1)
70#define CUT_OPT_FIELDS_FLGS (1 << 2) 78#define OPT_FIELDS (1 << 2)
71#define CUT_OPT_DELIM_FLGS (1 << 3) 79#define OPT_DELIM (1 << 3)
72#define CUT_OPT_ODELIM_FLGS (1 << 4) 80#define OPT_ODELIM (1 << 4)
73#define CUT_OPT_SUPPRESS_FLGS (1 << 5) 81#define OPT_SUPPRESS (1 << 5)
74#define CUT_OPT_NOSORT_FLGS (1 << 6) 82#define OPT_NOSORT (1 << 6)
75#define CUT_OPT_REGEX_FLGS ((1 << 7) * ENABLE_FEATURE_CUT_REGEX) 83#define OPT_REGEX ((1 << 7) * ENABLE_FEATURE_CUT_REGEX)
76 84
77struct cut_list { 85#define opt_REGEX (option_mask32 & OPT_REGEX)
78 int startpos; 86
79 int endpos; 87struct cut_range {
88 unsigned startpos;
89 unsigned endpos;
80}; 90};
81 91
82static int cmpfunc(const void *a, const void *b) 92static int cmpfunc(const void *a, const void *b)
83{ 93{
84 return (((struct cut_list *) a)->startpos - 94 const struct cut_range *aa = a;
85 ((struct cut_list *) b)->startpos); 95 const struct cut_range *bb = b;
96 return aa->startpos - bb->startpos;
86} 97}
87 98
99#define END_OF_LIST(list_elem) ((list_elem).startpos == UINT_MAX)
100#define NOT_END_OF_LIST(list_elem) ((list_elem).startpos != UINT_MAX)
101
88static void cut_file(FILE *file, const char *delim, const char *odelim, 102static void cut_file(FILE *file, const char *delim, const char *odelim,
89 const struct cut_list *cut_lists, unsigned nlists) 103 const struct cut_range *cut_list)
90{ 104{
91 char *line; 105 char *line;
92 unsigned linenum = 0; /* keep these zero-based to be consistent */ 106 unsigned linenum = 0; /* keep these zero-based to be consistent */
93 regex_t reg; 107 int first_print = 1;
94 int spos, shoe = option_mask32 & CUT_OPT_REGEX_FLGS;
95
96 if (shoe) xregcomp(&reg, delim, REG_EXTENDED);
97 108
98 /* go through every line in the file */ 109 /* go through every line in the file */
99 while ((line = xmalloc_fgetline(file)) != NULL) { 110 while ((line = xmalloc_fgetline(file)) != NULL) {
100 111
101 /* set up a list so we can keep track of what's been printed */ 112 /* set up a list so we can keep track of what's been printed */
102 int linelen = strlen(line); 113 unsigned linelen = strlen(line);
103 char *printed = xzalloc(linelen + 1);
104 char *orig_line = line;
105 unsigned cl_pos = 0; 114 unsigned cl_pos = 0;
106 115
107 /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */ 116 /* Cut based on chars/bytes XXX: only works when sizeof(char) == byte */
108 if (option_mask32 & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS)) { 117 if (option_mask32 & (OPT_CHAR | OPT_BYTE)) {
118 char *printed = xzalloc(linelen + 1);
119 int need_odelim = 0;
120
109 /* print the chars specified in each cut list */ 121 /* print the chars specified in each cut list */
110 for (; cl_pos < nlists; cl_pos++) { 122 for (; NOT_END_OF_LIST(cut_list[cl_pos]); cl_pos++) {
111 for (spos = cut_lists[cl_pos].startpos; spos < linelen;) { 123 unsigned spos = cut_list[cl_pos].startpos;
124 while (spos < linelen) {
112 if (!printed[spos]) { 125 if (!printed[spos]) {
113 printed[spos] = 'X'; 126 printed[spos] = 'X';
127 if (need_odelim && spos != 0 && !printed[spos-1]) {
128 need_odelim = 0;
129 fputs_stdout(odelim);
130 }
114 putchar(line[spos]); 131 putchar(line[spos]);
115 } 132 }
116 if (++spos > cut_lists[cl_pos].endpos) { 133 spos++;
134 if (spos > cut_list[cl_pos].endpos) {
135 /* will print OSEP (if not empty) */
136 need_odelim = (odelim && odelim[0]);
117 break; 137 break;
118 } 138 }
119 } 139 }
120 } 140 }
121 } else if (*delim == '\n') { /* cut by lines */ 141 free(printed);
122 spos = cut_lists[cl_pos].startpos; 142 /* Cut by lines */
143 } else if (!opt_REGEX && *delim == '\n') {
144 unsigned spos = cut_list[cl_pos].startpos;
123 145
124 /* get out if we have no more lists to process or if the lines 146 linenum++;
147 /* get out if we have no more ranges to process or if the lines
125 * are lower than what we're interested in */ 148 * are lower than what we're interested in */
126 if (((int)linenum < spos) || (cl_pos >= nlists)) 149 if (linenum <= spos || END_OF_LIST(cut_list[cl_pos]))
127 goto next_line; 150 goto next_line;
128 151
129 /* if the line we're looking for is lower than the one we were 152 /* if the line we're looking for is lower than the one we were
130 * passed, it means we displayed it already, so move on */ 153 * passed, it means we displayed it already, so move on */
131 while (spos < (int)linenum) { 154 while (++spos < linenum) {
132 spos++;
133 /* go to the next list if we're at the end of this one */ 155 /* go to the next list if we're at the end of this one */
134 if (spos > cut_lists[cl_pos].endpos) { 156 if (spos > cut_list[cl_pos].endpos) {
135 cl_pos++; 157 cl_pos++;
136 /* get out if there's no more lists to process */ 158 /* get out if there's no more ranges to process */
137 if (cl_pos >= nlists) 159 if (END_OF_LIST(cut_list[cl_pos]))
138 goto next_line; 160 goto next_line;
139 spos = cut_lists[cl_pos].startpos; 161 spos = cut_list[cl_pos].startpos;
140 /* get out if the current line is lower than the one 162 /* get out if the current line is lower than the one
141 * we just became interested in */ 163 * we just became interested in */
142 if ((int)linenum < spos) 164 if (linenum <= spos)
143 goto next_line; 165 goto next_line;
144 } 166 }
145 } 167 }
146 168
147 /* If we made it here, it means we've found the line we're 169 /* If we made it here, it means we've found the line we're
148 * looking for, so print it */ 170 * looking for, so print it */
149 puts(line); 171 if (first_print) {
172 first_print = 0;
173 fputs_stdout(line);
174 } else
175 printf("%s%s", odelim, line);
150 goto next_line; 176 goto next_line;
151 } else { /* cut by fields */ 177 /* Cut by fields */
152 unsigned uu = 0, start = 0, end = 0, out = 0; 178 } else {
153 int dcount = 0; 179 unsigned next = 0, start = 0, end = 0;
180 unsigned dcount = 0; /* we saw Nth delimiter (0 - didn't see any yet) */
181
182 /* Blank line? Check -s (later check for -s does not catch empty lines) */
183 if (linelen == 0) {
184 if (option_mask32 & OPT_SUPPRESS)
185 goto next_line;
186 }
187
188 if (!odelim)
189 odelim = "\t";
190 first_print = 1;
154 191
155#if ENABLE_PLATFORM_MINGW32
156 /* An empty line can't contain a delimiter */
157 if (linelen == 0 && (option_mask32 & CUT_OPT_SUPPRESS_FLGS))
158 goto next_line;
159#endif
160 /* Loop through bytes, finding next delimiter */ 192 /* Loop through bytes, finding next delimiter */
161 for (;;) { 193 for (;;) {
162 /* End of current range? */ 194 /* End of current range? */
163 if (end == linelen || dcount > cut_lists[cl_pos].endpos) { 195 if (end == linelen || dcount > cut_list[cl_pos].endpos) {
164 if (++cl_pos >= nlists) break; 196 end_of_range:
165 if (option_mask32 & CUT_OPT_NOSORT_FLGS) 197 cl_pos++;
166 start = dcount = uu = 0; 198 if (END_OF_LIST(cut_list[cl_pos]))
167 end = 0; 199 break;
200 if (option_mask32 & OPT_NOSORT)
201 start = dcount = next = 0;
202 end = 0; /* (why?) */
203 //bb_error_msg("End of current range");
168 } 204 }
169 /* End of current line? */ 205 /* End of current line? */
170 if (uu == linelen) { 206 if (next == linelen) {
171 /* If we've seen no delimiters, check -s */ 207 end = linelen; /* print up to end */
172 if (!cl_pos && !dcount && !shoe) { 208 /* If we've seen no delimiters, and no -D, check -s */
173 if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) 209 if (!(option_mask32 & OPT_NOSORT) && cl_pos == 0 && dcount == 0) {
210 if (option_mask32 & OPT_SUPPRESS)
174 goto next_line; 211 goto next_line;
175 } else if (dcount < cut_lists[cl_pos].startpos) 212 /* else: will print entire line */
176 start = linelen; 213 } else if (dcount < cut_list[cl_pos].startpos) {
177 end = linelen; 214 /* echo 1.2 | cut -d. -f1,3: prints "1", not "1." */
215 //break;
216 /* ^^^ this fails a case with -D:
217 * echo 1 2 | cut -DF 1,3,2:
218 * do not end line processing when didn't find field#3
219 */
220 //if (option_mask32 & OPT_NOSORT) - no, just do it always
221 goto end_of_range;
222 }
223 //bb_error_msg("End of current line: s:%d e:%d", start, end);
178 } else { 224 } else {
179 /* Find next delimiter */ 225 /* Find next delimiter */
180 if (shoe) { 226#if ENABLE_FEATURE_CUT_REGEX
181 regmatch_t rr = {-1, -1}; 227 if (opt_REGEX) {
182 228 regmatch_t rr;
183 if (!regexec(&reg, line+uu, 1, &rr, REG_NOTBOL|REG_NOTEOL)) { 229 regex_t *reg = (void*) delim;
184 end = uu + rr.rm_so; 230
185 uu += rr.rm_eo; 231 if (regexec(reg, line + next, 1, &rr, REG_NOTBOL|REG_NOTEOL) != 0) {
186 } else { 232 /* not found, go to "end of line" logic */
187 uu = linelen; 233 next = linelen;
188 continue; 234 continue;
189 } 235 }
190 } else if (line[end = uu++] != *delim) 236 end = next + rr.rm_so;
191 continue; 237 next += (rr.rm_eo ? rr.rm_eo : 1);
192 238 /* ^^^ advancing by at least 1 prevents infinite loops */
193 /* Got delimiter. Loop if not yet within range. */ 239 /* testcase: echo "no at sign" | cut -d'@*' -F 1- */
194 if (dcount++ < cut_lists[cl_pos].startpos) { 240 } else
195 start = uu; 241#endif
242 {
243 end = next++;
244 if (line[end] != *delim)
245 continue;
246 }
247 /* Got delimiter */
248 dcount++;
249 if (dcount <= cut_list[cl_pos].startpos) {
250 /* Not yet within range - loop */
251 start = next;
196 continue; 252 continue;
197 } 253 }
254 /* -F N-M preserves intermediate delimiters: */
255 //printf "1 2 3 4 5 6 7\n" | toybox cut -O: -F2,4-6,7
256 //2:4 5 6:7
257 if (opt_REGEX && dcount <= cut_list[cl_pos].endpos)
258 continue;
259// NB: toybox does the above for -f too, but it's a compatibility bug:
260//printf "1 2 3 4 5 6 7 8\n" | toybox cut -d' ' -O: -f2,4-6,7
261//2:4 5 6:7 // WRONG!
262//printf "1 2 3 4 5 6 7 8\n" | cut -d' ' --output-delimiter=: -f2,4-6,7
263//2:4:5:6:7 // GNU coreutils 9.1
198 } 264 }
199 if (end != start || !shoe) 265#if ENABLE_FEATURE_CUT_REGEX
200 printf("%s%.*s", out++ ? odelim : "", end-start, line + start); 266 if (end != start || !opt_REGEX)
201 start = uu; 267#endif
202 if (!dcount) 268 {
203 break; 269 if (first_print) {
204 } 270 first_print = 0;
271 printf("%.*s", end - start, line + start);
272 } else
273 printf("%s%.*s", odelim, end - start, line + start);
274 }
275 start = next;
276 //if (dcount == 0)
277 // break; - why?
278 } /* byte loop */
205 } 279 }
206 /* if we printed anything, finish with newline */ 280 /* if we printed anything, finish with newline */
207 putchar('\n'); 281 putchar('\n');
208 next_line: 282 next_line:
209 linenum++; 283 free(line);
210 free(printed); 284 } /* while (got line) */
211 free(orig_line); 285
212 } 286 /* For -d$'\n' --output-delimiter=^, the overall output is still terminated with \n, not ^ */
287 if (!opt_REGEX && *delim == '\n' && !first_print)
288 putchar('\n');
213} 289}
214 290
215int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 291int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
216int cut_main(int argc UNUSED_PARAM, char **argv) 292int cut_main(int argc UNUSED_PARAM, char **argv)
217{ 293{
218 /* growable array holding a series of lists */ 294 /* growable array holding a series of ranges */
219 struct cut_list *cut_lists = NULL; 295 struct cut_range *cut_list = NULL;
220 unsigned nlists = 0; /* number of elements in above list */ 296 unsigned nranges = 0; /* number of elements in above list */
221 char *sopt, *ltok; 297 char *LIST, *ltok;
222 const char *delim = NULL; 298 const char *delim = NULL;
223 const char *odelim = NULL; 299 const char *odelim = NULL;
224 unsigned opt; 300 unsigned opt;
301#if ENABLE_FEATURE_CUT_REGEX
302 regex_t reg;
303#endif
304#if ENABLE_LONG_OPTS
305 static const char cut_longopts[] ALIGN1 =
306 "output-delimiter\0" Required_argument "O"
307 ;
308#endif
225 309
226#define ARG "bcf"IF_FEATURE_CUT_REGEX("F") 310#define ARG "bcf"IF_FEATURE_CUT_REGEX("F")
227 opt = getopt32(argv, "^" 311#if ENABLE_LONG_OPTS
312 opt = getopt32long
313#else
314 opt = getopt32
315#endif
316 (argv, "^"
228 OPT_STR // = "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" 317 OPT_STR // = "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n"
229 "\0" "b--"ARG":c--"ARG":f--"ARG IF_FEATURE_CUT_REGEX("F--"ARG), 318 "\0" "b:c:f:" IF_FEATURE_CUT_REGEX("F:") /* one of -bcfF is required */
230 &sopt, &sopt, &sopt, &delim, &odelim IF_FEATURE_CUT_REGEX(, &sopt) 319 "b--"ARG":c--"ARG":f--"ARG IF_FEATURE_CUT_REGEX(":F--"ARG), /* they are mutually exclusive */
231 ); 320 IF_LONG_OPTS(cut_longopts,)
232 if (!delim || !*delim) 321 &LIST, &LIST, &LIST, &delim, &odelim IF_FEATURE_CUT_REGEX(, &LIST)
233 delim = (opt & CUT_OPT_REGEX_FLGS) ? "[[:space:]]+" : "\t"; 322 );
234 if (!odelim) odelim = (opt & CUT_OPT_REGEX_FLGS) ? " " : delim; 323 if (!odelim)
324 odelim = (opt & OPT_REGEX) ? " " : delim;
325 if (!delim)
326 delim = (opt & OPT_REGEX) ? "[[:space:]]+" : "\t";
235 327
236// argc -= optind; 328// argc -= optind;
237 argv += optind; 329 argv += optind;
238 if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS | CUT_OPT_REGEX_FLGS))) 330 //if (!(opt & (OPT_BYTE | OPT_CHAR | OPT_FIELDS | OPT_REGEX)))
239 bb_simple_error_msg_and_die("expected a list of bytes, characters, or fields"); 331 // bb_simple_error_msg_and_die("expected a list of bytes, characters, or fields");
240 332 //^^^ handled by getopt32
241 /* non-field (char or byte) cutting has some special handling */ 333
242 if (!(opt & (CUT_OPT_FIELDS_FLGS|CUT_OPT_REGEX_FLGS))) { 334 /* non-field (char or byte) cutting has some special handling */
243 static const char _op_on_field[] ALIGN1 = " only when operating on fields"; 335 if (!(opt & (OPT_FIELDS|OPT_REGEX))) {
244 336 static const char requires_f[] ALIGN1 = " requires -f"
245 if (opt & CUT_OPT_SUPPRESS_FLGS) { 337 IF_FEATURE_CUT_REGEX(" or -F");
246 bb_error_msg_and_die 338 if (opt & OPT_SUPPRESS)
247 ("suppressing non-delimited lines makes sense%s", _op_on_field); 339 bb_error_msg_and_die("-s%s", requires_f);
248 } 340 if (opt & OPT_DELIM)
249 if (opt & CUT_OPT_DELIM_FLGS) { 341 bb_error_msg_and_die("-d DELIM%s", requires_f);
250 bb_error_msg_and_die
251 ("a delimiter may be specified%s", _op_on_field);
252 }
253 } 342 }
254 343
255 /* 344 /*
256 * parse list and put values into startpos and endpos. 345 * parse list and put values into startpos and endpos.
257 * valid list formats: N, N-, N-M, -M 346 * valid range formats: N, N-, N-M, -M
258 * more than one list can be separated by commas 347 * more than one range can be separated by commas
259 */ 348 */
260 { 349 /* take apart the ranges, one by one (separated with commas) */
350 while ((ltok = strsep(&LIST, ",")) != NULL) {
261 char *ntok; 351 char *ntok;
262 int s = 0, e = 0; 352 int s, e;
263 353
264 /* take apart the lists, one by one (they are separated with commas) */ 354 /* it's actually legal to pass an empty list */
265 while ((ltok = strsep(&sopt, ",")) != NULL) { 355 //if (!ltok[0])
356 // continue;
357 //^^^ testcase?
358
359 /* get the start pos */
360 ntok = strsep(&ltok, "-");
361 if (!ntok[0]) {
362 if (!ltok) /* testcase: -f '' */
363 bb_show_usage();
364 if (!ltok[0]) /* testcase: -f - */
365 bb_show_usage();
366 s = 0; /* "-M" means "1-M" */
367 } else {
368 /* "N" or "N-[M]" */
369 /* arrays are zero based, while the user expects
370 * the first field/char on the line to be char #1 */
371 s = xatoi_positive(ntok) - 1;
372 }
266 373
267 /* it's actually legal to pass an empty list */ 374 /* get the end pos */
268 if (!ltok[0]) 375 if (!ltok) {
269 continue; 376 e = s; /* "N" means "N-N" */
377 } else if (!ltok[0]) {
378 /* "N-" means "until the end of the line" */
379 e = INT_MAX;
380 } else {
381 /* again, arrays are zero based, fields are 1 based */
382 e = xatoi_positive(ltok) - 1;
383 }
270 384
271 /* get the start pos */ 385 if (s < 0 || e < s)
272 ntok = strsep(&ltok, "-"); 386 bb_error_msg_and_die("invalid range %s-%s", ntok, ltok ?: ntok);
273 if (!ntok[0]) {
274 s = 0;
275 } else {
276 s = xatoi_positive(ntok);
277 /* account for the fact that arrays are zero based, while
278 * the user expects the first char on the line to be char #1 */
279#if !ENABLE_PLATFORM_MINGW32
280 if (s != 0)
281 s--;
282#else
283 s--;
284#endif
285 }
286 387
287 /* get the end pos */ 388 /* add the new range */
288 if (ltok == NULL) { 389 cut_list = xrealloc_vector(cut_list, 4, nranges);
289 e = s; 390 /* NB: s is always >= 0 */
290 } else if (!ltok[0]) { 391 cut_list[nranges].startpos = s;
291 e = INT_MAX; 392 cut_list[nranges].endpos = e;
292 } else { 393 nranges++;
293 e = xatoi_positive(ltok); 394 }
294 /* if the user specified no end position, 395 cut_list[nranges].startpos = UINT_MAX; /* end indicator */
295 * that means "til the end of the line" */
296#if !ENABLE_PLATFORM_MINGW32
297 if (!*ltok)
298 e = INT_MAX;
299 else if (e < s)
300 bb_error_msg_and_die("%d<%d", e, s);
301#endif
302 e--; /* again, arrays are zero based, lines are 1 based */
303 }
304#if ENABLE_PLATFORM_MINGW32
305 if (s < 0 || e < s)
306 bb_error_msg_and_die("invalid range %s-%s", ntok, ltok ?: ntok);
307#endif
308 396
309 /* add the new list */ 397 /* make sure we got some cut positions out of all that */
310 cut_lists = xrealloc_vector(cut_lists, 4, nlists); 398 //if (nranges == 0)
311 /* NB: startpos is always >= 0 */ 399 // bb_simple_error_msg_and_die("missing list of positions");
312 cut_lists[nlists].startpos = s; 400 //^^^ this is impossible since one of -bcfF is required,
313 cut_lists[nlists].endpos = e; 401 // they populate LIST with non-NULL string and when it is parsed,
314 nlists++; 402 // cut_list[] gets at least one element.
315 }
316 403
317 /* make sure we got some cut positions out of all that */ 404 /* now that the lists are parsed, we need to sort them to make life
318 if (nlists == 0) 405 * easier on us when it comes time to print the chars / fields / lines
319 bb_simple_error_msg_and_die("missing list of positions"); 406 */
407 if (!(opt & OPT_NOSORT))
408 qsort(cut_list, nranges, sizeof(cut_list[0]), cmpfunc);
320 409
321 /* now that the lists are parsed, we need to sort them to make life 410#if ENABLE_FEATURE_CUT_REGEX
322 * easier on us when it comes time to print the chars / fields / lines 411 if (opt & OPT_REGEX) {
323 */ 412 xregcomp(&reg, delim, REG_EXTENDED);
324 if (!(opt & CUT_OPT_NOSORT_FLGS)) 413 delim = (void*) &reg;
325 qsort(cut_lists, nlists, sizeof(cut_lists[0]), cmpfunc);
326 } 414 }
415#endif
327 416
328 { 417 {
329 exitcode_t retval = EXIT_SUCCESS; 418 exitcode_t retval = EXIT_SUCCESS;
@@ -337,12 +426,12 @@ int cut_main(int argc UNUSED_PARAM, char **argv)
337 retval = EXIT_FAILURE; 426 retval = EXIT_FAILURE;
338 continue; 427 continue;
339 } 428 }
340 cut_file(file, delim, odelim, cut_lists, nlists); 429 cut_file(file, delim, odelim, cut_list);
341 fclose_if_not_stdin(file); 430 fclose_if_not_stdin(file);
342 } while (*++argv); 431 } while (*++argv);
343 432
344 if (ENABLE_FEATURE_CLEAN_UP) 433 if (ENABLE_FEATURE_CLEAN_UP)
345 free(cut_lists); 434 free(cut_list);
346 fflush_stdout_and_exit(retval); 435 fflush_stdout_and_exit(retval);
347 } 436 }
348} 437}
diff --git a/coreutils/df.c b/coreutils/df.c
index 03aa78148..01c41db38 100644
--- a/coreutils/df.c
+++ b/coreutils/df.c
@@ -64,7 +64,9 @@
64//usage: "[-Pk" 64//usage: "[-Pk"
65//usage: IF_FEATURE_HUMAN_READABLE("mh") 65//usage: IF_FEATURE_HUMAN_READABLE("mh")
66//usage: "T" 66//usage: "T"
67//usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE") 67//usage: IF_FEATURE_DF_FANCY("a"
68//usage: IF_PLATFORM_POSIX("i")
69//usage: "] [-B SIZE")
68//usage: "] [-t TYPE] [FILESYSTEM]..." 70//usage: "] [-t TYPE] [FILESYSTEM]..."
69//usage:#define df_full_usage "\n\n" 71//usage:#define df_full_usage "\n\n"
70//usage: "Print filesystem usage statistics\n" 72//usage: "Print filesystem usage statistics\n"
@@ -78,7 +80,9 @@
78//usage: "\n -t TYPE Print only mounts of this type" 80//usage: "\n -t TYPE Print only mounts of this type"
79//usage: IF_FEATURE_DF_FANCY( 81//usage: IF_FEATURE_DF_FANCY(
80//usage: "\n -a Show all filesystems" 82//usage: "\n -a Show all filesystems"
83//usage: IF_PLATFORM_POSIX(
81//usage: "\n -i Inodes" 84//usage: "\n -i Inodes"
85//usage: )
82//usage: "\n -B SIZE Blocksize" 86//usage: "\n -B SIZE Blocksize"
83//usage: ) 87//usage: )
84//usage: 88//usage:
@@ -109,6 +113,12 @@ static unsigned long kscale(unsigned long b, unsigned long bs)
109} 113}
110#endif 114#endif
111 115
116#if ENABLE_PLATFORM_MINGW32
117# define ENABLE_FEATURE_DF_FANCY_POSIX 0
118#else
119# define ENABLE_FEATURE_DF_FANCY_POSIX ENABLE_FEATURE_DF_FANCY
120#endif
121
112int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 122int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
113int df_main(int argc UNUSED_PARAM, char **argv) 123int df_main(int argc UNUSED_PARAM, char **argv)
114{ 124{
@@ -124,11 +134,11 @@ int df_main(int argc UNUSED_PARAM, char **argv)
124 OPT_FSTYPE = (1 << 2), 134 OPT_FSTYPE = (1 << 2),
125 OPT_t = (1 << 3), 135 OPT_t = (1 << 3),
126 OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY, 136 OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY,
127 OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY, 137 OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY_POSIX,
128 OPT_BSIZE = (1 << 6) * ENABLE_FEATURE_DF_FANCY, 138 OPT_BSIZE = (1 << (5 + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_DF_FANCY,
129 OPT_HUMAN = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, 139 OPT_HUMAN = (1 << (4 + 2*ENABLE_FEATURE_DF_FANCY + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_HUMAN_READABLE,
130 OPT_HUMANDEC = (1 << (5 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, 140 OPT_HUMANDEC = (1 << (5 + 2*ENABLE_FEATURE_DF_FANCY + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_HUMAN_READABLE,
131 OPT_MEGA = (1 << (6 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, 141 OPT_MEGA = (1 << (6 + 2*ENABLE_FEATURE_DF_FANCY + ENABLE_FEATURE_DF_FANCY_POSIX)) * ENABLE_FEATURE_HUMAN_READABLE,
132 }; 142 };
133 const char *disp_units_hdr = NULL; 143 const char *disp_units_hdr = NULL;
134 char *chp, *opt_t; 144 char *chp, *opt_t;
@@ -144,7 +154,11 @@ int df_main(int argc UNUSED_PARAM, char **argv)
144 154
145 opt = getopt32(argv, "^" 155 opt = getopt32(argv, "^"
146 "kPTt:" 156 "kPTt:"
157#if ENABLE_PLATFORM_POSIX
147 IF_FEATURE_DF_FANCY("aiB:") 158 IF_FEATURE_DF_FANCY("aiB:")
159#else
160 IF_FEATURE_DF_FANCY("aB:")
161#endif
148 IF_FEATURE_HUMAN_READABLE("hHm") 162 IF_FEATURE_HUMAN_READABLE("hHm")
149 "\0" 163 "\0"
150#if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY 164#if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY
@@ -155,6 +169,9 @@ int df_main(int argc UNUSED_PARAM, char **argv)
155 , &opt_t 169 , &opt_t
156 IF_FEATURE_DF_FANCY(, &chp) 170 IF_FEATURE_DF_FANCY(, &chp)
157 ); 171 );
172 /* -k overrides $POSIXLY_CORRECT: */
173 if (opt & OPT_KILO)
174 df_disp_hr = 1024;
158 if (opt & OPT_MEGA) 175 if (opt & OPT_MEGA)
159 df_disp_hr = 1024*1024; 176 df_disp_hr = 1024*1024;
160 177
@@ -185,8 +202,8 @@ int df_main(int argc UNUSED_PARAM, char **argv)
185 if (disp_units_hdr == NULL) { 202 if (disp_units_hdr == NULL) {
186#if ENABLE_FEATURE_HUMAN_READABLE 203#if ENABLE_FEATURE_HUMAN_READABLE
187 disp_units_hdr = xasprintf("%s-blocks", 204 disp_units_hdr = xasprintf("%s-blocks",
188 /* print df_disp_hr, show no fractionals, 205 /* print df_disp_hr; show no fractionals;
189 * use suffixes if OPT_POSIX is set in opt */ 206 * if -P, unit=1 (print it in full, no KMG suffixes) */
190 make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX)) 207 make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX))
191 ); 208 );
192#else 209#else
diff --git a/coreutils/expr.c b/coreutils/expr.c
index 3f7e21871..c00559e4c 100644
--- a/coreutils/expr.c
+++ b/coreutils/expr.c
@@ -97,6 +97,10 @@ typedef long arith_t;
97 97
98/* TODO: use bb_strtol[l]? It's easier to check for errors... */ 98/* TODO: use bb_strtol[l]? It's easier to check for errors... */
99 99
100#if ENABLE_PLATFORM_MINGW32
101# define STRING BB_STRING
102#endif
103
100/* The kinds of value we can have. */ 104/* The kinds of value we can have. */
101enum { 105enum {
102 INTEGER, 106 INTEGER,
diff --git a/coreutils/stty.c b/coreutils/stty.c
index c88ef07f4..92d5838c0 100644
--- a/coreutils/stty.c
+++ b/coreutils/stty.c
@@ -20,14 +20,30 @@
20//kbuild:lib-$(CONFIG_STTY) += stty.o 20//kbuild:lib-$(CONFIG_STTY) += stty.o
21 21
22//usage:#define stty_trivial_usage 22//usage:#define stty_trivial_usage
23//usage: IF_NOT_PLATFORM_MINGW32(
23//usage: "[-a|g] [-F DEVICE] [SETTING]..." 24//usage: "[-a|g] [-F DEVICE] [SETTING]..."
25//usage: )
26//usage: IF_PLATFORM_MINGW32(
27//usage: "[-a] [SETTING]..."
28//usage: )
24//usage:#define stty_full_usage "\n\n" 29//usage:#define stty_full_usage "\n\n"
30//usage: IF_NOT_PLATFORM_MINGW32(
25//usage: "Without arguments, prints baud rate, line discipline,\n" 31//usage: "Without arguments, prints baud rate, line discipline,\n"
26//usage: "and deviations from stty sane\n" 32//usage: "and deviations from stty sane\n"
27//usage: "\n -F DEVICE Open device instead of stdin" 33//usage: "\n -F DEVICE Open device instead of stdin"
34//usage: )
35//usage: IF_PLATFORM_MINGW32(
36//usage: "Without arguments, prints deviations from stty sane\n"
37//usage: )
28//usage: "\n -a Print all current settings in human-readable form" 38//usage: "\n -a Print all current settings in human-readable form"
39//usage: IF_NOT_PLATFORM_MINGW32(
29//usage: "\n -g Print in stty-readable form" 40//usage: "\n -g Print in stty-readable form"
30//usage: "\n [SETTING] See manpage" 41//usage: "\n [SETTING] See manpage"
42//usage: )
43//usage: IF_PLATFORM_MINGW32(
44//usage: "\n [SETTING] [-]echo [-]cooked [-]raw sane"
45//usage: "\n cols N rows N size"
46//usage: )
31 47
32/* If no args are given, write to stdout the baud rate and settings that 48/* If no args are given, write to stdout the baud rate and settings that
33 * have been changed from their defaults. Mode reading and changes 49 * have been changed from their defaults. Mode reading and changes
@@ -294,6 +310,7 @@ struct mode_info {
294 const tcflag_t bits; /* Bits to set for this mode */ 310 const tcflag_t bits; /* Bits to set for this mode */
295}; 311};
296 312
313#if !ENABLE_PLATFORM_MINGW32
297enum { 314enum {
298 /* Must match mode_name[] and mode_info[] order! */ 315 /* Must match mode_name[] and mode_info[] order! */
299 IDX_evenp = 0, 316 IDX_evenp = 0,
@@ -320,19 +337,30 @@ enum {
320 IDX_LCASE, 337 IDX_LCASE,
321#endif 338#endif
322}; 339};
340#else
341enum {
342 /* Must match mode_name[] and mode_info[] order! */
343 IDX_sane = 0,
344 IDX_cooked,
345 IDX_raw,
346};
347#endif
323 348
324#define MI_ENTRY(N,T,F,B,M) N "\0" 349#define MI_ENTRY(N,T,F,B,M) N "\0"
325 350
326/* Mode names given on command line */ 351/* Mode names given on command line */
327static const char mode_name[] ALIGN1 = 352static const char mode_name[] ALIGN1 =
353#if !ENABLE_PLATFORM_MINGW32
328 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) 354 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
329 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) 355 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
330 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) 356 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
331 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) 357 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
332 MI_ENTRY("ek", combination, OMIT, 0, 0 ) 358 MI_ENTRY("ek", combination, OMIT, 0, 0 )
359#endif
333 MI_ENTRY("sane", combination, OMIT, 0, 0 ) 360 MI_ENTRY("sane", combination, OMIT, 0, 0 )
334 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) 361 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
335 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) 362 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
363#if !ENABLE_PLATFORM_MINGW32
336 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) 364 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
337 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) 365 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
338 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) 366 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
@@ -454,7 +482,9 @@ static const char mode_name[] ALIGN1 =
454#if IEXTEN 482#if IEXTEN
455 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) 483 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
456#endif 484#endif
485#endif /* !ENABLE_PLATFORM_MINGW32 */
457 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) 486 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
487#if !ENABLE_PLATFORM_MINGW32
458 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) 488 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
459 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) 489 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
460 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) 490 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
@@ -482,6 +512,7 @@ static const char mode_name[] ALIGN1 =
482#ifdef EXTPROC 512#ifdef EXTPROC
483 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) 513 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
484#endif 514#endif
515#endif /* !ENABLE_PLATFORM_MINGW32 */
485 ; 516 ;
486 517
487#undef MI_ENTRY 518#undef MI_ENTRY
@@ -489,14 +520,17 @@ static const char mode_name[] ALIGN1 =
489 520
490static const struct mode_info mode_info[] ALIGN4 = { 521static const struct mode_info mode_info[] ALIGN4 = {
491 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */ 522 /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */
523#if !ENABLE_PLATFORM_MINGW32
492 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) 524 MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 )
493 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) 525 MI_ENTRY("parity", combination, REV | OMIT, 0, 0 )
494 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) 526 MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 )
495 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) 527 MI_ENTRY("nl", combination, REV | OMIT, 0, 0 )
496 MI_ENTRY("ek", combination, OMIT, 0, 0 ) 528 MI_ENTRY("ek", combination, OMIT, 0, 0 )
529#endif
497 MI_ENTRY("sane", combination, OMIT, 0, 0 ) 530 MI_ENTRY("sane", combination, OMIT, 0, 0 )
498 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) 531 MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 )
499 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) 532 MI_ENTRY("raw", combination, REV | OMIT, 0, 0 )
533#if !ENABLE_PLATFORM_MINGW32
500 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) 534 MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 )
501 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) 535 MI_ENTRY("litout", combination, REV | OMIT, 0, 0 )
502 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) 536 MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 )
@@ -618,7 +652,9 @@ static const struct mode_info mode_info[] ALIGN4 = {
618#if IEXTEN 652#if IEXTEN
619 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) 653 MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 )
620#endif 654#endif
655#endif /* !ENABLE_PLATFORM_MINGW32 */
621 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) 656 MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 )
657#if !ENABLE_PLATFORM_MINGW32
622 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) 658 MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 )
623 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) 659 MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 )
624 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) 660 MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 )
@@ -646,6 +682,7 @@ static const struct mode_info mode_info[] ALIGN4 = {
646#ifdef EXTPROC 682#ifdef EXTPROC
647 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) 683 MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 )
648#endif 684#endif
685#endif /* !ENABLE_PLATFORM_MINGW32 */
649}; 686};
650 687
651enum { 688enum {
@@ -653,6 +690,7 @@ enum {
653}; 690};
654 691
655 692
693#if !ENABLE_PLATFORM_MINGW32
656/* Control characters */ 694/* Control characters */
657struct control_info { 695struct control_info {
658 const uint8_t saneval; /* Value to set for 'stty sane' */ 696 const uint8_t saneval; /* Value to set for 'stty sane' */
@@ -786,6 +824,7 @@ static const struct control_info control_info[] ALIGN2 = {
786enum { 824enum {
787 NUM_control_info = ARRAY_SIZE(control_info) 825 NUM_control_info = ARRAY_SIZE(control_info)
788}; 826};
827#endif
789 828
790 829
791struct globals { 830struct globals {
@@ -803,6 +842,7 @@ struct globals {
803 G.current_col = 0; /* we are noexec, must clear */ \ 842 G.current_col = 0; /* we are noexec, must clear */ \
804} while (0) 843} while (0)
805 844
845#if !ENABLE_PLATFORM_MINGW32
806static void set_speed_or_die(enum speed_setting type, const char *arg, 846static void set_speed_or_die(enum speed_setting type, const char *arg,
807 struct termios *mode) 847 struct termios *mode)
808{ 848{
@@ -817,6 +857,7 @@ static void set_speed_or_die(enum speed_setting type, const char *arg,
817 cfsetospeed(mode, baud); 857 cfsetospeed(mode, baud);
818 } 858 }
819} 859}
860#endif
820 861
821static NORETURN void perror_on_device_and_die(const char *fmt) 862static NORETURN void perror_on_device_and_die(const char *fmt)
822{ 863{
@@ -918,6 +959,7 @@ static const struct mode_info *find_mode(const char *name)
918 return i >= 0 ? &mode_info[i] : NULL; 959 return i >= 0 ? &mode_info[i] : NULL;
919} 960}
920 961
962#if !ENABLE_PLATFORM_MINGW32
921static const struct control_info *find_control(const char *name) 963static const struct control_info *find_control(const char *name)
922{ 964{
923 int i = index_in_strings(control_name, name); 965 int i = index_in_strings(control_name, name);
@@ -954,7 +996,32 @@ static int find_param(const char *name)
954 i |= 0x80; 996 i |= 0x80;
955 return i; 997 return i;
956} 998}
999#else
1000enum {
1001 param_need_arg = 0x80,
1002 param_rows = 1 | 0x80,
1003 param_cols = 2 | 0x80,
1004 param_columns = 3 | 0x80,
1005 param_size = 4,
1006};
957 1007
1008static int find_param(const char *name)
1009{
1010 static const char params[] ALIGN1 =
1011 "rows\0" /* 1 */
1012 "cols\0" /* 2 */
1013 "columns\0" /* 3 */
1014 "size\0"; /* 4 */
1015 int i = index_in_strings(params, name) + 1;
1016 if (i == 0)
1017 return 0;
1018 if (i != 4)
1019 i |= 0x80;
1020 return i;
1021}
1022#endif
1023
1024#if !ENABLE_PLATFORM_MINGW32
958static int recover_mode(const char *arg, struct termios *mode) 1025static int recover_mode(const char *arg, struct termios *mode)
959{ 1026{
960 int i, n; 1027 int i, n;
@@ -1013,6 +1080,9 @@ static void display_speed(const struct termios *mode, int fancy)
1013 if (fancy) fmt_str += 9; 1080 if (fancy) fmt_str += 9;
1014 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed)); 1081 wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed));
1015} 1082}
1083#else
1084# define display_speed(m, f) ((void)0)
1085#endif
1016 1086
1017static void do_display(const struct termios *mode, int all) 1087static void do_display(const struct termios *mode, int all)
1018{ 1088{
@@ -1030,6 +1100,7 @@ static void do_display(const struct termios *mode, int all)
1030 newline(); 1100 newline();
1031#endif 1101#endif
1032 1102
1103#if !ENABLE_PLATFORM_MINGW32
1033 for (i = 0; i != CIDX_min; ++i) { 1104 for (i = 0; i != CIDX_min; ++i) {
1034 char ch; 1105 char ch;
1035 char buf10[10]; 1106 char buf10[10];
@@ -1059,6 +1130,7 @@ static void do_display(const struct termios *mode, int all)
1059#endif 1130#endif
1060 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]); 1131 wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1061 newline(); 1132 newline();
1133#endif
1062 1134
1063 for (i = 0; i < NUM_mode_info; ++i) { 1135 for (i = 0; i < NUM_mode_info; ++i) {
1064 if (mode_info[i].flags & OMIT) 1136 if (mode_info[i].flags & OMIT)
@@ -1086,6 +1158,7 @@ static void do_display(const struct termios *mode, int all)
1086 1158
1087static void sane_mode(struct termios *mode) 1159static void sane_mode(struct termios *mode)
1088{ 1160{
1161#if !ENABLE_PLATFORM_MINGW32
1089 int i; 1162 int i;
1090 1163
1091 for (i = 0; i < NUM_control_info; ++i) { 1164 for (i = 0; i < NUM_control_info; ++i) {
@@ -1110,6 +1183,11 @@ static void sane_mode(struct termios *mode)
1110 *bitsp = val & ~mode_info[i].bits; 1183 *bitsp = val & ~mode_info[i].bits;
1111 } 1184 }
1112 } 1185 }
1186#else
1187 mode->c_lflag |= ECHO;
1188 mode->w_mode |= ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT |
1189 ENABLE_PROCESSED_INPUT;
1190#endif
1113} 1191}
1114 1192
1115static void set_mode(const struct mode_info *info, int reversed, 1193static void set_mode(const struct mode_info *info, int reversed,
@@ -1129,6 +1207,7 @@ static void set_mode(const struct mode_info *info, int reversed,
1129 } 1207 }
1130 1208
1131 /* !bitsp - it's a "combination" mode */ 1209 /* !bitsp - it's a "combination" mode */
1210#if !ENABLE_PLATFORM_MINGW32
1132 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) { 1211 if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) {
1133 if (reversed) 1212 if (reversed)
1134 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; 1213 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
@@ -1150,9 +1229,14 @@ static void set_mode(const struct mode_info *info, int reversed,
1150 } else if (info == &mode_info[IDX_ek]) { 1229 } else if (info == &mode_info[IDX_ek]) {
1151 mode->c_cc[VERASE] = CERASE; 1230 mode->c_cc[VERASE] = CERASE;
1152 mode->c_cc[VKILL] = CKILL; 1231 mode->c_cc[VKILL] = CKILL;
1153 } else if (info == &mode_info[IDX_sane]) { 1232 }
1233 else
1234#endif /* !ENABLE_PLATFORM_MINGW32 */
1235 if (info == &mode_info[IDX_sane]) {
1154 sane_mode(mode); 1236 sane_mode(mode);
1155 } else if (info == &mode_info[IDX_cbreak]) { 1237 }
1238#if !ENABLE_PLATFORM_MINGW32
1239 else if (info == &mode_info[IDX_cbreak]) {
1156 if (reversed) 1240 if (reversed)
1157 mode->c_lflag |= ICANON; 1241 mode->c_lflag |= ICANON;
1158 else 1242 else
@@ -1175,11 +1259,14 @@ static void set_mode(const struct mode_info *info, int reversed,
1175 mode->c_iflag &= ~ISTRIP; 1259 mode->c_iflag &= ~ISTRIP;
1176 mode->c_oflag &= ~OPOST; 1260 mode->c_oflag &= ~OPOST;
1177 } 1261 }
1178 } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) { 1262 }
1263#endif /* !ENABLE_PLATFORM_MINGW32 */
1264 else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) {
1179 if ((info == &mode_info[IDX_raw] && reversed) 1265 if ((info == &mode_info[IDX_raw] && reversed)
1180 || (info == &mode_info[IDX_cooked] && !reversed) 1266 || (info == &mode_info[IDX_cooked] && !reversed)
1181 ) { 1267 ) {
1182 /* Cooked mode */ 1268 /* Cooked mode */
1269#if !ENABLE_PLATFORM_MINGW32
1183 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; 1270 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1184 mode->c_oflag |= OPOST; 1271 mode->c_oflag |= OPOST;
1185 mode->c_lflag |= ISIG | ICANON; 1272 mode->c_lflag |= ISIG | ICANON;
@@ -1189,15 +1276,23 @@ static void set_mode(const struct mode_info *info, int reversed,
1189#if VTIME == VEOL 1276#if VTIME == VEOL
1190 mode->c_cc[VEOL] = CEOL; 1277 mode->c_cc[VEOL] = CEOL;
1191#endif 1278#endif
1279#else
1280 mode->w_mode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
1281#endif
1192 } else { 1282 } else {
1193 /* Raw mode */ 1283 /* Raw mode */
1284#if !ENABLE_PLATFORM_MINGW32
1194 mode->c_iflag = 0; 1285 mode->c_iflag = 0;
1195 mode->c_oflag &= ~OPOST; 1286 mode->c_oflag &= ~OPOST;
1196 mode->c_lflag &= ~(ISIG | ICANON | XCASE); 1287 mode->c_lflag &= ~(ISIG | ICANON | XCASE);
1197 mode->c_cc[VMIN] = 1; 1288 mode->c_cc[VMIN] = 1;
1198 mode->c_cc[VTIME] = 0; 1289 mode->c_cc[VTIME] = 0;
1290#else
1291 mode->w_mode &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
1292#endif
1199 } 1293 }
1200 } 1294 }
1295#if !ENABLE_PLATFORM_MINGW32
1201#if IXANY 1296#if IXANY
1202 else if (info == &mode_info[IDX_decctlq]) { 1297 else if (info == &mode_info[IDX_decctlq]) {
1203 if (reversed) 1298 if (reversed)
@@ -1244,8 +1339,10 @@ static void set_mode(const struct mode_info *info, int reversed,
1244 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE; 1339 mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE;
1245 if (IXANY) mode->c_iflag &= ~IXANY; 1340 if (IXANY) mode->c_iflag &= ~IXANY;
1246 } 1341 }
1342#endif /*!ENABLE_PLATFORM_MINGW32 */
1247} 1343}
1248 1344
1345#if !ENABLE_PLATFORM_MINGW32
1249static void set_control_char_or_die(const struct control_info *info, 1346static void set_control_char_or_die(const struct control_info *info,
1250 const char *arg, struct termios *mode) 1347 const char *arg, struct termios *mode)
1251{ 1348{
@@ -1265,6 +1362,7 @@ static void set_control_char_or_die(const struct control_info *info,
1265 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); 1362 value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes);
1266 mode->c_cc[info->offset] = value; 1363 mode->c_cc[info->offset] = value;
1267} 1364}
1365#endif
1268 1366
1269#define STTY_require_set_attr (1 << 0) 1367#define STTY_require_set_attr (1 << 0)
1270#define STTY_speed_was_set (1 << 1) 1368#define STTY_speed_was_set (1 << 1)
@@ -1277,7 +1375,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1277{ 1375{
1278 struct termios mode; 1376 struct termios mode;
1279 void (*output_func)(const struct termios *, int); 1377 void (*output_func)(const struct termios *, int);
1378#if !ENABLE_PLATFORM_MINGW32
1280 const char *file_name = NULL; 1379 const char *file_name = NULL;
1380#endif
1281 int display_all = 0; 1381 int display_all = 0;
1282 int stty_state; 1382 int stty_state;
1283 int k; 1383 int k;
@@ -1291,7 +1391,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1291 k = 0; 1391 k = 0;
1292 while (argv[++k]) { 1392 while (argv[++k]) {
1293 const struct mode_info *mp; 1393 const struct mode_info *mp;
1394#if !ENABLE_PLATFORM_MINGW32
1294 const struct control_info *cp; 1395 const struct control_info *cp;
1396#endif
1295 const char *arg = argv[k]; 1397 const char *arg = argv[k];
1296 const char *argnext = argv[k+1]; 1398 const char *argnext = argv[k+1];
1297 int param; 1399 int param;
@@ -1314,6 +1416,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1314 output_func = do_display; 1416 output_func = do_display;
1315 display_all = 1; 1417 display_all = 1;
1316 break; 1418 break;
1419#if !ENABLE_PLATFORM_MINGW32
1317 case 'g': 1420 case 'g':
1318 stty_state |= STTY_recoverable_output; 1421 stty_state |= STTY_recoverable_output;
1319 output_func = display_recoverable; 1422 output_func = display_recoverable;
@@ -1334,11 +1437,14 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1334 } 1437 }
1335 } 1438 }
1336 goto end_option; 1439 goto end_option;
1440#endif
1337 default: 1441 default:
1338 goto invalid_argument; 1442 goto invalid_argument;
1339 } 1443 }
1340 } 1444 }
1445#if !ENABLE_PLATFORM_MINGW32
1341 end_option: 1446 end_option:
1447#endif
1342 continue; 1448 continue;
1343 } 1449 }
1344 1450
@@ -1348,6 +1454,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1348 continue; 1454 continue;
1349 } 1455 }
1350 1456
1457#if !ENABLE_PLATFORM_MINGW32
1351 cp = find_control(arg); 1458 cp = find_control(arg);
1352 if (cp) { 1459 if (cp) {
1353 if (!argnext) 1460 if (!argnext)
@@ -1358,6 +1465,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1358 ++k; 1465 ++k;
1359 continue; 1466 continue;
1360 } 1467 }
1468#endif
1361 1469
1362 param = find_param(arg); 1470 param = find_param(arg);
1363 if (param & param_need_arg) { 1471 if (param & param_need_arg) {
@@ -1381,7 +1489,11 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1381 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); 1489 xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes);
1382 break; 1490 break;
1383 case param_size: 1491 case param_size:
1492# if ENABLE_PLATFORM_MINGW32
1493 break;
1494# endif
1384#endif 1495#endif
1496#if !ENABLE_PLATFORM_MINGW32
1385 case param_speed: 1497 case param_speed:
1386 break; 1498 break;
1387 case param_ispeed: 1499 case param_ispeed:
@@ -1392,15 +1504,19 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1392 /* called for the side effect of xfunc death only */ 1504 /* called for the side effect of xfunc death only */
1393 set_speed_or_die(output_speed, argnext, &mode); 1505 set_speed_or_die(output_speed, argnext, &mode);
1394 break; 1506 break;
1507#endif
1395 default: 1508 default:
1509#if !ENABLE_PLATFORM_MINGW32
1396 if (recover_mode(arg, &mode) == 1) break; 1510 if (recover_mode(arg, &mode) == 1) break;
1397 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break; 1511 if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break;
1512#endif
1398 invalid_argument: 1513 invalid_argument:
1399 bb_error_msg_and_die("invalid argument '%s'", arg); 1514 bb_error_msg_and_die("invalid argument '%s'", arg);
1400 } 1515 }
1401 stty_state &= ~STTY_noargs; 1516 stty_state &= ~STTY_noargs;
1402 } 1517 }
1403 1518
1519#if !ENABLE_PLATFORM_MINGW32
1404 /* Specifying both -a and -g is an error */ 1520 /* Specifying both -a and -g is an error */
1405 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) == 1521 if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) ==
1406 (STTY_verbose_output | STTY_recoverable_output) 1522 (STTY_verbose_output | STTY_recoverable_output)
@@ -1413,13 +1529,22 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1413 ) { 1529 ) {
1414 bb_simple_error_msg_and_die("modes may not be set when -a or -g is used"); 1530 bb_simple_error_msg_and_die("modes may not be set when -a or -g is used");
1415 } 1531 }
1532#else
1533 /* Specifying -a with non-options is an error */
1534 if ((stty_state & STTY_verbose_output) && !(stty_state & STTY_noargs)
1535 ) {
1536 bb_simple_error_msg_and_die("modes may not be set when -a is used");
1537 }
1538#endif
1416 1539
1540#if !ENABLE_PLATFORM_MINGW32
1417 /* Now it is safe to start doing things */ 1541 /* Now it is safe to start doing things */
1418 if (file_name) { 1542 if (file_name) {
1419 G.device_name = file_name; 1543 G.device_name = file_name;
1420 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO); 1544 xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO);
1421 ndelay_off(STDIN_FILENO); 1545 ndelay_off(STDIN_FILENO);
1422 } 1546 }
1547#endif
1423 1548
1424 /* Initialize to all zeroes so there is no risk memcmp will report a 1549 /* Initialize to all zeroes so there is no risk memcmp will report a
1425 spurious difference in an uninitialized portion of the structure */ 1550 spurious difference in an uninitialized portion of the structure */
@@ -1437,7 +1562,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1437 k = 0; 1562 k = 0;
1438 while (argv[++k]) { 1563 while (argv[++k]) {
1439 const struct mode_info *mp; 1564 const struct mode_info *mp;
1565#if !ENABLE_PLATFORM_MINGW32
1440 const struct control_info *cp; 1566 const struct control_info *cp;
1567#endif
1441 const char *arg = argv[k]; 1568 const char *arg = argv[k];
1442 const char *argnext = argv[k+1]; 1569 const char *argnext = argv[k+1];
1443 int param; 1570 int param;
@@ -1459,6 +1586,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1459 continue; 1586 continue;
1460 } 1587 }
1461 1588
1589#if !ENABLE_PLATFORM_MINGW32
1462 cp = find_control(arg); 1590 cp = find_control(arg);
1463 if (cp) { 1591 if (cp) {
1464 ++k; 1592 ++k;
@@ -1466,6 +1594,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1466 stty_state |= STTY_require_set_attr; 1594 stty_state |= STTY_require_set_attr;
1467 continue; 1595 continue;
1468 } 1596 }
1597#endif
1469 1598
1470 param = find_param(arg); 1599 param = find_param(arg);
1471 if (param & param_need_arg) { 1600 if (param & param_need_arg) {
@@ -1491,6 +1620,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1491 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1); 1620 set_window_size(xatoul_sfx(argnext, stty_suffixes), -1);
1492 break; 1621 break;
1493#endif 1622#endif
1623#if !ENABLE_PLATFORM_MINGW32
1494 case param_speed: 1624 case param_speed:
1495 display_speed(&mode, 0); 1625 display_speed(&mode, 0);
1496 break; 1626 break;
@@ -1502,7 +1632,9 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1502 set_speed_or_die(output_speed, argnext, &mode); 1632 set_speed_or_die(output_speed, argnext, &mode);
1503 stty_state |= (STTY_require_set_attr | STTY_speed_was_set); 1633 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1504 break; 1634 break;
1635#endif
1505 default: 1636 default:
1637#if !ENABLE_PLATFORM_MINGW32
1506 if (recover_mode(arg, &mode) == 1) 1638 if (recover_mode(arg, &mode) == 1)
1507 stty_state |= STTY_require_set_attr; 1639 stty_state |= STTY_require_set_attr;
1508 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{ 1640 else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{
@@ -1510,15 +1642,24 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1510 stty_state |= (STTY_require_set_attr | STTY_speed_was_set); 1642 stty_state |= (STTY_require_set_attr | STTY_speed_was_set);
1511 } /* else - impossible (caught in the first pass): 1643 } /* else - impossible (caught in the first pass):
1512 bb_error_msg_and_die("invalid argument '%s'", arg); */ 1644 bb_error_msg_and_die("invalid argument '%s'", arg); */
1645#endif
1513 } 1646 }
1514 } 1647 }
1515 1648
1516 if (stty_state & STTY_require_set_attr) { 1649 if (stty_state & STTY_require_set_attr) {
1650#if !ENABLE_PLATFORM_MINGW32
1517 struct termios new_mode; 1651 struct termios new_mode;
1652#else
1653 if (mode.c_lflag & ECHO)
1654 mode.w_mode |= ENABLE_ECHO_INPUT;
1655 else
1656 mode.w_mode &= ~ENABLE_ECHO_INPUT;
1657#endif
1518 1658
1519 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode)) 1659 if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode))
1520 perror_on_device_and_die("%s"); 1660 perror_on_device_and_die("%s");
1521 1661
1662#if !ENABLE_PLATFORM_MINGW32
1522 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if 1663 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1523 it performs *any* of the requested operations. This means it 1664 it performs *any* of the requested operations. This means it
1524 can report 'success' when it has actually failed to perform 1665 can report 'success' when it has actually failed to perform
@@ -1554,6 +1695,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv)
1554#endif 1695#endif
1555 perror_on_device_and_die("%s: cannot perform all requested operations"); 1696 perror_on_device_and_die("%s: cannot perform all requested operations");
1556 } 1697 }
1698#endif
1557 } 1699 }
1558 1700
1559 return EXIT_SUCCESS; 1701 return EXIT_SUCCESS;
diff --git a/coreutils/truncate.c b/coreutils/truncate.c
index 8826e6b4c..87a47bb09 100644
--- a/coreutils/truncate.c
+++ b/coreutils/truncate.c
@@ -73,6 +73,12 @@ int truncate_main(int argc UNUSED_PARAM, char **argv)
73 * do not report error, exitcode is also 0. 73 * do not report error, exitcode is also 0.
74 */ 74 */
75 } else { 75 } else {
76#if ENABLE_PLATFORM_MINGW32
77 struct stat st;
78
79 if (fstat(fd, &st) == 0 && size > st.st_size)
80 make_sparse(fd, st.st_size, size);
81#endif
76 if (ftruncate(fd, size) == -1) { 82 if (ftruncate(fd, size) == -1) {
77 bb_perror_msg("%s: truncate", *argv); 83 bb_perror_msg("%s: truncate", *argv);
78 ret = EXIT_FAILURE; 84 ret = EXIT_FAILURE;
diff --git a/editors/diff.c b/editors/diff.c
index b324feaa5..8911859cd 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -773,7 +773,7 @@ static int diffreg(char *file[2])
773 fd = fd_tmp; 773 fd = fd_tmp;
774 xlseek(fd, 0, SEEK_SET); 774 xlseek(fd, 0, SEEK_SET);
775 } 775 }
776 fp[i] = fdopen(fd, "r"); 776 fp[i] = xfdopen_for_read(fd);
777 } 777 }
778 778
779 setup_common_bufsiz(); 779 setup_common_bufsiz();
diff --git a/editors/sed.c b/editors/sed.c
index 107e664a0..204417108 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -257,7 +257,12 @@ static FILE *sed_xfopen_w(const char *fname)
257 257
258static void cleanup_outname(void) 258static void cleanup_outname(void)
259{ 259{
260 if (G.outname) unlink(G.outname); 260 if (G.outname) {
261#if ENABLE_PLATFORM_MINGW32
262 fclose(G.nonstdout);
263#endif
264 unlink(G.outname);
265 }
261} 266}
262 267
263/* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */ 268/* strcpy, replacing "\from" with 'to'. If to is NUL, replacing "\any" with 'any' */
diff --git a/findutils/xargs.c b/findutils/xargs.c
index f0abf1a23..83af75521 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -846,11 +846,11 @@ int xargs_main(int argc UNUSED_PARAM, char **argv)
846 * arguments, but not if the command is a NOFORK applet. If the rules 846 * arguments, but not if the command is a NOFORK applet. If the rules
847 * to detect this situation change xargs_exec() above will also need 847 * to detect this situation change xargs_exec() above will also need
848 * to be updated. */ 848 * to be updated. */
849# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL 849# if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1)
850# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL
850 if (G.max_procs == 1) 851 if (G.max_procs == 1)
851# endif 852# endif
852 { 853 {
853# if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1)
854 int applet = find_applet_by_name(argv[0]); 854 int applet = find_applet_by_name(argv[0]);
855 if (applet >= 0 && APPLET_IS_NOFORK(applet)) { 855 if (applet >= 0 && APPLET_IS_NOFORK(applet)) {
856 quote = FALSE; 856 quote = FALSE;
diff --git a/include/libbb.h b/include/libbb.h
index bc1453e12..8dc4e4992 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -281,6 +281,26 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
281# endif 281# endif
282#endif 282#endif
283 283
284#if ENABLE_FEATURE_TLS_SCHANNEL || ENABLE_FEATURE_USE_CNG_API
285# define SECURITY_WIN32
286# include <windows.h>
287# include <security.h>
288#endif
289
290#if ENABLE_FEATURE_USE_CNG_API
291# include <bcrypt.h>
292
293// these work on Windows >= 10
294# define BCRYPT_HMAC_SHA1_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x000000a1)
295# define BCRYPT_HMAC_SHA256_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x000000b1)
296# define sha1_begin_hmac BCRYPT_HMAC_SHA1_ALG_HANDLE
297# define sha256_begin_hmac BCRYPT_HMAC_SHA256_ALG_HANDLE
298#else
299# define sha1_begin_hmac sha1_begin
300# define sha256_begin_hmac sha256_begin
301# define hmac_uninit(...) ((void)0)
302#endif
303
284/* Tested to work correctly with all int types (IIRC :]) */ 304/* Tested to work correctly with all int types (IIRC :]) */
285#define MAXINT(T) (T)( \ 305#define MAXINT(T) (T)( \
286 ((T)-1) > 0 \ 306 ((T)-1) > 0 \
@@ -899,7 +919,36 @@ struct hostent *xgethostbyname(const char *name) FAST_FUNC;
899// Also mount.c and inetd.c are using gethostbyname(), 919// Also mount.c and inetd.c are using gethostbyname(),
900// + inet_common.c has additional IPv4-only stuff 920// + inet_common.c has additional IPv4-only stuff
901 921
922#if defined CONFIG_FEATURE_TLS_SCHANNEL
923typedef struct tls_state {
924 int ofd;
925 int ifd;
926
927 // handles
928 CredHandle cred_handle;
929 CtxtHandle ctx_handle;
930
931 // buffers
932 char in_buffer[16384 + 256]; // input buffer (to read from server)
933 unsigned long in_buffer_size; // amount of data currently in input buffer
934
935 char *out_buffer; // output buffer (for decrypted data), this is essentially the same as input buffer as data is decrypted in place
936 unsigned long out_buffer_size; // amount of data currently in output buffer
937 unsigned long out_buffer_used; // amount of extra data currently in output buffer
938
939 // data
940 char *hostname;
941 SecPkgContext_StreamSizes stream_sizes;
942
943 // booleans
902 944
945 // context initialized
946 int initialized;
947
948 // closed by remote peer
949 int closed;
950} tls_state_t;
951#else
903struct tls_aes { 952struct tls_aes {
904 uint32_t key[60]; 953 uint32_t key[60];
905 unsigned rounds; 954 unsigned rounds;
@@ -956,12 +1005,14 @@ typedef struct tls_state {
956 struct tls_aes aes_decrypt; 1005 struct tls_aes aes_decrypt;
957 uint8_t H[16]; //used by AES_GCM 1006 uint8_t H[16]; //used by AES_GCM
958} tls_state_t; 1007} tls_state_t;
1008#endif
959 1009
960static inline tls_state_t *new_tls_state(void) 1010static inline tls_state_t *new_tls_state(void)
961{ 1011{
962 tls_state_t *tls = xzalloc(sizeof(*tls)); 1012 tls_state_t *tls = xzalloc(sizeof(*tls));
963 return tls; 1013 return tls;
964} 1014}
1015
965void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC; 1016void tls_handshake(tls_state_t *tls, const char *sni) FAST_FUNC;
966#define TLSLOOP_EXIT_ON_LOCAL_EOF (1 << 0) 1017#define TLSLOOP_EXIT_ON_LOCAL_EOF (1 << 0)
967void tls_run_copy_loop(tls_state_t *tls, unsigned flags) FAST_FUNC; 1018void tls_run_copy_loop(tls_state_t *tls, unsigned flags) FAST_FUNC;
@@ -1071,13 +1122,13 @@ unsigned bb_clk_tck(void) FAST_FUNC;
1071 1122
1072#if SEAMLESS_COMPRESSION 1123#if SEAMLESS_COMPRESSION
1073/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ 1124/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */
1074int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; 1125int setup_unzip_on_fd(int fd, int die_if_not_compressed) FAST_FUNC;
1075/* Autodetects .gz etc */ 1126/* Autodetects .gz etc */
1076extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC; 1127extern int open_zipped(const char *fname, int die_if_not_compressed) FAST_FUNC;
1077extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 1128extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
1078#else 1129#else
1079# define setup_unzip_on_fd(...) (0) 1130# define setup_unzip_on_fd(...) (0)
1080# define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY); 1131# define open_zipped(fname, die_if_not_compressed) open((fname), O_RDONLY);
1081# define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p)) 1132# define xmalloc_open_zipped_read_close(fname, maxsz_p) xmalloc_open_read_close((fname), (maxsz_p))
1082#endif 1133#endif
1083/* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */ 1134/* lzma has no signature, need a little helper. NB: exist only for ENABLE_FEATURE_SEAMLESS_LZMA=y */
@@ -1173,6 +1224,16 @@ char *bin2hex(char *dst, const char *src, int count) FAST_FUNC;
1173/* Reverse */ 1224/* Reverse */
1174char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; 1225char* hex2bin(char *dst, const char *src, int count) FAST_FUNC;
1175 1226
1227void FAST_FUNC xorbuf_3(void *dst, const void *src1, const void *src2, unsigned count);
1228void FAST_FUNC xorbuf(void* buf, const void* mask, unsigned count);
1229void FAST_FUNC xorbuf16_aligned_long(void* buf, const void* mask);
1230void FAST_FUNC xorbuf64_3_aligned64(void *dst, const void *src1, const void *src2);
1231#if BB_UNALIGNED_MEMACCESS_OK
1232# define xorbuf16(buf,mask) xorbuf16_aligned_long(buf,mask)
1233#else
1234void FAST_FUNC xorbuf16(void* buf, const void* mask);
1235#endif
1236
1176/* Generate a UUID */ 1237/* Generate a UUID */
1177void generate_uuid(uint8_t *buf) FAST_FUNC; 1238void generate_uuid(uint8_t *buf) FAST_FUNC;
1178 1239
@@ -1887,18 +1948,25 @@ extern char *pw_encrypt(const char *clear, const char *salt, int cleanup) FAST_F
1887extern int obscure(const char *old, const char *newval, const struct passwd *pwdp) FAST_FUNC; 1948extern int obscure(const char *old, const char *newval, const struct passwd *pwdp) FAST_FUNC;
1888/* 1949/*
1889 * rnd is additional random input. New one is returned. 1950 * rnd is additional random input. New one is returned.
1890 * Useful if you call crypt_make_salt many times in a row: 1951 * Useful if you call crypt_make_rand64encoded many times in a row:
1891 * rnd = crypt_make_salt(buf1, 4, 0); 1952 * rnd = crypt_make_rand64encoded(buf1, 4, 0);
1892 * rnd = crypt_make_salt(buf2, 4, rnd); 1953 * rnd = crypt_make_rand64encoded(buf2, 4, rnd);
1893 * rnd = crypt_make_salt(buf3, 4, rnd); 1954 * rnd = crypt_make_rand64encoded(buf3, 4, rnd);
1894 * (otherwise we risk having same salt generated) 1955 * (otherwise we risk having same salt generated)
1895 */ 1956 */
1896extern int crypt_make_salt(char *p, int cnt /*, int rnd*/) FAST_FUNC; 1957extern int crypt_make_rand64encoded(char *p, int cnt /*, int rnd*/) FAST_FUNC;
1897/* "$N$" + sha_salt_16_bytes + NUL */ 1958/* Size of char salt[] to hold randomly-generated salt string
1898#define MAX_PW_SALT_LEN (3 + 16 + 1) 1959 * sha256/512:
1960 * "$5$" ["rounds=999999999$"] "<sha_salt_16_chars><NUL>"
1961 * "$6$" ["rounds=999999999$"] "<sha_salt_16_chars><NUL>"
1962 * #define MAX_PW_SALT_LEN (3 + sizeof("rounds=999999999$")-1 + 16 + 1)
1963 * yescrypt:
1964 * "$y$" <up to 8 params of up to 6 chars each> "$" <up to 86 chars salt><NUL>
1965 * (86 chars are ascii64-encoded 64 binary bytes)
1966 */
1967#define MAX_PW_SALT_LEN (3 + 8*6 + 1 + 86 + 1)
1899extern char* crypt_make_pw_salt(char p[MAX_PW_SALT_LEN], const char *algo) FAST_FUNC; 1968extern char* crypt_make_pw_salt(char p[MAX_PW_SALT_LEN], const char *algo) FAST_FUNC;
1900 1969
1901
1902/* Returns number of lines changed, or -1 on error */ 1970/* Returns number of lines changed, or -1 on error */
1903#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) 1971#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP)
1904#define update_passwd(filename, username, data, member) \ 1972#define update_passwd(filename, username, data, member) \
@@ -2041,6 +2109,10 @@ int64_t windows_read_key(int fd, char *buffer, int timeout) FAST_FUNC;
2041int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC; 2109int64_t safe_read_key(int fd, char *buffer, int timeout) FAST_FUNC;
2042void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; 2110void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC;
2043 2111
2112int check_got_signal_and_poll(struct pollfd pfd[1], int timeout) FAST_FUNC;
2113#if ENABLE_PLATFORM_MINGW32
2114# define check_got_signal_and_poll(p, t) poll(p, 1, t)
2115#endif
2044 2116
2045#if ENABLE_FEATURE_EDITING 2117#if ENABLE_FEATURE_EDITING
2046/* It's NOT just ENABLEd or disabled. It's a number: */ 2118/* It's NOT just ENABLEd or disabled. It's a number: */
@@ -2087,7 +2159,7 @@ typedef struct line_input_t {
2087# if MAX_HISTORY 2159# if MAX_HISTORY
2088 int cnt_history; 2160 int cnt_history;
2089 int cur_history; 2161 int cur_history;
2090 int max_history; /* must never be <= 0 */ 2162 int max_history; /* must never be < 0 */
2091# if ENABLE_FEATURE_EDITING_SAVEHISTORY 2163# if ENABLE_FEATURE_EDITING_SAVEHISTORY
2092 /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT: 2164 /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT:
2093 * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are 2165 * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are
@@ -2294,6 +2366,51 @@ char *decode_base64(char *dst, const char **pp_src) FAST_FUNC;
2294char *decode_base32(char *dst, const char **pp_src) FAST_FUNC; 2366char *decode_base32(char *dst, const char **pp_src) FAST_FUNC;
2295void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC; 2367void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC;
2296 2368
2369int FAST_FUNC i2a64(int i);
2370int FAST_FUNC a2i64(char c);
2371char* FAST_FUNC num2str64_lsb_first(char *s, unsigned v, int n);
2372
2373enum {
2374 /* how many bytes XYZ_end() fills */
2375 MD5_OUTSIZE = 16,
2376 SHA1_OUTSIZE = 20,
2377 SHA256_OUTSIZE = 32,
2378 SHA512_OUTSIZE = 64,
2379 SHA3_OUTSIZE = 28,
2380 /* size of input block */
2381 SHA2_INSIZE = 64,
2382};
2383
2384#if defined CONFIG_FEATURE_USE_CNG_API
2385struct bcrypt_hash_ctx_t {
2386 void *handle;
2387 void *hash_obj;
2388 unsigned int output_size;
2389};
2390typedef struct bcrypt_hash_ctx_t md5_ctx_t;
2391typedef struct bcrypt_hash_ctx_t sha1_ctx_t;
2392typedef struct bcrypt_hash_ctx_t sha256_ctx_t;
2393typedef struct bcrypt_hash_ctx_t sha512_ctx_t;
2394typedef struct sha3_ctx_t {
2395 uint64_t state[25];
2396 unsigned bytes_queued;
2397 unsigned input_block_bytes;
2398} sha3_ctx_t;
2399void md5_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC;
2400void sha1_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC;
2401void sha256_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC;
2402void sha512_begin(struct bcrypt_hash_ctx_t *ctx) FAST_FUNC;
2403void generic_hash(struct bcrypt_hash_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC;
2404unsigned generic_end(struct bcrypt_hash_ctx_t *ctx, void *resbuf) FAST_FUNC;
2405# define md5_hash generic_hash
2406# define sha1_hash generic_hash
2407# define sha256_hash generic_hash
2408# define sha512_hash generic_hash
2409# define md5_end generic_end
2410# define sha1_end generic_end
2411# define sha256_end generic_end
2412# define sha512_end generic_end
2413#else
2297typedef struct md5_ctx_t { 2414typedef struct md5_ctx_t {
2298 uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */ 2415 uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */
2299 void (*process_block)(struct md5_ctx_t*) FAST_FUNC; 2416 void (*process_block)(struct md5_ctx_t*) FAST_FUNC;
@@ -2324,20 +2441,66 @@ void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC;
2324void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; 2441void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC;
2325void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; 2442void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC;
2326unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; 2443unsigned sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC;
2444#endif
2327void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC; 2445void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC;
2328void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; 2446void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC;
2329unsigned sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC; 2447unsigned sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC;
2448void FAST_FUNC sha256_block(const void *in, size_t len, uint8_t hash[32]);
2330/* TLS benefits from knowing that sha1 and sha256 share these. Give them "agnostic" names too */ 2449/* TLS benefits from knowing that sha1 and sha256 share these. Give them "agnostic" names too */
2450#if defined CONFIG_FEATURE_USE_CNG_API
2451typedef struct bcrypt_hash_ctx_t md5sha_ctx_t;
2452#define md5sha_hash generic_hash
2453#define sha_end generic_end
2454#else
2331typedef struct md5_ctx_t md5sha_ctx_t; 2455typedef struct md5_ctx_t md5sha_ctx_t;
2332#define md5sha_hash md5_hash 2456#define md5sha_hash md5_hash
2333#define sha_end sha1_end 2457#define sha_end sha1_end
2334enum { 2458#endif
2335 MD5_OUTSIZE = 16, 2459
2336 SHA1_OUTSIZE = 20, 2460/* RFC 2104 HMAC (hash-based message authentication code) */
2337 SHA256_OUTSIZE = 32, 2461#if !ENABLE_FEATURE_USE_CNG_API
2338 SHA512_OUTSIZE = 64, 2462typedef struct hmac_ctx {
2339 SHA3_OUTSIZE = 28, 2463 md5sha_ctx_t hashed_key_xor_ipad;
2340}; 2464 md5sha_ctx_t hashed_key_xor_opad;
2465} hmac_ctx_t;
2466#else
2467typedef struct bcrypt_hash_ctx_t hmac_ctx_t;
2468#endif
2469#define HMAC_ONLY_SHA256 (!ENABLE_FEATURE_TLS_SHA1)
2470typedef void md5sha_begin_func(md5sha_ctx_t *ctx) FAST_FUNC;
2471#if !ENABLE_FEATURE_USE_CNG_API
2472#if HMAC_ONLY_SHA256
2473#define hmac_begin(ctx,key,key_size,begin) \
2474 hmac_begin(ctx,key,key_size)
2475#endif
2476void FAST_FUNC hmac_begin(hmac_ctx_t *ctx, const uint8_t *key, unsigned key_size, md5sha_begin_func *begin);
2477static ALWAYS_INLINE void hmac_hash(hmac_ctx_t *ctx, const void *in, size_t len)
2478{
2479 md5sha_hash(&ctx->hashed_key_xor_ipad, in, len);
2480}
2481#else
2482# if HMAC_ONLY_SHA256
2483# define hmac_begin(pre,key,key_size,begin) \
2484 _hmac_begin(pre, key, key_size, sha256_begin_hmac)
2485# else
2486# define hmac_begin _hmac_begin
2487# endif
2488void _hmac_begin(hmac_ctx_t *pre, uint8_t *key, unsigned key_size,
2489 BCRYPT_ALG_HANDLE alg_handle);
2490void hmac_uninit(hmac_ctx_t *pre);
2491#endif
2492unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out);
2493#if HMAC_ONLY_SHA256
2494#define hmac_block(key,key_size,begin,in,sz,out) \
2495 hmac_block(key,key_size,in,sz,out)
2496#endif
2497unsigned FAST_FUNC hmac_block(const uint8_t *key, unsigned key_size,
2498 md5sha_begin_func *begin,
2499 const void *in, unsigned sz,
2500 uint8_t *out);
2501/* HMAC helpers for TLS: */
2502void FAST_FUNC hmac_hash_v(hmac_ctx_t *ctx, va_list va);
2503unsigned hmac_peek_hash(hmac_ctx_t *ctx, uint8_t *out, ...);
2341 2504
2342extern uint32_t *global_crc32_table; 2505extern uint32_t *global_crc32_table;
2343uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; 2506uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC;
@@ -2473,31 +2636,10 @@ extern struct globals *BB_GLOBAL_CONST ptr_to_globals;
2473#define barrier() asm volatile ("":::"memory") 2636#define barrier() asm volatile ("":::"memory")
2474 2637
2475#if defined(__clang_major__) && __clang_major__ >= 9 2638#if defined(__clang_major__) && __clang_major__ >= 9
2476/* Clang/llvm drops assignment to "constant" storage. Silently. 2639/* {ASSIGN,XZALLOC}_CONST_PTR() are out-of-line functions
2477 * Needs serious convincing to not eliminate the store. 2640 * to prevent clang from reading pointer before it is assigned.
2478 */
2479static ALWAYS_INLINE void* not_const_pp(const void *p)
2480{
2481 void *pp;
2482 asm volatile (
2483 "# forget that p points to const"
2484 : /*outputs*/ "=r" (pp)
2485 : /*inputs*/ "0" (p)
2486 );
2487 return pp;
2488}
2489# if !ENABLE_PLATFORM_MINGW32
2490# define ASSIGN_CONST_PTR(pptr, v) do { \
2491 *(void**)not_const_pp(pptr) = (void*)(v); \
2492 barrier(); \
2493} while (0)
2494#else
2495/* On Windows it seems necessary for this to be a function too. */
2496void ASSIGN_CONST_PTR(const void *pptr, const void *ptr) FAST_FUNC;
2497#endif
2498/* XZALLOC_CONST_PTR() is an out-of-line function to prevent
2499 * clang from reading pointer before it is assigned.
2500 */ 2641 */
2642void ASSIGN_CONST_PTR(const void *pptr, void *v) FAST_FUNC;
2501void XZALLOC_CONST_PTR(const void *pptr, size_t size) FAST_FUNC; 2643void XZALLOC_CONST_PTR(const void *pptr, size_t size) FAST_FUNC;
2502#else 2644#else
2503# define ASSIGN_CONST_PTR(pptr, v) do { \ 2645# define ASSIGN_CONST_PTR(pptr, v) do { \
diff --git a/include/mingw.h b/include/mingw.h
index c41c0f91e..276e40659 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -259,6 +259,7 @@ int ffs(int i);
259 */ 259 */
260 260
261#define TIOCGWINSZ 0x5413 261#define TIOCGWINSZ 0x5413
262#define TIOCSWINSZ 0x5414
262 263
263int ioctl(int fd, int code, ...); 264int ioctl(int fd, int code, ...);
264 265
@@ -669,3 +670,5 @@ enum {
669}; 670};
670int elevation_state(void); 671int elevation_state(void);
671void set_interp(int i) FAST_FUNC; 672void set_interp(int i) FAST_FUNC;
673int mingw_shell_execute(SHELLEXECUTEINFO *info);
674void mingw_die_if_error(NTSTATUS status, const char *function_name);
diff --git a/include/usage.src.h b/include/usage.src.h
index 5d2038834..0881337f8 100644
--- a/include/usage.src.h
+++ b/include/usage.src.h
@@ -17,11 +17,11 @@
17#define scripted_trivial_usage NOUSAGE_STR 17#define scripted_trivial_usage NOUSAGE_STR
18#define scripted_full_usage "" 18#define scripted_full_usage ""
19 19
20#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA 20#if !ENABLE_USE_BB_CRYPT
21# define CRYPT_METHODS_HELP_STR "des,md5,sha256/512" \ 21# define CRYPT_METHODS_HELP_STR "des,md5,sha256/512,yescrypt" \
22 " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")" 22 " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")"
23#else 23#else
24# define CRYPT_METHODS_HELP_STR "des,md5" \ 24# define CRYPT_METHODS_HELP_STR "des,md5"IF_USE_BB_CRYPT_SHA(",sha256/512")IF_USE_BB_CRYPT_YES(",yescrypt") \
25 " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")" 25 " (default "CONFIG_FEATURE_DEFAULT_PASSWD_ALGO")"
26#endif 26#endif
27 27
diff --git a/init/bootchartd.c b/init/bootchartd.c
index 0929890a3..a5447c6ad 100644
--- a/init/bootchartd.c
+++ b/init/bootchartd.c
@@ -133,7 +133,7 @@ static void dump_file(FILE *fp, const char *filename)
133static int dump_procs(FILE *fp, int look_for_login_process) 133static int dump_procs(FILE *fp, int look_for_login_process)
134{ 134{
135 struct dirent *entry; 135 struct dirent *entry;
136 DIR *dir = opendir("/proc"); 136 DIR *dir = xopendir("/proc");
137 int found_login_process = 0; 137 int found_login_process = 0;
138 138
139 fputs(G.jiffy_line, fp); 139 fputs(G.jiffy_line, fp);
diff --git a/init/init.c b/init/init.c
index 2ee1e4cde..797e0a0eb 100644
--- a/init/init.c
+++ b/init/init.c
@@ -1198,17 +1198,29 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1198 /* Wait for any child process(es) to exit */ 1198 /* Wait for any child process(es) to exit */
1199 while (1) { 1199 while (1) {
1200 pid_t wpid; 1200 pid_t wpid;
1201 int status;
1201 struct init_action *a; 1202 struct init_action *a;
1202 1203
1203 wpid = waitpid(-1, NULL, WNOHANG); 1204 wpid = waitpid(-1, &status, WNOHANG);
1204 if (wpid <= 0) 1205 if (wpid <= 0)
1205 break; 1206 break;
1206 1207
1207 a = mark_terminated(wpid); 1208 a = mark_terminated(wpid);
1208 if (a) { 1209 if (a) {
1209 message(L_LOG, "process '%s' (pid %u) exited. " 1210 const char *s = "killed, signal";
1211 int ex = WTERMSIG(status);
1212 /* "if (!WIFSIGNALED(status))" generates more code:
1213 * on linux, WIFEXITED(status) is "WTERMSIG(status) == 0"
1214 * and WTERMSIG(status) is known, so compiler optimizes.
1215 */
1216 if (WIFEXITED(status)) {
1217 s = "exited, exitcode";
1218 ex = WEXITSTATUS(status);
1219 }
1220 message(L_LOG, "process '%s' (pid %u) %s:%d. "
1210 "Scheduling for restart.", 1221 "Scheduling for restart.",
1211 a->command, (unsigned)wpid); 1222 a->command, (unsigned)wpid,
1223 s, ex);
1212 } 1224 }
1213 } 1225 }
1214 1226
diff --git a/libbb/Config.src b/libbb/Config.src
index 61b4601d6..eff327c2a 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -37,6 +37,14 @@ config PASSWORD_MINLEN
37 help 37 help
38 Minimum allowable password length. 38 Minimum allowable password length.
39 39
40config FEATURE_USE_CNG_API
41 bool "Use the Windows CNG API for checksums (Windows 10+ only)"
42 default n
43 depends on PLATFORM_MINGW32
44 help
45 Use the in-built Windows CNG API for checksums.
46 This reduces code size, but is only supported on Windows 10+.
47
40config MD5_SMALL 48config MD5_SMALL
41 int "MD5: Trade bytes for speed (0:fast, 3:slow)" 49 int "MD5: Trade bytes for speed (0:fast, 3:slow)"
42 default 1 # all "fast or small" options default to small 50 default 1 # all "fast or small" options default to small
@@ -67,6 +75,7 @@ config SHA1_SMALL
67config SHA1_HWACCEL 75config SHA1_HWACCEL
68 bool "SHA1: Use hardware accelerated instructions if possible" 76 bool "SHA1: Use hardware accelerated instructions if possible"
69 default y 77 default y
78 depends on !FEATURE_USE_CNG_API
70 help 79 help
71 On x86, this adds ~590 bytes of code. Throughput 80 On x86, this adds ~590 bytes of code. Throughput
72 is about twice as fast as fully-unrolled generic code. 81 is about twice as fast as fully-unrolled generic code.
@@ -74,6 +83,7 @@ config SHA1_HWACCEL
74config SHA256_HWACCEL 83config SHA256_HWACCEL
75 bool "SHA256: Use hardware accelerated instructions if possible" 84 bool "SHA256: Use hardware accelerated instructions if possible"
76 default y 85 default y
86 depends on !FEATURE_USE_CNG_API
77 help 87 help
78 On x86, this adds ~1k bytes of code. 88 On x86, this adds ~1k bytes of code.
79 89
@@ -182,8 +192,8 @@ config FEATURE_EDITING_VI
182config FEATURE_EDITING_HISTORY 192config FEATURE_EDITING_HISTORY
183 int "History size" 193 int "History size"
184 # Don't allow way too big values here, code uses fixed "char *history[N]" struct member 194 # Don't allow way too big values here, code uses fixed "char *history[N]" struct member
185 range 0 9999 195 range 0 2000
186 default 255 196 default 200
187 depends on FEATURE_EDITING 197 depends on FEATURE_EDITING
188 help 198 help
189 Specify command history size (0 - disable). 199 Specify command history size (0 - disable).
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index d6e042775..b1064d10a 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -933,7 +933,7 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
933 full_write1_str(" multi-call binary.\n"); /* reuse */ 933 full_write1_str(" multi-call binary.\n"); /* reuse */
934#endif 934#endif
935 full_write1_str( 935 full_write1_str(
936 "BusyBox is copyrighted by many authors between 1998-2024.\n" 936 "BusyBox is copyrighted by many authors between 1998-2025.\n"
937 "Licensed under GPLv2. See source distribution for detailed\n" 937 "Licensed under GPLv2. See source distribution for detailed\n"
938 "copyright notices.\n" 938 "copyright notices.\n"
939 "\n" 939 "\n"
diff --git a/libbb/bitops.c b/libbb/bitops.c
new file mode 100644
index 000000000..467e1a2d9
--- /dev/null
+++ b/libbb/bitops.c
@@ -0,0 +1,128 @@
1/*
2 * Utility routines.
3 *
4 * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8//kbuild:lib-y += bitops.o
9
10#include "libbb.h"
11
12void FAST_FUNC xorbuf_3(void *dst, const void *src1, const void *src2, unsigned count)
13{
14 uint8_t *d = dst;
15 const uint8_t *s1 = src1;
16 const uint8_t *s2 = src2;
17#if BB_UNALIGNED_MEMACCESS_OK
18 while (count >= sizeof(long)) {
19 *(long*)d = *(long*)s1 ^ *(long*)s2;
20 count -= sizeof(long);
21 d += sizeof(long);
22 s1 += sizeof(long);
23 s2 += sizeof(long);
24 }
25#endif
26 while (count--)
27 *d++ = *s1++ ^ *s2++;
28}
29
30void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count)
31{
32 xorbuf_3(dst, dst, src, count);
33}
34
35void FAST_FUNC xorbuf16_aligned_long(void *dst, const void *src)
36{
37#if defined(__SSE__) /* any x86_64 has it */
38 asm volatile(
39"\n movups (%0),%%xmm0"
40"\n movups (%1),%%xmm1" // can't just xorps(%1),%%xmm0:
41"\n xorps %%xmm1,%%xmm0" // SSE requires 16-byte alignment
42"\n movups %%xmm0,(%0)"
43"\n"
44 : "=r" (dst), "=r" (src)
45 : "0" (dst), "1" (src)
46 : "xmm0", "xmm1", "memory"
47 );
48#else
49 unsigned long *d = dst;
50 const unsigned long *s = src;
51 d[0] ^= s[0];
52# if LONG_MAX <= 0x7fffffffffffffff
53 d[1] ^= s[1];
54# if LONG_MAX == 0x7fffffff
55 d[2] ^= s[2];
56 d[3] ^= s[3];
57# endif
58# endif
59#endif
60}
61// The above can be inlined in libbb.h, in a way where compiler
62// is even free to use better addressing modes than (%reg), and
63// to keep the result in a register
64// (to not store it to memory after each XOR):
65//#if defined(__SSE__)
66//#include <xmmintrin.h>
67//^^^ or just: typedef float __m128_u attribute((__vector_size__(16),__may_alias__,__aligned__(1)));
68//static ALWAYS_INLINE void xorbuf16_aligned_long(void *dst, const void *src)
69//{
70// __m128_u xmm0, xmm1;
71// asm volatile(
72//"\n xorps %1,%0"
73// : "=x" (xmm0), "=x" (xmm1)
74// : "0" (*(__m128_u*)dst), "1" (*(__m128_u*)src)
75// );
76// *(__m128_u*)dst = xmm0; // this store may be optimized out!
77//}
78//#endif
79// but I don't trust gcc optimizer enough to not generate some monstrosity.
80// See GMULT() function in TLS code as an example.
81
82void FAST_FUNC xorbuf64_3_aligned64(void *dst, const void *src1, const void *src2)
83{
84#if defined(__SSE__) /* any x86_64 has it */
85 asm volatile(
86"\n movups 0*16(%1),%%xmm0"
87"\n movups 0*16(%2),%%xmm1" // can't just xorps(%2),%%xmm0:
88"\n xorps %%xmm1,%%xmm0" // SSE requires 16-byte alignment, we have only 8-byte
89"\n movups %%xmm0,0*16(%0)"
90"\n movups 1*16(%1),%%xmm0"
91"\n movups 1*16(%2),%%xmm1"
92"\n xorps %%xmm1,%%xmm0"
93"\n movups %%xmm0,1*16(%0)"
94"\n movups 2*16(%1),%%xmm0"
95"\n movups 2*16(%2),%%xmm1"
96"\n xorps %%xmm1,%%xmm0"
97"\n movups %%xmm0,2*16(%0)"
98"\n movups 3*16(%1),%%xmm0"
99"\n movups 3*16(%2),%%xmm1"
100"\n xorps %%xmm1,%%xmm0"
101"\n movups %%xmm0,3*16(%0)"
102"\n"
103 : "=r" (dst), "=r" (src1), "=r" (src2)
104 : "0" (dst), "1" (src1), "2" (src2)
105 : "xmm0", "xmm1", "memory"
106 );
107#else
108 long *d = dst;
109 const long *s1 = src1;
110 const long *s2 = src2;
111 unsigned count = 64 / sizeof(long);
112 do {
113 *d++ = *s1++ ^ *s2++;
114 } while (--count != 0);
115#endif
116}
117
118#if !BB_UNALIGNED_MEMACCESS_OK
119void FAST_FUNC xorbuf16(void *dst, const void *src)
120{
121#define p_aligned(a) (((uintptr_t)(a) & (sizeof(long)-1)) == 0)
122 if (p_aligned(src) && p_aligned(dst)) {
123 xorbuf16_aligned_long(dst, src);
124 return;
125 }
126 xorbuf_3(dst, dst, src, 16);
127}
128#endif
diff --git a/libbb/const_hack.c b/libbb/const_hack.c
index 75163fede..1d175481b 100644
--- a/libbb/const_hack.c
+++ b/libbb/const_hack.c
@@ -9,18 +9,27 @@
9#include "libbb.h" 9#include "libbb.h"
10 10
11#if defined(__clang_major__) && __clang_major__ >= 9 11#if defined(__clang_major__) && __clang_major__ >= 9
12void FAST_FUNC XZALLOC_CONST_PTR(const void *pptr, size_t size) 12/* Clang/llvm drops assignment to "constant" storage. Silently.
13 * Needs serious convincing to not eliminate the store.
14 */
15static ALWAYS_INLINE void* not_const_pp(const void *p)
13{ 16{
14 ASSIGN_CONST_PTR(pptr, xzalloc(size)); 17 void *pp;
18 asm volatile (
19 "# forget that p points to const"
20 : /*outputs*/ "=r" (pp)
21 : /*inputs*/ "0" (p)
22 );
23 return pp;
15} 24}
16 25void FAST_FUNC ASSIGN_CONST_PTR(const void *pptr, void *v)
17# if ENABLE_PLATFORM_MINGW32 26{
18void FAST_FUNC ASSIGN_CONST_PTR(const void *pptr, const void *v) 27 *(void**)not_const_pp(pptr) = v;
28 barrier();
29}
30void FAST_FUNC XZALLOC_CONST_PTR(const void *pptr, size_t size)
19{ 31{
20 do { 32 *(void**)not_const_pp(pptr) = xzalloc(size);
21 *(void**)not_const_pp(pptr) = (void*)(v); 33 barrier();
22 barrier();
23 } while (0);
24} 34}
25# endif
26#endif 35#endif
diff --git a/libbb/dump.c b/libbb/dump.c
index ffc46f6a7..b2abe85af 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -204,9 +204,11 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
204 if (!e) 204 if (!e)
205 goto DO_BAD_CONV_CHAR; 205 goto DO_BAD_CONV_CHAR;
206 pr->flags = F_INT; 206 pr->flags = F_INT;
207 if (e > int_convs + 1) /* not d or i? */
208 pr->flags = F_UINT;
209 byte_count_str = "\010\004\002\001"; 207 byte_count_str = "\010\004\002\001";
208 if (e > int_convs + 1) { /* not d or i? */
209 pr->flags = F_UINT;
210 byte_count_str++;
211 }
210 goto DO_BYTE_COUNT; 212 goto DO_BYTE_COUNT;
211 } else 213 } else
212 if (strchr(int_convs, *p1)) { /* %d etc */ 214 if (strchr(int_convs, *p1)) { /* %d etc */
@@ -701,15 +703,21 @@ static NOINLINE void display(priv_dumper_t* dumper)
701 conv_u(pr, bp); 703 conv_u(pr, bp);
702 break; 704 break;
703 case F_UINT: { 705 case F_UINT: {
706 union {
707 uint16_t uval16;
708 uint32_t uval32;
709 } u;
704 unsigned value = (unsigned char)*bp; 710 unsigned value = (unsigned char)*bp;
705 switch (pr->bcnt) { 711 switch (pr->bcnt) {
706 case 1: 712 case 1:
707 break; 713 break;
708 case 2: 714 case 2:
709 move_from_unaligned16(value, bp); 715 move_from_unaligned16(u.uval16, bp);
716 value = u.uval16;
710 break; 717 break;
711 case 4: 718 case 4:
712 move_from_unaligned32(value, bp); 719 move_from_unaligned32(u.uval32, bp);
720 value = u.uval32;
713 break; 721 break;
714 /* case 8: no users yet */ 722 /* case 8: no users yet */
715 } 723 }
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index 56040e150..76d29d5eb 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -93,7 +93,7 @@ getopt32(char **argv, const char *applet_opts, ...)
93 93
94 "!" If the first character in the applet_opts string is a '!', 94 "!" If the first character in the applet_opts string is a '!',
95 report bad options, missing required options, 95 report bad options, missing required options,
96 inconsistent options with all-ones return value (instead of abort. 96 inconsistent options with all-ones return value instead of aborting.
97 97
98 "+" If the first character in the applet_opts string is a plus, 98 "+" If the first character in the applet_opts string is a plus,
99 then option processing will stop as soon as a non-option is 99 then option processing will stop as soon as a non-option is
@@ -265,7 +265,7 @@ Special characters:
265 for "long options only" cases, such as tar --exclude=PATTERN, 265 for "long options only" cases, such as tar --exclude=PATTERN,
266 wget --header=HDR cases. 266 wget --header=HDR cases.
267 267
268 "a?b" A "?" between an option and a group of options means that 268 "a?bc" A "?" between an option and a group of options means that
269 at least one of them is required to occur if the first option 269 at least one of them is required to occur if the first option
270 occurs in preceding command line arguments. 270 occurs in preceding command line arguments.
271 271
@@ -348,9 +348,6 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options,
348 unsigned trigger; 348 unsigned trigger;
349 int min_arg = 0; 349 int min_arg = 0;
350 int max_arg = -1; 350 int max_arg = -1;
351 int spec_flgs = 0;
352
353#define SHOW_USAGE_IF_ERROR 1
354 351
355 on_off = complementary; 352 on_off = complementary;
356 memset(on_off, 0, sizeof(complementary)); 353 memset(on_off, 0, sizeof(complementary));
@@ -449,9 +446,7 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options,
449 continue; 446 continue;
450 c = s[1]; 447 c = s[1];
451 if (*s == '?') { 448 if (*s == '?') {
452 if (c < '0' || c > '9') { 449 if (c >= '0' && c <= '9') {
453 spec_flgs |= SHOW_USAGE_IF_ERROR;
454 } else {
455 max_arg = c - '0'; 450 max_arg = c - '0';
456 s++; 451 s++;
457 } 452 }
@@ -465,8 +460,10 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options,
465 continue; 460 continue;
466 } 461 }
467 if (*s == '=') { 462 if (*s == '=') {
468 min_arg = max_arg = c - '0'; 463 if (c >= '0' && c <= '9') {
469 s++; 464 min_arg = max_arg = c - '0';
465 s++;
466 }
470 continue; 467 continue;
471 } 468 }
472 for (on_off = complementary; on_off->opt_char; on_off++) 469 for (on_off = complementary; on_off->opt_char; on_off++)
diff --git a/libbb/hash_hmac.c b/libbb/hash_hmac.c
new file mode 100644
index 000000000..b3138029f
--- /dev/null
+++ b/libbb/hash_hmac.c
@@ -0,0 +1,154 @@
1/*
2 * Copyright (C) 2025 Denys Vlasenko
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6//kbuild:lib-$(CONFIG_TLS) += hash_hmac.o
7//kbuild:lib-$(CONFIG_USE_BB_CRYPT_YES) += hash_hmac.o
8
9#include "libbb.h"
10
11// RFC 2104:
12// HMAC(key, text) based on a hash H (say, sha256) is:
13// ipad = [0x36 x INSIZE]
14// opad = [0x5c x INSIZE]
15// HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text))
16//
17// H(key XOR opad) and H(key XOR ipad) can be precomputed
18// if we often need HMAC hmac with the same key.
19//
20// text is often given in disjoint pieces.
21#if !ENABLE_FEATURE_USE_CNG_API
22void FAST_FUNC hmac_begin(hmac_ctx_t *ctx, const uint8_t *key, unsigned key_size, md5sha_begin_func *begin)
23{
24#if HMAC_ONLY_SHA256
25#define begin sha256_begin
26#endif
27 uint8_t key_xor_ipad[SHA2_INSIZE];
28 uint8_t key_xor_opad[SHA2_INSIZE];
29 unsigned i;
30
31 // "The authentication key can be of any length up to INSIZE, the
32 // block length of the hash function. Applications that use keys longer
33 // than INSIZE bytes will first hash the key using H and then use the
34 // resultant OUTSIZE byte string as the actual key to HMAC."
35 if (key_size > SHA2_INSIZE) {
36 uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE];
37 /* use ctx->hashed_key_xor_ipad as scratch ctx */
38 begin(&ctx->hashed_key_xor_ipad);
39 md5sha_hash(&ctx->hashed_key_xor_ipad, key, key_size);
40 key_size = sha_end(&ctx->hashed_key_xor_ipad, tempkey);
41 key = tempkey;
42 }
43
44 for (i = 0; i < key_size; i++) {
45 key_xor_ipad[i] = key[i] ^ 0x36;
46 key_xor_opad[i] = key[i] ^ 0x5c;
47 }
48 for (; i < SHA2_INSIZE; i++) {
49 key_xor_ipad[i] = 0x36;
50 key_xor_opad[i] = 0x5c;
51 }
52
53 begin(&ctx->hashed_key_xor_ipad);
54 begin(&ctx->hashed_key_xor_opad);
55 md5sha_hash(&ctx->hashed_key_xor_ipad, key_xor_ipad, SHA2_INSIZE);
56 md5sha_hash(&ctx->hashed_key_xor_opad, key_xor_opad, SHA2_INSIZE);
57}
58#undef begin
59
60unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out)
61{
62 unsigned len = sha_end(&ctx->hashed_key_xor_ipad, out);
63 /* out = H((key XOR opad) + out) */
64 md5sha_hash(&ctx->hashed_key_xor_opad, out, len);
65 return sha_end(&ctx->hashed_key_xor_opad, out);
66}
67
68unsigned FAST_FUNC hmac_block(const uint8_t *key, unsigned key_size, md5sha_begin_func *begin, const void *in, unsigned sz, uint8_t *out)
69{
70 hmac_ctx_t ctx;
71 hmac_begin(&ctx, key, key_size, begin);
72 hmac_hash(&ctx, in, sz);
73 return hmac_end(&ctx, out);
74}
75
76/* TLS helpers */
77
78void FAST_FUNC hmac_hash_v(
79 hmac_ctx_t *ctx,
80 va_list va)
81{
82 uint8_t *in;
83
84 /* ctx->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */
85 /* ctx->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */
86
87 /* calculate out = H((key XOR ipad) + text) */
88 while ((in = va_arg(va, uint8_t*)) != NULL) {
89 unsigned size = va_arg(va, unsigned);
90 md5sha_hash(&ctx->hashed_key_xor_ipad, in, size);
91 }
92}
93#else
94void _hmac_begin(hmac_ctx_t *ctx, uint8_t *key, unsigned key_size,
95 BCRYPT_ALG_HANDLE alg_handle) {
96 DWORD hash_object_length = 0;
97 ULONG _unused;
98 NTSTATUS status;
99
100 status = BCryptGetProperty(alg_handle, BCRYPT_OBJECT_LENGTH,
101 (PUCHAR)&hash_object_length, sizeof(DWORD), &_unused, 0);
102 mingw_die_if_error(status, "BCryptGetProperty");
103 status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH,
104 (PUCHAR)&ctx->output_size, sizeof(DWORD), &_unused, 0);
105 mingw_die_if_error(status, "BCryptGetProperty");
106
107 ctx->hash_obj = xmalloc(hash_object_length);
108
109 status = BCryptCreateHash(alg_handle, &ctx->handle, ctx->hash_obj,
110 hash_object_length, key, key_size, BCRYPT_HASH_REUSABLE_FLAG);
111 mingw_die_if_error(status, "BCryptCreateHash");
112}
113
114unsigned FAST_FUNC hmac_end(hmac_ctx_t *ctx, uint8_t *out)
115{
116 NTSTATUS status;
117
118 status = BCryptFinishHash(ctx->handle, out, ctx->output_size, 0);
119 mingw_die_if_error(status, "BCryptFinishHash");
120
121 return ctx->output_size;
122}
123
124void FAST_FUNC hmac_hash_v(hmac_ctx_t *ctx, va_list va)
125{
126 uint8_t *in;
127
128 while ((in = va_arg(va, uint8_t*)) != NULL) {
129 unsigned size = va_arg(va, unsigned);
130 BCryptHashData(ctx->handle, in, size, 0);
131 }
132}
133
134void hmac_uninit(hmac_ctx_t *ctx) {
135 BCryptDestroyHash(ctx->handle);
136 free(ctx->hash_obj);
137}
138#endif
139
140/* Using HMAC state, make a copy of it (IOW: without affecting this state!)
141 * hash in the list of (ptr,size) blocks, and finish the HMAC to out[] buffer.
142 * This function is useful for TLS PRF.
143 */
144unsigned hmac_peek_hash(hmac_ctx_t *ctx, uint8_t *out, ...)
145{
146 hmac_ctx_t tmpctx = *ctx; /* struct copy */
147 va_list va;
148
149 va_start(va, out);
150 hmac_hash_v(&tmpctx, va);
151 va_end(va);
152
153 return hmac_end(&tmpctx, out);
154}
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index 75a61c32c..22dd890bf 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -13,6 +13,82 @@
13 13
14#define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA) 14#define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA)
15 15
16#if ENABLE_FEATURE_USE_CNG_API
17# include <windows.h>
18# include <bcrypt.h>
19
20// these work on Windows >= 10
21# define BCRYPT_MD5_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000021)
22# define BCRYPT_SHA1_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000031)
23# define BCRYPT_SHA256_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000041)
24# define BCRYPT_SHA512_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000061)
25
26/* Initialize structure containing state of computation.
27 * (RFC 1321, 3.3: Step 3)
28 */
29
30static void generic_init(struct bcrypt_hash_ctx_t *ctx, BCRYPT_ALG_HANDLE alg_handle) {
31 DWORD hash_object_length = 0;
32 ULONG _unused;
33 NTSTATUS status;
34
35 status = BCryptGetProperty(alg_handle, BCRYPT_OBJECT_LENGTH, (PUCHAR)&hash_object_length, sizeof(DWORD), &_unused, 0);
36 mingw_die_if_error(status, "BCryptGetProperty");
37 status = BCryptGetProperty(alg_handle, BCRYPT_HASH_LENGTH, (PUCHAR)&ctx->output_size, sizeof(DWORD), &_unused, 0);
38 mingw_die_if_error(status, "BCryptGetProperty");
39
40
41 ctx->hash_obj = xmalloc(hash_object_length);
42
43 status = BCryptCreateHash(alg_handle, &ctx->handle, ctx->hash_obj, hash_object_length, NULL, 0, 0);
44 mingw_die_if_error(status, "BCryptCreateHash");
45}
46
47void FAST_FUNC md5_begin(md5_ctx_t *ctx)
48{
49 generic_init(ctx, BCRYPT_MD5_ALG_HANDLE);
50}
51
52void FAST_FUNC sha1_begin(sha1_ctx_t *ctx)
53{
54 generic_init(ctx, BCRYPT_SHA1_ALG_HANDLE);
55}
56
57/* Initialize structure containing state of computation.
58 (FIPS 180-2:5.3.2) */
59void FAST_FUNC sha256_begin(sha256_ctx_t *ctx)
60{
61 generic_init(ctx, BCRYPT_SHA256_ALG_HANDLE);
62}
63
64#if NEED_SHA512
65/* Initialize structure containing state of computation.
66 (FIPS 180-2:5.3.3) */
67void FAST_FUNC sha512_begin(sha512_ctx_t *ctx)
68{
69 generic_init(ctx, BCRYPT_SHA512_ALG_HANDLE);
70}
71#endif /* NEED_SHA512 */
72
73void FAST_FUNC generic_hash(struct bcrypt_hash_ctx_t *ctx, const void *buffer, size_t len)
74{
75 /*
76 for perf, no error checking here
77 */
78 /*NTSTATUS status = */ BCryptHashData(ctx->handle, (const PUCHAR)buffer, len, 0);
79 // mingw_die_if_error(status, "BCryptHashData");
80}
81
82unsigned FAST_FUNC generic_end(struct bcrypt_hash_ctx_t *ctx, void *resbuf)
83{
84 NTSTATUS status = BCryptFinishHash(ctx->handle, resbuf, ctx->output_size, 0);
85 mingw_die_if_error(status, "BCryptFinishHash");
86 BCryptDestroyHash(ctx->handle);
87 free(ctx->hash_obj);
88 return ctx->output_size;
89}
90#endif /* !ENABLE_FEATURE_USE_CNG_API */
91
16#if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL 92#if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL
17# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) 93# if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
18static void cpuid_eax_ebx_ecx(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx) 94static void cpuid_eax_ebx_ecx(unsigned *eax, unsigned *ebx, unsigned *ecx, unsigned *edx)
@@ -80,6 +156,7 @@ static ALWAYS_INLINE uint64_t rotl64(uint64_t x, unsigned n)
80 return (x << n) | (x >> (64 - n)); 156 return (x << n) | (x >> (64 - n));
81} 157}
82 158
159#if !ENABLE_FEATURE_USE_CNG_API
83/* Process the remaining bytes in the buffer */ 160/* Process the remaining bytes in the buffer */
84static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) 161static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed)
85{ 162{
@@ -1367,6 +1444,7 @@ unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
1367 return sizeof(ctx->hash); 1444 return sizeof(ctx->hash);
1368} 1445}
1369#endif /* NEED_SHA512 */ 1446#endif /* NEED_SHA512 */
1447#endif /* !ENABLE_FEATURE_USE_CNG_API */
1370 1448
1371 1449
1372/* 1450/*
diff --git a/libbb/hash_sha256_block.c b/libbb/hash_sha256_block.c
new file mode 100644
index 000000000..3c4366321
--- /dev/null
+++ b/libbb/hash_sha256_block.c
@@ -0,0 +1,19 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2025 Denys Vlasenko
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9//kbuild:lib-y += hash_sha256_block.o
10#include "libbb.h"
11
12void FAST_FUNC
13sha256_block(const void *in, size_t len, uint8_t hash[32])
14{
15 sha256_ctx_t ctx;
16 sha256_begin(&ctx);
17 sha256_hash(&ctx, in, len);
18 sha256_end(&ctx, hash);
19}
diff --git a/libbb/hash_sha256_hwaccel_x86-32.S b/libbb/hash_sha256_hwaccel_x86-32.S
index a0e4a571a..8d84055e8 100644
--- a/libbb/hash_sha256_hwaccel_x86-32.S
+++ b/libbb/hash_sha256_hwaccel_x86-32.S
@@ -34,21 +34,21 @@
34#define MSG %xmm0 34#define MSG %xmm0
35#define STATE0 %xmm1 35#define STATE0 %xmm1
36#define STATE1 %xmm2 36#define STATE1 %xmm2
37#define MSGTMP0 %xmm3 37#define MSG0 %xmm3
38#define MSGTMP1 %xmm4 38#define MSG1 %xmm4
39#define MSGTMP2 %xmm5 39#define MSG2 %xmm5
40#define MSGTMP3 %xmm6 40#define MSG3 %xmm6
41 41
42#define XMMTMP %xmm7 42#define XMMTMP %xmm7
43 43
44#define SHUF(a,b,c,d) $(a+(b<<2)+(c<<4)+(d<<6)) 44#define SHUF(a,b,c,d) $((a)+((b)<<2)+((c)<<4)+((d)<<6))
45 45
46 .balign 8 # allow decoders to fetch at least 2 first insns 46 .balign 8 # allow decoders to fetch at least 2 first insns
47sha256_process_block64_shaNI: 47sha256_process_block64_shaNI:
48 48
49 movu128 76+0*16(%eax), XMMTMP /* ABCD (little-endian dword order) */ 49 movu128 76+0*16(%eax), XMMTMP /* ABCD (shown least-significant-dword-first) */
50 movu128 76+1*16(%eax), STATE1 /* EFGH */ 50 movu128 76+1*16(%eax), STATE1 /* EFGH */
51/* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ 51/* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */
52 mova128 STATE1, STATE0 52 mova128 STATE1, STATE0
53 /* --- -------------- ABCD -- EFGH */ 53 /* --- -------------- ABCD -- EFGH */
54 shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */ 54 shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */
@@ -58,190 +58,208 @@ sha256_process_block64_shaNI:
58 mova128 PSHUFFLE_BSWAP32_FLIP_MASK, XMMTMP 58 mova128 PSHUFFLE_BSWAP32_FLIP_MASK, XMMTMP
59 movl $K256+8*16, SHA256CONSTANTS 59 movl $K256+8*16, SHA256CONSTANTS
60 60
61// sha256rnds2 instruction uses only lower 64 bits of MSG.
62// The code below needs to move upper 64 bits to lower 64 bits
63// for the second sha256rnds2 invocation
64// (what remains in upper bits does not matter).
65// There are several ways to do it:
66// movhlps MSG, MSG // abcd -> cdcd (3 bytes of code)
67// shuf128_32 SHUF(2,3,n,n), MSG, MSG // abcd -> cdXX (4 bytes)
68// punpckhqdq MSG, MSG // abcd -> cdcd (4 bytes)
69// unpckhpd MSG, MSG // abcd -> cdcd (4 bytes)
70// psrldq $8, MSG // abcd -> cd00 (5 bytes)
71// palignr $8, MSG, MSG // abcd -> cdab (6 bytes, SSSE3 insn)
72#define MOVE_UPPER64_DOWN(reg) movhlps reg, reg
73//#define MOVE_UPPER64_DOWN(reg) shuf128_32 SHUF(2,3,0,0), reg, reg
74//#define MOVE_UPPER64_DOWN(reg) punpckhqdq reg, reg
75//#define MOVE_UPPER64_DOWN(reg) unpckhpd reg, reg
76//#define MOVE_UPPER64_DOWN(reg) psrldq $8, reg
77//#define MOVE_UPPER64_DOWN(reg) palignr $8, reg, reg
78
61 /* Rounds 0-3 */ 79 /* Rounds 0-3 */
62 movu128 0*16(DATA_PTR), MSG 80 movu128 0*16(DATA_PTR), MSG
63 pshufb XMMTMP, MSG 81 pshufb XMMTMP, MSG
64 mova128 MSG, MSGTMP0 82 mova128 MSG, MSG0
65 paddd 0*16-8*16(SHA256CONSTANTS), MSG 83 paddd 0*16-8*16(SHA256CONSTANTS), MSG
66 sha256rnds2 MSG, STATE0, STATE1 84 sha256rnds2 MSG, STATE0, STATE1
67 shuf128_32 $0x0E, MSG, MSG 85 MOVE_UPPER64_DOWN(MSG)
68 sha256rnds2 MSG, STATE1, STATE0 86 sha256rnds2 MSG, STATE1, STATE0
69 87
70 /* Rounds 4-7 */ 88 /* Rounds 4-7 */
71 movu128 1*16(DATA_PTR), MSG 89 movu128 1*16(DATA_PTR), MSG
72 pshufb XMMTMP, MSG 90 pshufb XMMTMP, MSG
73 mova128 MSG, MSGTMP1 91 mova128 MSG, MSG1
74 paddd 1*16-8*16(SHA256CONSTANTS), MSG 92 paddd 1*16-8*16(SHA256CONSTANTS), MSG
75 sha256rnds2 MSG, STATE0, STATE1 93 sha256rnds2 MSG, STATE0, STATE1
76 shuf128_32 $0x0E, MSG, MSG 94 MOVE_UPPER64_DOWN(MSG)
77 sha256rnds2 MSG, STATE1, STATE0 95 sha256rnds2 MSG, STATE1, STATE0
78 sha256msg1 MSGTMP1, MSGTMP0 96 sha256msg1 MSG1, MSG0
79 97
80 /* Rounds 8-11 */ 98 /* Rounds 8-11 */
81 movu128 2*16(DATA_PTR), MSG 99 movu128 2*16(DATA_PTR), MSG
82 pshufb XMMTMP, MSG 100 pshufb XMMTMP, MSG
83 mova128 MSG, MSGTMP2 101 mova128 MSG, MSG2
84 paddd 2*16-8*16(SHA256CONSTANTS), MSG 102 paddd 2*16-8*16(SHA256CONSTANTS), MSG
85 sha256rnds2 MSG, STATE0, STATE1 103 sha256rnds2 MSG, STATE0, STATE1
86 shuf128_32 $0x0E, MSG, MSG 104 MOVE_UPPER64_DOWN(MSG)
87 sha256rnds2 MSG, STATE1, STATE0 105 sha256rnds2 MSG, STATE1, STATE0
88 sha256msg1 MSGTMP2, MSGTMP1 106 sha256msg1 MSG2, MSG1
89 107
90 /* Rounds 12-15 */ 108 /* Rounds 12-15 */
91 movu128 3*16(DATA_PTR), MSG 109 movu128 3*16(DATA_PTR), MSG
92 pshufb XMMTMP, MSG 110 pshufb XMMTMP, MSG
93/* ...to here */ 111/* ...to here */
94 mova128 MSG, MSGTMP3 112 mova128 MSG, MSG3
95 paddd 3*16-8*16(SHA256CONSTANTS), MSG 113 paddd 3*16-8*16(SHA256CONSTANTS), MSG
96 sha256rnds2 MSG, STATE0, STATE1 114 sha256rnds2 MSG, STATE0, STATE1
97 mova128 MSGTMP3, XMMTMP 115 mova128 MSG3, XMMTMP
98 palignr $4, MSGTMP2, XMMTMP 116 palignr $4, MSG2, XMMTMP
99 paddd XMMTMP, MSGTMP0 117 paddd XMMTMP, MSG0
100 sha256msg2 MSGTMP3, MSGTMP0 118 sha256msg2 MSG3, MSG0
101 shuf128_32 $0x0E, MSG, MSG 119 MOVE_UPPER64_DOWN(MSG)
102 sha256rnds2 MSG, STATE1, STATE0 120 sha256rnds2 MSG, STATE1, STATE0
103 sha256msg1 MSGTMP3, MSGTMP2 121 sha256msg1 MSG3, MSG2
104 122
105 /* Rounds 16-19 */ 123 /* Rounds 16-19 */
106 mova128 MSGTMP0, MSG 124 mova128 MSG0, MSG
107 paddd 4*16-8*16(SHA256CONSTANTS), MSG 125 paddd 4*16-8*16(SHA256CONSTANTS), MSG
108 sha256rnds2 MSG, STATE0, STATE1 126 sha256rnds2 MSG, STATE0, STATE1
109 mova128 MSGTMP0, XMMTMP 127 mova128 MSG0, XMMTMP
110 palignr $4, MSGTMP3, XMMTMP 128 palignr $4, MSG3, XMMTMP
111 paddd XMMTMP, MSGTMP1 129 paddd XMMTMP, MSG1
112 sha256msg2 MSGTMP0, MSGTMP1 130 sha256msg2 MSG0, MSG1
113 shuf128_32 $0x0E, MSG, MSG 131 MOVE_UPPER64_DOWN(MSG)
114 sha256rnds2 MSG, STATE1, STATE0 132 sha256rnds2 MSG, STATE1, STATE0
115 sha256msg1 MSGTMP0, MSGTMP3 133 sha256msg1 MSG0, MSG3
116 134
117 /* Rounds 20-23 */ 135 /* Rounds 20-23 */
118 mova128 MSGTMP1, MSG 136 mova128 MSG1, MSG
119 paddd 5*16-8*16(SHA256CONSTANTS), MSG 137 paddd 5*16-8*16(SHA256CONSTANTS), MSG
120 sha256rnds2 MSG, STATE0, STATE1 138 sha256rnds2 MSG, STATE0, STATE1
121 mova128 MSGTMP1, XMMTMP 139 mova128 MSG1, XMMTMP
122 palignr $4, MSGTMP0, XMMTMP 140 palignr $4, MSG0, XMMTMP
123 paddd XMMTMP, MSGTMP2 141 paddd XMMTMP, MSG2
124 sha256msg2 MSGTMP1, MSGTMP2 142 sha256msg2 MSG1, MSG2
125 shuf128_32 $0x0E, MSG, MSG 143 MOVE_UPPER64_DOWN(MSG)
126 sha256rnds2 MSG, STATE1, STATE0 144 sha256rnds2 MSG, STATE1, STATE0
127 sha256msg1 MSGTMP1, MSGTMP0 145 sha256msg1 MSG1, MSG0
128 146
129 /* Rounds 24-27 */ 147 /* Rounds 24-27 */
130 mova128 MSGTMP2, MSG 148 mova128 MSG2, MSG
131 paddd 6*16-8*16(SHA256CONSTANTS), MSG 149 paddd 6*16-8*16(SHA256CONSTANTS), MSG
132 sha256rnds2 MSG, STATE0, STATE1 150 sha256rnds2 MSG, STATE0, STATE1
133 mova128 MSGTMP2, XMMTMP 151 mova128 MSG2, XMMTMP
134 palignr $4, MSGTMP1, XMMTMP 152 palignr $4, MSG1, XMMTMP
135 paddd XMMTMP, MSGTMP3 153 paddd XMMTMP, MSG3
136 sha256msg2 MSGTMP2, MSGTMP3 154 sha256msg2 MSG2, MSG3
137 shuf128_32 $0x0E, MSG, MSG 155 MOVE_UPPER64_DOWN(MSG)
138 sha256rnds2 MSG, STATE1, STATE0 156 sha256rnds2 MSG, STATE1, STATE0
139 sha256msg1 MSGTMP2, MSGTMP1 157 sha256msg1 MSG2, MSG1
140 158
141 /* Rounds 28-31 */ 159 /* Rounds 28-31 */
142 mova128 MSGTMP3, MSG 160 mova128 MSG3, MSG
143 paddd 7*16-8*16(SHA256CONSTANTS), MSG 161 paddd 7*16-8*16(SHA256CONSTANTS), MSG
144 sha256rnds2 MSG, STATE0, STATE1 162 sha256rnds2 MSG, STATE0, STATE1
145 mova128 MSGTMP3, XMMTMP 163 mova128 MSG3, XMMTMP
146 palignr $4, MSGTMP2, XMMTMP 164 palignr $4, MSG2, XMMTMP
147 paddd XMMTMP, MSGTMP0 165 paddd XMMTMP, MSG0
148 sha256msg2 MSGTMP3, MSGTMP0 166 sha256msg2 MSG3, MSG0
149 shuf128_32 $0x0E, MSG, MSG 167 MOVE_UPPER64_DOWN(MSG)
150 sha256rnds2 MSG, STATE1, STATE0 168 sha256rnds2 MSG, STATE1, STATE0
151 sha256msg1 MSGTMP3, MSGTMP2 169 sha256msg1 MSG3, MSG2
152 170
153 /* Rounds 32-35 */ 171 /* Rounds 32-35 */
154 mova128 MSGTMP0, MSG 172 mova128 MSG0, MSG
155 paddd 8*16-8*16(SHA256CONSTANTS), MSG 173 paddd 8*16-8*16(SHA256CONSTANTS), MSG
156 sha256rnds2 MSG, STATE0, STATE1 174 sha256rnds2 MSG, STATE0, STATE1
157 mova128 MSGTMP0, XMMTMP 175 mova128 MSG0, XMMTMP
158 palignr $4, MSGTMP3, XMMTMP 176 palignr $4, MSG3, XMMTMP
159 paddd XMMTMP, MSGTMP1 177 paddd XMMTMP, MSG1
160 sha256msg2 MSGTMP0, MSGTMP1 178 sha256msg2 MSG0, MSG1
161 shuf128_32 $0x0E, MSG, MSG 179 MOVE_UPPER64_DOWN(MSG)
162 sha256rnds2 MSG, STATE1, STATE0 180 sha256rnds2 MSG, STATE1, STATE0
163 sha256msg1 MSGTMP0, MSGTMP3 181 sha256msg1 MSG0, MSG3
164 182
165 /* Rounds 36-39 */ 183 /* Rounds 36-39 */
166 mova128 MSGTMP1, MSG 184 mova128 MSG1, MSG
167 paddd 9*16-8*16(SHA256CONSTANTS), MSG 185 paddd 9*16-8*16(SHA256CONSTANTS), MSG
168 sha256rnds2 MSG, STATE0, STATE1 186 sha256rnds2 MSG, STATE0, STATE1
169 mova128 MSGTMP1, XMMTMP 187 mova128 MSG1, XMMTMP
170 palignr $4, MSGTMP0, XMMTMP 188 palignr $4, MSG0, XMMTMP
171 paddd XMMTMP, MSGTMP2 189 paddd XMMTMP, MSG2
172 sha256msg2 MSGTMP1, MSGTMP2 190 sha256msg2 MSG1, MSG2
173 shuf128_32 $0x0E, MSG, MSG 191 MOVE_UPPER64_DOWN(MSG)
174 sha256rnds2 MSG, STATE1, STATE0 192 sha256rnds2 MSG, STATE1, STATE0
175 sha256msg1 MSGTMP1, MSGTMP0 193 sha256msg1 MSG1, MSG0
176 194
177 /* Rounds 40-43 */ 195 /* Rounds 40-43 */
178 mova128 MSGTMP2, MSG 196 mova128 MSG2, MSG
179 paddd 10*16-8*16(SHA256CONSTANTS), MSG 197 paddd 10*16-8*16(SHA256CONSTANTS), MSG
180 sha256rnds2 MSG, STATE0, STATE1 198 sha256rnds2 MSG, STATE0, STATE1
181 mova128 MSGTMP2, XMMTMP 199 mova128 MSG2, XMMTMP
182 palignr $4, MSGTMP1, XMMTMP 200 palignr $4, MSG1, XMMTMP
183 paddd XMMTMP, MSGTMP3 201 paddd XMMTMP, MSG3
184 sha256msg2 MSGTMP2, MSGTMP3 202 sha256msg2 MSG2, MSG3
185 shuf128_32 $0x0E, MSG, MSG 203 MOVE_UPPER64_DOWN(MSG)
186 sha256rnds2 MSG, STATE1, STATE0 204 sha256rnds2 MSG, STATE1, STATE0
187 sha256msg1 MSGTMP2, MSGTMP1 205 sha256msg1 MSG2, MSG1
188 206
189 /* Rounds 44-47 */ 207 /* Rounds 44-47 */
190 mova128 MSGTMP3, MSG 208 mova128 MSG3, MSG
191 paddd 11*16-8*16(SHA256CONSTANTS), MSG 209 paddd 11*16-8*16(SHA256CONSTANTS), MSG
192 sha256rnds2 MSG, STATE0, STATE1 210 sha256rnds2 MSG, STATE0, STATE1
193 mova128 MSGTMP3, XMMTMP 211 mova128 MSG3, XMMTMP
194 palignr $4, MSGTMP2, XMMTMP 212 palignr $4, MSG2, XMMTMP
195 paddd XMMTMP, MSGTMP0 213 paddd XMMTMP, MSG0
196 sha256msg2 MSGTMP3, MSGTMP0 214 sha256msg2 MSG3, MSG0
197 shuf128_32 $0x0E, MSG, MSG 215 MOVE_UPPER64_DOWN(MSG)
198 sha256rnds2 MSG, STATE1, STATE0 216 sha256rnds2 MSG, STATE1, STATE0
199 sha256msg1 MSGTMP3, MSGTMP2 217 sha256msg1 MSG3, MSG2
200 218
201 /* Rounds 48-51 */ 219 /* Rounds 48-51 */
202 mova128 MSGTMP0, MSG 220 mova128 MSG0, MSG
203 paddd 12*16-8*16(SHA256CONSTANTS), MSG 221 paddd 12*16-8*16(SHA256CONSTANTS), MSG
204 sha256rnds2 MSG, STATE0, STATE1 222 sha256rnds2 MSG, STATE0, STATE1
205 mova128 MSGTMP0, XMMTMP 223 mova128 MSG0, XMMTMP
206 palignr $4, MSGTMP3, XMMTMP 224 palignr $4, MSG3, XMMTMP
207 paddd XMMTMP, MSGTMP1 225 paddd XMMTMP, MSG1
208 sha256msg2 MSGTMP0, MSGTMP1 226 sha256msg2 MSG0, MSG1
209 shuf128_32 $0x0E, MSG, MSG 227 MOVE_UPPER64_DOWN(MSG)
210 sha256rnds2 MSG, STATE1, STATE0 228 sha256rnds2 MSG, STATE1, STATE0
211 sha256msg1 MSGTMP0, MSGTMP3 229 sha256msg1 MSG0, MSG3
212 230
213 /* Rounds 52-55 */ 231 /* Rounds 52-55 */
214 mova128 MSGTMP1, MSG 232 mova128 MSG1, MSG
215 paddd 13*16-8*16(SHA256CONSTANTS), MSG 233 paddd 13*16-8*16(SHA256CONSTANTS), MSG
216 sha256rnds2 MSG, STATE0, STATE1 234 sha256rnds2 MSG, STATE0, STATE1
217 mova128 MSGTMP1, XMMTMP 235 mova128 MSG1, XMMTMP
218 palignr $4, MSGTMP0, XMMTMP 236 palignr $4, MSG0, XMMTMP
219 paddd XMMTMP, MSGTMP2 237 paddd XMMTMP, MSG2
220 sha256msg2 MSGTMP1, MSGTMP2 238 sha256msg2 MSG1, MSG2
221 shuf128_32 $0x0E, MSG, MSG 239 MOVE_UPPER64_DOWN(MSG)
222 sha256rnds2 MSG, STATE1, STATE0 240 sha256rnds2 MSG, STATE1, STATE0
223 241
224 /* Rounds 56-59 */ 242 /* Rounds 56-59 */
225 mova128 MSGTMP2, MSG 243 mova128 MSG2, MSG
226 paddd 14*16-8*16(SHA256CONSTANTS), MSG 244 paddd 14*16-8*16(SHA256CONSTANTS), MSG
227 sha256rnds2 MSG, STATE0, STATE1 245 sha256rnds2 MSG, STATE0, STATE1
228 mova128 MSGTMP2, XMMTMP 246 mova128 MSG2, XMMTMP
229 palignr $4, MSGTMP1, XMMTMP 247 palignr $4, MSG1, XMMTMP
230 paddd XMMTMP, MSGTMP3 248 paddd XMMTMP, MSG3
231 sha256msg2 MSGTMP2, MSGTMP3 249 sha256msg2 MSG2, MSG3
232 shuf128_32 $0x0E, MSG, MSG 250 MOVE_UPPER64_DOWN(MSG)
233 sha256rnds2 MSG, STATE1, STATE0 251 sha256rnds2 MSG, STATE1, STATE0
234 252
235 /* Rounds 60-63 */ 253 /* Rounds 60-63 */
236 mova128 MSGTMP3, MSG 254 mova128 MSG3, MSG
237 paddd 15*16-8*16(SHA256CONSTANTS), MSG 255 paddd 15*16-8*16(SHA256CONSTANTS), MSG
238 sha256rnds2 MSG, STATE0, STATE1 256 sha256rnds2 MSG, STATE0, STATE1
239 shuf128_32 $0x0E, MSG, MSG 257 MOVE_UPPER64_DOWN(MSG)
240 sha256rnds2 MSG, STATE1, STATE0 258 sha256rnds2 MSG, STATE1, STATE0
241 259
242 /* Write hash values back in the correct order */ 260 /* Write hash values back in the correct order */
243 mova128 STATE0, XMMTMP 261 mova128 STATE0, XMMTMP
244/* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ 262/* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */
245 /* --- -------------- HGDC -- FEBA */ 263 /* --- -------------- HGDC -- FEBA */
246 shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */ 264 shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */
247 shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */ 265 shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */
diff --git a/libbb/hash_sha256_hwaccel_x86-64.S b/libbb/hash_sha256_hwaccel_x86-64.S
index 172c2eae2..ee3abbd1f 100644
--- a/libbb/hash_sha256_hwaccel_x86-64.S
+++ b/libbb/hash_sha256_hwaccel_x86-64.S
@@ -34,24 +34,24 @@
34#define MSG %xmm0 34#define MSG %xmm0
35#define STATE0 %xmm1 35#define STATE0 %xmm1
36#define STATE1 %xmm2 36#define STATE1 %xmm2
37#define MSGTMP0 %xmm3 37#define MSG0 %xmm3
38#define MSGTMP1 %xmm4 38#define MSG1 %xmm4
39#define MSGTMP2 %xmm5 39#define MSG2 %xmm5
40#define MSGTMP3 %xmm6 40#define MSG3 %xmm6
41 41
42#define XMMTMP %xmm7 42#define XMMTMP %xmm7
43 43
44#define SAVE0 %xmm8 44#define SAVE0 %xmm8
45#define SAVE1 %xmm9 45#define SAVE1 %xmm9
46 46
47#define SHUF(a,b,c,d) $(a+(b<<2)+(c<<4)+(d<<6)) 47#define SHUF(a,b,c,d) $((a)+((b)<<2)+((c)<<4)+((d)<<6))
48 48
49 .balign 8 # allow decoders to fetch at least 2 first insns 49 .balign 8 # allow decoders to fetch at least 2 first insns
50sha256_process_block64_shaNI: 50sha256_process_block64_shaNI:
51 51
52 movu128 80+0*16(%rdi), XMMTMP /* ABCD (little-endian dword order) */ 52 movu128 80+0*16(%rdi), XMMTMP /* ABCD (shown least-significant-dword-first) */
53 movu128 80+1*16(%rdi), STATE1 /* EFGH */ 53 movu128 80+1*16(%rdi), STATE1 /* EFGH */
54/* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ 54/* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */
55 mova128 STATE1, STATE0 55 mova128 STATE1, STATE0
56 /* --- -------------- ABCD -- EFGH */ 56 /* --- -------------- ABCD -- EFGH */
57 shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */ 57 shufps SHUF(1,0,1,0), XMMTMP, STATE0 /* FEBA */
@@ -65,185 +65,203 @@ sha256_process_block64_shaNI:
65 mova128 STATE0, SAVE0 65 mova128 STATE0, SAVE0
66 mova128 STATE1, SAVE1 66 mova128 STATE1, SAVE1
67 67
68// sha256rnds2 instruction uses only lower 64 bits of MSG.
69// The code below needs to move upper 64 bits to lower 64 bits
70// for the second sha256rnds2 invocation
71// (what remains in upper bits does not matter).
72// There are several ways to do it:
73// movhlps MSG, MSG // abcd -> cdcd (3 bytes of code)
74// shuf128_32 SHUF(2,3,n,n), MSG, MSG // abcd -> cdXX (4 bytes)
75// punpckhqdq MSG, MSG // abcd -> cdcd (4 bytes)
76// unpckhpd MSG, MSG // abcd -> cdcd (4 bytes)
77// psrldq $8, MSG // abcd -> cd00 (5 bytes)
78// palignr $8, MSG, MSG // abcd -> cdab (6 bytes, SSSE3 insn)
79#define MOVE_UPPER64_DOWN(reg) movhlps reg, reg
80//#define MOVE_UPPER64_DOWN(reg) shuf128_32 SHUF(2,3,0,0), reg, reg
81//#define MOVE_UPPER64_DOWN(reg) punpckhqdq reg, reg
82//#define MOVE_UPPER64_DOWN(reg) unpckhpd reg, reg
83//#define MOVE_UPPER64_DOWN(reg) psrldq $8, reg
84//#define MOVE_UPPER64_DOWN(reg) palignr $8, reg, reg
85
68 /* Rounds 0-3 */ 86 /* Rounds 0-3 */
69 movu128 0*16(DATA_PTR), MSG 87 movu128 0*16(DATA_PTR), MSG
70 pshufb XMMTMP, MSG 88 pshufb XMMTMP, MSG
71 mova128 MSG, MSGTMP0 89 mova128 MSG, MSG0
72 paddd 0*16-8*16(SHA256CONSTANTS), MSG 90 paddd 0*16-8*16(SHA256CONSTANTS), MSG
73 sha256rnds2 MSG, STATE0, STATE1 91 sha256rnds2 MSG, STATE0, STATE1
74 shuf128_32 $0x0E, MSG, MSG 92 MOVE_UPPER64_DOWN(MSG)
75 sha256rnds2 MSG, STATE1, STATE0 93 sha256rnds2 MSG, STATE1, STATE0
76 94
77 /* Rounds 4-7 */ 95 /* Rounds 4-7 */
78 movu128 1*16(DATA_PTR), MSG 96 movu128 1*16(DATA_PTR), MSG
79 pshufb XMMTMP, MSG 97 pshufb XMMTMP, MSG
80 mova128 MSG, MSGTMP1 98 mova128 MSG, MSG1
81 paddd 1*16-8*16(SHA256CONSTANTS), MSG 99 paddd 1*16-8*16(SHA256CONSTANTS), MSG
82 sha256rnds2 MSG, STATE0, STATE1 100 sha256rnds2 MSG, STATE0, STATE1
83 shuf128_32 $0x0E, MSG, MSG 101 MOVE_UPPER64_DOWN(MSG)
84 sha256rnds2 MSG, STATE1, STATE0 102 sha256rnds2 MSG, STATE1, STATE0
85 sha256msg1 MSGTMP1, MSGTMP0 103 sha256msg1 MSG1, MSG0
86 104
87 /* Rounds 8-11 */ 105 /* Rounds 8-11 */
88 movu128 2*16(DATA_PTR), MSG 106 movu128 2*16(DATA_PTR), MSG
89 pshufb XMMTMP, MSG 107 pshufb XMMTMP, MSG
90 mova128 MSG, MSGTMP2 108 mova128 MSG, MSG2
91 paddd 2*16-8*16(SHA256CONSTANTS), MSG 109 paddd 2*16-8*16(SHA256CONSTANTS), MSG
92 sha256rnds2 MSG, STATE0, STATE1 110 sha256rnds2 MSG, STATE0, STATE1
93 shuf128_32 $0x0E, MSG, MSG 111 MOVE_UPPER64_DOWN(MSG)
94 sha256rnds2 MSG, STATE1, STATE0 112 sha256rnds2 MSG, STATE1, STATE0
95 sha256msg1 MSGTMP2, MSGTMP1 113 sha256msg1 MSG2, MSG1
96 114
97 /* Rounds 12-15 */ 115 /* Rounds 12-15 */
98 movu128 3*16(DATA_PTR), MSG 116 movu128 3*16(DATA_PTR), MSG
99 pshufb XMMTMP, MSG 117 pshufb XMMTMP, MSG
100/* ...to here */ 118/* ...to here */
101 mova128 MSG, MSGTMP3 119 mova128 MSG, MSG3
102 paddd 3*16-8*16(SHA256CONSTANTS), MSG 120 paddd 3*16-8*16(SHA256CONSTANTS), MSG
103 sha256rnds2 MSG, STATE0, STATE1 121 sha256rnds2 MSG, STATE0, STATE1
104 mova128 MSGTMP3, XMMTMP 122 mova128 MSG3, XMMTMP
105 palignr $4, MSGTMP2, XMMTMP 123 palignr $4, MSG2, XMMTMP
106 paddd XMMTMP, MSGTMP0 124 paddd XMMTMP, MSG0
107 sha256msg2 MSGTMP3, MSGTMP0 125 sha256msg2 MSG3, MSG0
108 shuf128_32 $0x0E, MSG, MSG 126 MOVE_UPPER64_DOWN(MSG)
109 sha256rnds2 MSG, STATE1, STATE0 127 sha256rnds2 MSG, STATE1, STATE0
110 sha256msg1 MSGTMP3, MSGTMP2 128 sha256msg1 MSG3, MSG2
111 129
112 /* Rounds 16-19 */ 130 /* Rounds 16-19 */
113 mova128 MSGTMP0, MSG 131 mova128 MSG0, MSG
114 paddd 4*16-8*16(SHA256CONSTANTS), MSG 132 paddd 4*16-8*16(SHA256CONSTANTS), MSG
115 sha256rnds2 MSG, STATE0, STATE1 133 sha256rnds2 MSG, STATE0, STATE1
116 mova128 MSGTMP0, XMMTMP 134 mova128 MSG0, XMMTMP
117 palignr $4, MSGTMP3, XMMTMP 135 palignr $4, MSG3, XMMTMP
118 paddd XMMTMP, MSGTMP1 136 paddd XMMTMP, MSG1
119 sha256msg2 MSGTMP0, MSGTMP1 137 sha256msg2 MSG0, MSG1
120 shuf128_32 $0x0E, MSG, MSG 138 MOVE_UPPER64_DOWN(MSG)
121 sha256rnds2 MSG, STATE1, STATE0 139 sha256rnds2 MSG, STATE1, STATE0
122 sha256msg1 MSGTMP0, MSGTMP3 140 sha256msg1 MSG0, MSG3
123 141
124 /* Rounds 20-23 */ 142 /* Rounds 20-23 */
125 mova128 MSGTMP1, MSG 143 mova128 MSG1, MSG
126 paddd 5*16-8*16(SHA256CONSTANTS), MSG 144 paddd 5*16-8*16(SHA256CONSTANTS), MSG
127 sha256rnds2 MSG, STATE0, STATE1 145 sha256rnds2 MSG, STATE0, STATE1
128 mova128 MSGTMP1, XMMTMP 146 mova128 MSG1, XMMTMP
129 palignr $4, MSGTMP0, XMMTMP 147 palignr $4, MSG0, XMMTMP
130 paddd XMMTMP, MSGTMP2 148 paddd XMMTMP, MSG2
131 sha256msg2 MSGTMP1, MSGTMP2 149 sha256msg2 MSG1, MSG2
132 shuf128_32 $0x0E, MSG, MSG 150 MOVE_UPPER64_DOWN(MSG)
133 sha256rnds2 MSG, STATE1, STATE0 151 sha256rnds2 MSG, STATE1, STATE0
134 sha256msg1 MSGTMP1, MSGTMP0 152 sha256msg1 MSG1, MSG0
135 153
136 /* Rounds 24-27 */ 154 /* Rounds 24-27 */
137 mova128 MSGTMP2, MSG 155 mova128 MSG2, MSG
138 paddd 6*16-8*16(SHA256CONSTANTS), MSG 156 paddd 6*16-8*16(SHA256CONSTANTS), MSG
139 sha256rnds2 MSG, STATE0, STATE1 157 sha256rnds2 MSG, STATE0, STATE1
140 mova128 MSGTMP2, XMMTMP 158 mova128 MSG2, XMMTMP
141 palignr $4, MSGTMP1, XMMTMP 159 palignr $4, MSG1, XMMTMP
142 paddd XMMTMP, MSGTMP3 160 paddd XMMTMP, MSG3
143 sha256msg2 MSGTMP2, MSGTMP3 161 sha256msg2 MSG2, MSG3
144 shuf128_32 $0x0E, MSG, MSG 162 MOVE_UPPER64_DOWN(MSG)
145 sha256rnds2 MSG, STATE1, STATE0 163 sha256rnds2 MSG, STATE1, STATE0
146 sha256msg1 MSGTMP2, MSGTMP1 164 sha256msg1 MSG2, MSG1
147 165
148 /* Rounds 28-31 */ 166 /* Rounds 28-31 */
149 mova128 MSGTMP3, MSG 167 mova128 MSG3, MSG
150 paddd 7*16-8*16(SHA256CONSTANTS), MSG 168 paddd 7*16-8*16(SHA256CONSTANTS), MSG
151 sha256rnds2 MSG, STATE0, STATE1 169 sha256rnds2 MSG, STATE0, STATE1
152 mova128 MSGTMP3, XMMTMP 170 mova128 MSG3, XMMTMP
153 palignr $4, MSGTMP2, XMMTMP 171 palignr $4, MSG2, XMMTMP
154 paddd XMMTMP, MSGTMP0 172 paddd XMMTMP, MSG0
155 sha256msg2 MSGTMP3, MSGTMP0 173 sha256msg2 MSG3, MSG0
156 shuf128_32 $0x0E, MSG, MSG 174 MOVE_UPPER64_DOWN(MSG)
157 sha256rnds2 MSG, STATE1, STATE0 175 sha256rnds2 MSG, STATE1, STATE0
158 sha256msg1 MSGTMP3, MSGTMP2 176 sha256msg1 MSG3, MSG2
159 177
160 /* Rounds 32-35 */ 178 /* Rounds 32-35 */
161 mova128 MSGTMP0, MSG 179 mova128 MSG0, MSG
162 paddd 8*16-8*16(SHA256CONSTANTS), MSG 180 paddd 8*16-8*16(SHA256CONSTANTS), MSG
163 sha256rnds2 MSG, STATE0, STATE1 181 sha256rnds2 MSG, STATE0, STATE1
164 mova128 MSGTMP0, XMMTMP 182 mova128 MSG0, XMMTMP
165 palignr $4, MSGTMP3, XMMTMP 183 palignr $4, MSG3, XMMTMP
166 paddd XMMTMP, MSGTMP1 184 paddd XMMTMP, MSG1
167 sha256msg2 MSGTMP0, MSGTMP1 185 sha256msg2 MSG0, MSG1
168 shuf128_32 $0x0E, MSG, MSG 186 MOVE_UPPER64_DOWN(MSG)
169 sha256rnds2 MSG, STATE1, STATE0 187 sha256rnds2 MSG, STATE1, STATE0
170 sha256msg1 MSGTMP0, MSGTMP3 188 sha256msg1 MSG0, MSG3
171 189
172 /* Rounds 36-39 */ 190 /* Rounds 36-39 */
173 mova128 MSGTMP1, MSG 191 mova128 MSG1, MSG
174 paddd 9*16-8*16(SHA256CONSTANTS), MSG 192 paddd 9*16-8*16(SHA256CONSTANTS), MSG
175 sha256rnds2 MSG, STATE0, STATE1 193 sha256rnds2 MSG, STATE0, STATE1
176 mova128 MSGTMP1, XMMTMP 194 mova128 MSG1, XMMTMP
177 palignr $4, MSGTMP0, XMMTMP 195 palignr $4, MSG0, XMMTMP
178 paddd XMMTMP, MSGTMP2 196 paddd XMMTMP, MSG2
179 sha256msg2 MSGTMP1, MSGTMP2 197 sha256msg2 MSG1, MSG2
180 shuf128_32 $0x0E, MSG, MSG 198 MOVE_UPPER64_DOWN(MSG)
181 sha256rnds2 MSG, STATE1, STATE0 199 sha256rnds2 MSG, STATE1, STATE0
182 sha256msg1 MSGTMP1, MSGTMP0 200 sha256msg1 MSG1, MSG0
183 201
184 /* Rounds 40-43 */ 202 /* Rounds 40-43 */
185 mova128 MSGTMP2, MSG 203 mova128 MSG2, MSG
186 paddd 10*16-8*16(SHA256CONSTANTS), MSG 204 paddd 10*16-8*16(SHA256CONSTANTS), MSG
187 sha256rnds2 MSG, STATE0, STATE1 205 sha256rnds2 MSG, STATE0, STATE1
188 mova128 MSGTMP2, XMMTMP 206 mova128 MSG2, XMMTMP
189 palignr $4, MSGTMP1, XMMTMP 207 palignr $4, MSG1, XMMTMP
190 paddd XMMTMP, MSGTMP3 208 paddd XMMTMP, MSG3
191 sha256msg2 MSGTMP2, MSGTMP3 209 sha256msg2 MSG2, MSG3
192 shuf128_32 $0x0E, MSG, MSG 210 MOVE_UPPER64_DOWN(MSG)
193 sha256rnds2 MSG, STATE1, STATE0 211 sha256rnds2 MSG, STATE1, STATE0
194 sha256msg1 MSGTMP2, MSGTMP1 212 sha256msg1 MSG2, MSG1
195 213
196 /* Rounds 44-47 */ 214 /* Rounds 44-47 */
197 mova128 MSGTMP3, MSG 215 mova128 MSG3, MSG
198 paddd 11*16-8*16(SHA256CONSTANTS), MSG 216 paddd 11*16-8*16(SHA256CONSTANTS), MSG
199 sha256rnds2 MSG, STATE0, STATE1 217 sha256rnds2 MSG, STATE0, STATE1
200 mova128 MSGTMP3, XMMTMP 218 mova128 MSG3, XMMTMP
201 palignr $4, MSGTMP2, XMMTMP 219 palignr $4, MSG2, XMMTMP
202 paddd XMMTMP, MSGTMP0 220 paddd XMMTMP, MSG0
203 sha256msg2 MSGTMP3, MSGTMP0 221 sha256msg2 MSG3, MSG0
204 shuf128_32 $0x0E, MSG, MSG 222 MOVE_UPPER64_DOWN(MSG)
205 sha256rnds2 MSG, STATE1, STATE0 223 sha256rnds2 MSG, STATE1, STATE0
206 sha256msg1 MSGTMP3, MSGTMP2 224 sha256msg1 MSG3, MSG2
207 225
208 /* Rounds 48-51 */ 226 /* Rounds 48-51 */
209 mova128 MSGTMP0, MSG 227 mova128 MSG0, MSG
210 paddd 12*16-8*16(SHA256CONSTANTS), MSG 228 paddd 12*16-8*16(SHA256CONSTANTS), MSG
211 sha256rnds2 MSG, STATE0, STATE1 229 sha256rnds2 MSG, STATE0, STATE1
212 mova128 MSGTMP0, XMMTMP 230 mova128 MSG0, XMMTMP
213 palignr $4, MSGTMP3, XMMTMP 231 palignr $4, MSG3, XMMTMP
214 paddd XMMTMP, MSGTMP1 232 paddd XMMTMP, MSG1
215 sha256msg2 MSGTMP0, MSGTMP1 233 sha256msg2 MSG0, MSG1
216 shuf128_32 $0x0E, MSG, MSG 234 MOVE_UPPER64_DOWN(MSG)
217 sha256rnds2 MSG, STATE1, STATE0 235 sha256rnds2 MSG, STATE1, STATE0
218 sha256msg1 MSGTMP0, MSGTMP3 236 sha256msg1 MSG0, MSG3
219 237
220 /* Rounds 52-55 */ 238 /* Rounds 52-55 */
221 mova128 MSGTMP1, MSG 239 mova128 MSG1, MSG
222 paddd 13*16-8*16(SHA256CONSTANTS), MSG 240 paddd 13*16-8*16(SHA256CONSTANTS), MSG
223 sha256rnds2 MSG, STATE0, STATE1 241 sha256rnds2 MSG, STATE0, STATE1
224 mova128 MSGTMP1, XMMTMP 242 mova128 MSG1, XMMTMP
225 palignr $4, MSGTMP0, XMMTMP 243 palignr $4, MSG0, XMMTMP
226 paddd XMMTMP, MSGTMP2 244 paddd XMMTMP, MSG2
227 sha256msg2 MSGTMP1, MSGTMP2 245 sha256msg2 MSG1, MSG2
228 shuf128_32 $0x0E, MSG, MSG 246 MOVE_UPPER64_DOWN(MSG)
229 sha256rnds2 MSG, STATE1, STATE0 247 sha256rnds2 MSG, STATE1, STATE0
230 248
231 /* Rounds 56-59 */ 249 /* Rounds 56-59 */
232 mova128 MSGTMP2, MSG 250 mova128 MSG2, MSG
233 paddd 14*16-8*16(SHA256CONSTANTS), MSG 251 paddd 14*16-8*16(SHA256CONSTANTS), MSG
234 sha256rnds2 MSG, STATE0, STATE1 252 sha256rnds2 MSG, STATE0, STATE1
235 mova128 MSGTMP2, XMMTMP 253 mova128 MSG2, XMMTMP
236 palignr $4, MSGTMP1, XMMTMP 254 palignr $4, MSG1, XMMTMP
237 paddd XMMTMP, MSGTMP3 255 paddd XMMTMP, MSG3
238 sha256msg2 MSGTMP2, MSGTMP3 256 sha256msg2 MSG2, MSG3
239 shuf128_32 $0x0E, MSG, MSG 257 MOVE_UPPER64_DOWN(MSG)
240 sha256rnds2 MSG, STATE1, STATE0 258 sha256rnds2 MSG, STATE1, STATE0
241 259
242 /* Rounds 60-63 */ 260 /* Rounds 60-63 */
243 mova128 MSGTMP3, MSG 261 mova128 MSG3, MSG
244 paddd 15*16-8*16(SHA256CONSTANTS), MSG 262 paddd 15*16-8*16(SHA256CONSTANTS), MSG
245 sha256rnds2 MSG, STATE0, STATE1 263 sha256rnds2 MSG, STATE0, STATE1
246 shuf128_32 $0x0E, MSG, MSG 264 MOVE_UPPER64_DOWN(MSG)
247 sha256rnds2 MSG, STATE1, STATE0 265 sha256rnds2 MSG, STATE1, STATE0
248 266
249 /* Add current hash values with previously saved */ 267 /* Add current hash values with previously saved */
@@ -252,7 +270,7 @@ sha256_process_block64_shaNI:
252 270
253 /* Write hash values back in the correct order */ 271 /* Write hash values back in the correct order */
254 mova128 STATE0, XMMTMP 272 mova128 STATE0, XMMTMP
255/* shufps takes dwords 0,1 from *2nd* operand, and dwords 2,3 from 1st one */ 273/* shufps: dwords 0,1 of the result are selected from *2nd* operand, and dwords 2,3 from 1st operand */
256 /* --- -------------- HGDC -- FEBA */ 274 /* --- -------------- HGDC -- FEBA */
257 shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */ 275 shufps SHUF(3,2,3,2), STATE1, STATE0 /* ABCD */
258 shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */ 276 shufps SHUF(1,0,1,0), STATE1, XMMTMP /* EFGH */
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 8e2b37853..c8a0f37fe 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -457,7 +457,7 @@ static void put_cur_glyph_and_inc_cursor(void)
457 * have automargin (IOW: it is moving cursor to next line 457 * have automargin (IOW: it is moving cursor to next line
458 * by itself (which is wrong for VT-10x terminals)), 458 * by itself (which is wrong for VT-10x terminals)),
459 * this will break things: there will be one extra empty line */ 459 * this will break things: there will be one extra empty line */
460 puts("\r"); /* + implicit '\n' */ 460 fputs("\r\n", stderr);
461#else 461#else
462 /* VT-10x terminals don't wrap cursor to next line when last char 462 /* VT-10x terminals don't wrap cursor to next line when last char
463 * on the line is printed - cursor stays "over" this char. 463 * on the line is printed - cursor stays "over" this char.
@@ -1302,9 +1302,10 @@ static void showfiles(void)
1302 ); 1302 );
1303 } 1303 }
1304 if (ENABLE_UNICODE_SUPPORT) 1304 if (ENABLE_UNICODE_SUPPORT)
1305 puts(printable_string(matches[n])); 1305 fputs(printable_string(matches[n]), stderr);
1306 else 1306 else
1307 puts(matches[n]); 1307 fputs(matches[n], stderr);
1308 bb_putchar_stderr('\n');
1308 } 1309 }
1309} 1310}
1310 1311
@@ -1595,8 +1596,8 @@ unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp)
1595# endif 1596# endif
1596 if (hp) { 1597 if (hp) {
1597 size = atoi(hp); 1598 size = atoi(hp);
1598 if (size <= 0) 1599 if (size < 0)
1599 return 1; 1600 return 0;
1600 if (size > MAX_HISTORY) 1601 if (size > MAX_HISTORY)
1601 return MAX_HISTORY; 1602 return MAX_HISTORY;
1602 } 1603 }
@@ -1690,18 +1691,21 @@ static void load_history(line_input_t *st_parm)
1690 /* NB: do not trash old history if file can't be opened */ 1691 /* NB: do not trash old history if file can't be opened */
1691 1692
1692 fp = fopen_for_read(st_parm->hist_file); 1693 fp = fopen_for_read(st_parm->hist_file);
1693 if (fp) { 1694 if (!fp)
1694 /* clean up old history */ 1695 return;
1695 for (idx = st_parm->cnt_history; idx > 0;) { 1696
1696 idx--; 1697 /* clean up old history */
1697 free(st_parm->history[idx]); 1698 for (idx = st_parm->cnt_history; idx > 0;) {
1698 st_parm->history[idx] = NULL; 1699 idx--;
1699 } 1700 free(st_parm->history[idx]);
1701 st_parm->history[idx] = NULL;
1702 }
1700 1703
1701 /* fill temp_h[], retaining only last MAX_HISTORY lines */ 1704 /* fill temp_h[], retaining only last max_history lines */
1702 memset(temp_h, 0, sizeof(temp_h)); 1705 memset(temp_h, 0, sizeof(temp_h));
1703 idx = 0; 1706 idx = 0;
1704 st_parm->cnt_history_in_file = 0; 1707 st_parm->cnt_history_in_file = 0;
1708 if (st_parm->max_history != 0) {
1705 while ((line = xmalloc_fgetline(fp)) != NULL) { 1709 while ((line = xmalloc_fgetline(fp)) != NULL) {
1706 if (line[0] == '\0') { 1710 if (line[0] == '\0') {
1707 free(line); 1711 free(line);
@@ -1714,34 +1718,34 @@ static void load_history(line_input_t *st_parm)
1714 if (idx == st_parm->max_history) 1718 if (idx == st_parm->max_history)
1715 idx = 0; 1719 idx = 0;
1716 } 1720 }
1717 fclose(fp); 1721 }
1718 1722 fclose(fp);
1719 /* find first non-NULL temp_h[], if any */
1720 if (st_parm->cnt_history_in_file) {
1721 while (temp_h[idx] == NULL) {
1722 idx++;
1723 if (idx == st_parm->max_history)
1724 idx = 0;
1725 }
1726 }
1727 1723
1728 /* copy temp_h[] to st_parm->history[] */ 1724 /* find first non-NULL temp_h[], if any */
1729 for (i = 0; i < st_parm->max_history;) { 1725 if (st_parm->cnt_history_in_file != 0) {
1730 line = temp_h[idx]; 1726 while (temp_h[idx] == NULL) {
1731 if (!line)
1732 break;
1733 idx++; 1727 idx++;
1734 if (idx == st_parm->max_history) 1728 if (idx == st_parm->max_history)
1735 idx = 0; 1729 idx = 0;
1736 line_len = strlen(line);
1737 if (line_len >= MAX_LINELEN)
1738 line[MAX_LINELEN-1] = '\0';
1739 st_parm->history[i++] = line;
1740 } 1730 }
1741 st_parm->cnt_history = i;
1742 if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1743 st_parm->cnt_history_in_file = i;
1744 } 1731 }
1732
1733 /* copy temp_h[] to st_parm->history[] */
1734 for (i = 0; i < st_parm->max_history;) {
1735 line = temp_h[idx];
1736 if (!line)
1737 break;
1738 idx++;
1739 if (idx == st_parm->max_history)
1740 idx = 0;
1741 line_len = strlen(line);
1742 if (line_len >= MAX_LINELEN)
1743 line[MAX_LINELEN-1] = '\0';
1744 st_parm->history[i++] = line;
1745 }
1746 st_parm->cnt_history = i;
1747 if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1748 st_parm->cnt_history_in_file = i;
1745} 1749}
1746 1750
1747# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 1751# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
@@ -1749,17 +1753,27 @@ void FAST_FUNC save_history(line_input_t *st)
1749{ 1753{
1750 FILE *fp; 1754 FILE *fp;
1751 1755
1752 if (!st || !st->hist_file) 1756 /* bash compat: HISTFILE="" disables history saving */
1757 if (!st || !st->hist_file || !state->hist_file[0])
1753 return; 1758 return;
1754 if (st->cnt_history <= st->cnt_history_in_file) 1759 if (st->cnt_history <= st->cnt_history_in_file)
1755 return; 1760 return; /* no new entries were added */
1761 /* note: if st->max_history is 0, we do not abort: we truncate the history to 0 lines */
1756 1762
1757 fp = fopen(st->hist_file, "a"); 1763 fp = fopen(st->hist_file, (st->max_history == 0 ? "w" : "a"));
1758 if (fp) { 1764 if (fp) {
1759 int i, fd; 1765 int i, fd;
1760 char *new_name; 1766 char *new_name;
1761 line_input_t *st_temp; 1767 line_input_t *st_temp;
1762 1768
1769 /* max_history==0 needs special-casing in general code,
1770 * just handle it in a simpler way: */
1771 if (st->max_history == 0) {
1772 /* fopen("w") already truncated it */
1773 fclose(fp);
1774 return;
1775 }
1776
1763 for (i = st->cnt_history_in_file; i < st->cnt_history; i++) 1777 for (i = st->cnt_history_in_file; i < st->cnt_history; i++)
1764 fprintf(fp, "%s\n", st->history[i]); 1778 fprintf(fp, "%s\n", st->history[i]);
1765 fclose(fp); 1779 fclose(fp);
@@ -1769,6 +1783,8 @@ void FAST_FUNC save_history(line_input_t *st)
1769 st_temp = new_line_input_t(st->flags); 1783 st_temp = new_line_input_t(st->flags);
1770 st_temp->hist_file = st->hist_file; 1784 st_temp->hist_file = st->hist_file;
1771 st_temp->max_history = st->max_history; 1785 st_temp->max_history = st->max_history;
1786 /* load no more than max_history last lines */
1787 /* (in unlikely case that file disappeared, st_temp gets empty history) */
1772 load_history(st_temp); 1788 load_history(st_temp);
1773 1789
1774 /* write out temp file and replace hist_file atomically */ 1790 /* write out temp file and replace hist_file atomically */
@@ -1792,13 +1808,13 @@ static void save_history(char *str)
1792 int fd; 1808 int fd;
1793 int len, len2; 1809 int len, len2;
1794 1810
1795 if (!state->hist_file) 1811 /* bash compat: HISTFILE="" disables history saving */
1812 if (!state->hist_file || !state->hist_file[0])
1796 return; 1813 return;
1797 1814
1798 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); 1815 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
1799 if (fd < 0) 1816 if (fd < 0)
1800 return; 1817 return;
1801 xlseek(fd, 0, SEEK_END); /* paranoia */
1802 len = strlen(str); 1818 len = strlen(str);
1803 str[len] = '\n'; /* we (try to) do atomic write */ 1819 str[len] = '\n'; /* we (try to) do atomic write */
1804 len2 = full_write(fd, str, len + 1); 1820 len2 = full_write(fd, str, len + 1);
@@ -1853,13 +1869,10 @@ static void remember_in_history(char *str)
1853 if (str[0] == '\0') 1869 if (str[0] == '\0')
1854 return; 1870 return;
1855 i = state->cnt_history; 1871 i = state->cnt_history;
1856 /* Don't save dupes */ 1872 /* Don't save dups */
1857 if (i && strcmp(state->history[i-1], str) == 0) 1873 if (i != 0 && strcmp(state->history[i-1], str) == 0)
1858 return; 1874 return;
1859 1875
1860 free(state->history[state->max_history]); /* redundant, paranoia */
1861 state->history[state->max_history] = NULL; /* redundant, paranoia */
1862
1863 /* If history[] is full, remove the oldest command */ 1876 /* If history[] is full, remove the oldest command */
1864 /* we need to keep history[state->max_history] empty, hence >=, not > */ 1877 /* we need to keep history[state->max_history] empty, hence >=, not > */
1865 if (i >= state->max_history) { 1878 if (i >= state->max_history) {
@@ -1872,7 +1885,7 @@ static void remember_in_history(char *str)
1872 state->cnt_history_in_file--; 1885 state->cnt_history_in_file--;
1873# endif 1886# endif
1874 } 1887 }
1875 /* i <= state->max_history-1 */ 1888 /* i < state->max_history */
1876 state->history[i++] = xstrdup(str); 1889 state->history[i++] = xstrdup(str);
1877 /* i <= state->max_history */ 1890 /* i <= state->max_history */
1878 state->cur_history = i; 1891 state->cur_history = i;
@@ -2388,7 +2401,6 @@ static int lineedit_read_key(char *read_key_buffer, int timeout)
2388 errno = EINTR; 2401 errno = EINTR;
2389 return -1; 2402 return -1;
2390 } 2403 }
2391//FIXME: still races here with signals, but small window to poll() inside read_key
2392 IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) 2404 IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;)
2393 /* errno = 0; - read_key does this itself */ 2405 /* errno = 0; - read_key does this itself */
2394 ic = read_key(STDIN_FILENO, read_key_buffer, timeout); 2406 ic = read_key(STDIN_FILENO, read_key_buffer, timeout);
diff --git a/libbb/poll_with_signals.c b/libbb/poll_with_signals.c
new file mode 100644
index 000000000..d3c005418
--- /dev/null
+++ b/libbb/poll_with_signals.c
@@ -0,0 +1,48 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 2025 Denys Vlasenko <vda.linux@googlemail.com>
6 *
7 * Licensed under GPLv2, see file LICENSE in this source tree.
8 */
9//kbuild:lib-$(CONFIG_PLATFORM_POSIX) += poll_with_signals.o
10
11#include "libbb.h"
12
13/* Shells, for example, need their line input and "read" builtin
14 * to be interruptible, and the naive handling of it a-la:
15 * if (bb_got_signal) {
16 * errno = EINTR;
17 * return -1;
18 * }
19 * poll(pfd, 1, -1); // signal here would set EINTR
20 * is racy.
21 * This is a bit heavy-handed, but safe wrt races:
22 */
23int FAST_FUNC check_got_signal_and_poll(struct pollfd pfd[1], int timeout)
24{
25 int n;
26 struct timespec tv;
27 sigset_t orig_mask;
28
29 if (bb_got_signal) /* optimization */
30 goto eintr;
31
32 if (timeout >= 0) {
33 tv.tv_sec = timeout / 1000;
34 tv.tv_nsec = (timeout % 1000) * 1000000;
35 }
36 /* test bb_got_signal, then poll(), atomically wrt signals */
37 sigfillset(&orig_mask);
38 sigprocmask2(SIG_BLOCK, &orig_mask);
39 if (bb_got_signal) {
40 sigprocmask2(SIG_SETMASK, &orig_mask);
41 eintr:
42 errno = EINTR; /* inform the caller that we got a signal */
43 return -1;
44 }
45 n = ppoll(pfd, 1, timeout >= 0 ? &tv : NULL, &orig_mask);
46 sigprocmask2(SIG_SETMASK, &orig_mask);
47 return n;
48}
diff --git a/libbb/pw_ascii64.c b/libbb/pw_ascii64.c
new file mode 100644
index 000000000..3993932ca
--- /dev/null
+++ b/libbb/pw_ascii64.c
@@ -0,0 +1,91 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10/* Returns >=64 for invalid chars */
11int FAST_FUNC a2i64(char c)
12{
13 unsigned char ch = c;
14 if (ch >= 'a')
15 /* "a..z" to 38..63 */
16 /* anything after "z": positive int >= 64 */
17 return (ch - 'a' + 38);
18
19 if (ch > 'Z')
20 /* after "Z" but before "a": positive byte >= 64 */
21 return ch;
22
23 if (ch >= 'A')
24 /* "A..Z" to 12..37 */
25 return (ch - 'A' + 12);
26
27 if (ch > '9')
28 return 64;
29
30 /* "./0123456789" to 0,1,2..11 */
31 /* anything before "." becomes positive byte >= 64 */
32 return (unsigned char)(ch - '.');
33}
34
35/* 0..63 ->
36 * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
37 */
38int FAST_FUNC i2a64(int i)
39{
40 i &= 0x3f;
41
42 i += '.';
43 /* the above maps 0..11 to "./0123456789":
44 * ACSII codes of "./" are ('0'-2) and ('0'-1) */
45
46 if (i > '9')
47 i += ('A' - '9' - 1);
48 if (i > 'Z')
49 i += ('a' - 'Z' - 1);
50 return i;
51}
52
53char* FAST_FUNC
54num2str64_lsb_first(char *s, unsigned v, int n)
55{
56 while (--n >= 0) {
57 *s++ = i2a64(v);
58 v >>= 6;
59 }
60 return s;
61}
62
63static void
64num2str64_4chars_msb_first(char *s, unsigned v)
65{
66 *s++ = i2a64(v >> 18); /* bits 23..18 */
67 *s++ = i2a64(v >> 12); /* bits 17..12 */
68 *s++ = i2a64(v >> 6); /* bits 11..6 */
69 *s = i2a64(v); /* bits 5..0 */
70}
71
72int FAST_FUNC crypt_make_rand64encoded(char *p, int cnt /*, int x */)
73{
74 /* was: x += ... */
75 unsigned x = getpid() + monotonic_us();
76 do {
77 /* x = (x*1664525 + 1013904223) % 2^32 generator is lame
78 * (low-order bit is not "random", etc...),
79 * but for our purposes it is good enough */
80 x = x*1664525 + 1013904223;
81 /* BTW, Park and Miller's "minimal standard generator" is
82 * x = x*16807 % ((2^31)-1)
83 * It has no problem with visibly alternating lowest bit
84 * but is also weak in cryptographic sense + needs div,
85 * which needs more code (and slower) on many CPUs */
86 *p++ = i2a64(x >> 16);
87 *p++ = i2a64(x >> 22);
88 } while (--cnt);
89 *p = '\0';
90 return x;
91}
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
index 3463fd95b..93653de9f 100644
--- a/libbb/pw_encrypt.c
+++ b/libbb/pw_encrypt.c
@@ -13,48 +13,11 @@
13#endif 13#endif
14#include "libbb.h" 14#include "libbb.h"
15 15
16/* static const uint8_t ascii64[] ALIGN1 = 16#include "pw_ascii64.c"
17 * "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
18 */
19
20static int i64c(int i)
21{
22 i &= 0x3f;
23 if (i == 0)
24 return '.';
25 if (i == 1)
26 return '/';
27 if (i < 12)
28 return ('0' - 2 + i);
29 if (i < 38)
30 return ('A' - 12 + i);
31 return ('a' - 38 + i);
32}
33
34int FAST_FUNC crypt_make_salt(char *p, int cnt /*, int x */)
35{
36 /* was: x += ... */
37 unsigned x = getpid() + monotonic_us();
38 do {
39 /* x = (x*1664525 + 1013904223) % 2^32 generator is lame
40 * (low-order bit is not "random", etc...),
41 * but for our purposes it is good enough */
42 x = x*1664525 + 1013904223;
43 /* BTW, Park and Miller's "minimal standard generator" is
44 * x = x*16807 % ((2^31)-1)
45 * It has no problem with visibly alternating lowest bit
46 * but is also weak in cryptographic sense + needs div,
47 * which needs more code (and slower) on many CPUs */
48 *p++ = i64c(x >> 16);
49 *p++ = i64c(x >> 22);
50 } while (--cnt);
51 *p = '\0';
52 return x;
53}
54 17
55char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo) 18char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo)
56{ 19{
57 int len = 2/2; 20 int len = 2 / 2;
58 char *salt_ptr = salt; 21 char *salt_ptr = salt;
59 22
60 /* Standard chpasswd uses uppercase algos ("MD5", not "md5"). 23 /* Standard chpasswd uses uppercase algos ("MD5", not "md5").
@@ -67,28 +30,61 @@ char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo)
67 *salt_ptr++ = '$'; 30 *salt_ptr++ = '$';
68#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA 31#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA
69 if ((algo[0]|0x20) == 's') { /* sha */ 32 if ((algo[0]|0x20) == 's') { /* sha */
70 salt[1] = '5' + (strcasecmp(algo, "sha512") == 0); 33 salt[1] = '5' + (strncasecmp(algo, "sha512", 6) == 0);
71 len = 16/2; 34 len = 16 / 2;
35 }
36#endif
37#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_YES
38 if ((algo[0]|0x20) == 'y') { /* yescrypt */
39 int rnd;
40 salt[1] = 'y';
41// The "j9T$" below is the default "yescrypt parameters" encoded by yescrypt_encode_params_r():
42//shadow-4.17.4/src/passwd.c
43// salt = crypt_make_salt(NULL, NULL);
44//shadow-4.17.4/lib/salt.c
45//const char *crypt_make_salt(const char *meth, void *arg)
46// if (streq(method, "YESCRYPT")) {
47// MAGNUM(result, 'y');
48// salt_len = YESCRYPT_SALT_SIZE; // 24
49// rounds = YESCRYPT_get_salt_cost(arg); // always Y_COST_DEFAULT == 5 for NULL arg
50// YESCRYPT_salt_cost_to_buf(result, rounds); // always "j9T$"
51// char *retval = crypt_gensalt(result, rounds, NULL, 0);
52//libxcrypt-4.4.38/lib/crypt-yescrypt.c
53//void gensalt_yescrypt_rn (unsigned long count,
54// const uint8_t *rbytes, size_t nrbytes,
55// uint8_t *output, size_t o_size)
56// yescrypt_params_t params = {
57// .flags = YESCRYPT_DEFAULTS,
58// .p = 1,
59// };
60// if (count < 3) ... else
61// params.r = 32; // N in 4KiB
62// params.N = 1ULL << (count + 7); // 3 -> 1024, 4 -> 2048, ... 11 -> 262144
63// yescrypt_encode_params_r(&params, rbytes, nrbytes, outbuf, o_size) // always "$y$j9T$<random>"
64 len = 22 / 2;
65 salt_ptr = stpcpy(salt_ptr, "j9T$");
66 /* append 2*len random chars */
67 rnd = crypt_make_rand64encoded(salt_ptr, len);
68 /* fix up last char: it must be in 0..3 range (encoded as one of "./01").
69 * IOW: salt_ptr[20..21] encode 16th random byte, must not be > 0xff.
70 * Without this, we can generate salts which are rejected
71 * by implementations with more strict salt length check.
72 */
73 salt_ptr[21] = i2a64(rnd & 3);
74 /* For "mkpasswd -m yescrypt PASS j9T$<salt>" use case,
75 * "j9T$" is considered part of salt,
76 * need to return pointer to 'j'. Without -4,
77 * we'd end up using "j9T$j9T$<salt>" as salt.
78 */
79 return salt_ptr - 4;
72 } 80 }
73#endif 81#endif
74 } 82 }
75 crypt_make_salt(salt_ptr, len); 83 crypt_make_rand64encoded(salt_ptr, len); /* appends 2*len random chars */
76 return salt_ptr; 84 return salt_ptr;
77} 85}
78 86
79#if ENABLE_USE_BB_CRYPT 87#if ENABLE_USE_BB_CRYPT
80
81static char*
82to64(char *s, unsigned v, int n)
83{
84 while (--n >= 0) {
85 /* *s++ = ascii64[v & 0x3f]; */
86 *s++ = i64c(v);
87 v >>= 6;
88 }
89 return s;
90}
91
92/* 88/*
93 * DES and MD5 crypt implementations are taken from uclibc. 89 * DES and MD5 crypt implementations are taken from uclibc.
94 * They were modified to not use static buffers. 90 * They were modified to not use static buffers.
@@ -99,6 +95,9 @@ to64(char *s, unsigned v, int n)
99#if ENABLE_USE_BB_CRYPT_SHA 95#if ENABLE_USE_BB_CRYPT_SHA
100#include "pw_encrypt_sha.c" 96#include "pw_encrypt_sha.c"
101#endif 97#endif
98#if ENABLE_USE_BB_CRYPT_YES
99#include "pw_encrypt_yes.c"
100#endif
102 101
103/* Other advanced crypt ids (TODO?): */ 102/* Other advanced crypt ids (TODO?): */
104/* $2$ or $2a$: Blowfish */ 103/* $2$ or $2a$: Blowfish */
@@ -109,7 +108,7 @@ static struct des_ctx *des_ctx;
109/* my_crypt returns malloc'ed data */ 108/* my_crypt returns malloc'ed data */
110static char *my_crypt(const char *key, const char *salt) 109static char *my_crypt(const char *key, const char *salt)
111{ 110{
112 /* MD5 or SHA? */ 111 /* "$x$...." string? */
113 if (salt[0] == '$' && salt[1] && salt[2] == '$') { 112 if (salt[0] == '$' && salt[1] && salt[2] == '$') {
114 if (salt[1] == '1') 113 if (salt[1] == '1')
115 return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); 114 return md5_crypt(xzalloc(MD5_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
@@ -117,6 +116,10 @@ static char *my_crypt(const char *key, const char *salt)
117 if (salt[1] == '5' || salt[1] == '6') 116 if (salt[1] == '5' || salt[1] == '6')
118 return sha_crypt((char*)key, (char*)salt); 117 return sha_crypt((char*)key, (char*)salt);
119#endif 118#endif
119#if ENABLE_USE_BB_CRYPT_YES
120 if (salt[1] == 'y')
121 return yes_crypt(key, salt);
122#endif
120 } 123 }
121 124
122 if (!des_cctx) 125 if (!des_cctx)
diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c
index fe8237cfe..ca8aa9bcc 100644
--- a/libbb/pw_encrypt_des.c
+++ b/libbb/pw_encrypt_des.c
@@ -186,39 +186,9 @@ static const uint8_t pbox[32] ALIGN1 = {
186 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 186 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
187}; 187};
188 188
189static const uint32_t bits32[32] ALIGN4 = {
190 0x80000000, 0x40000000, 0x20000000, 0x10000000,
191 0x08000000, 0x04000000, 0x02000000, 0x01000000,
192 0x00800000, 0x00400000, 0x00200000, 0x00100000,
193 0x00080000, 0x00040000, 0x00020000, 0x00010000,
194 0x00008000, 0x00004000, 0x00002000, 0x00001000,
195 0x00000800, 0x00000400, 0x00000200, 0x00000100,
196 0x00000080, 0x00000040, 0x00000020, 0x00000010,
197 0x00000008, 0x00000004, 0x00000002, 0x00000001
198};
199
200static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; 189static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
201 190
202 191
203static int
204ascii_to_bin(char ch)
205{
206 if (ch > 'z')
207 return 0;
208 if (ch >= 'a')
209 return (ch - 'a' + 38);
210 if (ch > 'Z')
211 return 0;
212 if (ch >= 'A')
213 return (ch - 'A' + 12);
214 if (ch > '9')
215 return 0;
216 if (ch >= '.')
217 return (ch - '.');
218 return 0;
219}
220
221
222/* Static stuff that stays resident and doesn't change after 192/* Static stuff that stays resident and doesn't change after
223 * being initialized, and therefore doesn't need to be made 193 * being initialized, and therefore doesn't need to be made
224 * reentrant. */ 194 * reentrant. */
@@ -354,11 +324,18 @@ des_init(struct des_ctx *ctx, const struct const_des_ctx *cctx)
354 int i, j, b, k, inbit, obit; 324 int i, j, b, k, inbit, obit;
355 uint32_t p; 325 uint32_t p;
356 const uint32_t *bits28, *bits24; 326 const uint32_t *bits28, *bits24;
327 uint32_t bits32[32];
357 328
358 if (!ctx) 329 if (!ctx)
359 ctx = xmalloc(sizeof(*ctx)); 330 ctx = xmalloc(sizeof(*ctx));
360 const_ctx = cctx; 331 const_ctx = cctx;
361 332
333 p = 0x80000000U;
334 for (i = 0; p; i++) {
335 bits32[i] = p;
336 p >>= 1;
337 }
338
362#if USE_REPETITIVE_SPEEDUP 339#if USE_REPETITIVE_SPEEDUP
363 old_rawkey0 = old_rawkey1 = 0; 340 old_rawkey0 = old_rawkey1 = 0;
364 old_salt = 0; 341 old_salt = 0;
@@ -694,21 +671,6 @@ do_des(struct des_ctx *ctx, /*uint32_t l_in, uint32_t r_in,*/ uint32_t *l_out, u
694 671
695#define DES_OUT_BUFSIZE 21 672#define DES_OUT_BUFSIZE 21
696 673
697static void
698to64_msb_first(char *s, unsigned v)
699{
700#if 0
701 *s++ = ascii64[(v >> 18) & 0x3f]; /* bits 23..18 */
702 *s++ = ascii64[(v >> 12) & 0x3f]; /* bits 17..12 */
703 *s++ = ascii64[(v >> 6) & 0x3f]; /* bits 11..6 */
704 *s = ascii64[v & 0x3f]; /* bits 5..0 */
705#endif
706 *s++ = i64c(v >> 18); /* bits 23..18 */
707 *s++ = i64c(v >> 12); /* bits 17..12 */
708 *s++ = i64c(v >> 6); /* bits 11..6 */
709 *s = i64c(v); /* bits 5..0 */
710}
711
712static char * 674static char *
713NOINLINE 675NOINLINE
714des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], 676des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
@@ -740,44 +702,28 @@ des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
740 */ 702 */
741 output[0] = salt_str[0]; 703 output[0] = salt_str[0];
742 output[1] = salt_str[1]; 704 output[1] = salt_str[1];
743 salt = (ascii_to_bin(salt_str[1]) << 6) 705
744 | ascii_to_bin(salt_str[0]); 706 salt = a2i64(salt_str[0]);
707 if (salt >= 64)
708 return NULL; /* bad salt char */
709 salt |= (a2i64(salt_str[1]) << 6);
710 if (salt >= (64 << 6))
711 return NULL; /* bad salt char */
745 setup_salt(ctx, salt); /* set ctx->saltbits for do_des() */ 712 setup_salt(ctx, salt); /* set ctx->saltbits for do_des() */
746 713
747 /* Do it. */ 714 /* Do it. */
748 do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */); 715 do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */);
749 716
750 /* Now encode the result. */ 717 /* Now encode the result. */
751#if 0
752{
753 uint32_t l = (r0 >> 8);
754 q = (uint8_t *)output + 2;
755 *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 31..26 of r0 */
756 *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 25..20 of r0 */
757 *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 19..14 of r0 */
758 *q++ = ascii64[l & 0x3f]; /* bits 13..8 of r0 */
759 l = ((r0 << 16) | (r1 >> 16));
760 *q++ = ascii64[(l >> 18) & 0x3f]; /* bits 7..2 of r0 */
761 *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 1..2 of r0 and 31..28 of r1 */
762 *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 27..22 of r1 */
763 *q++ = ascii64[l & 0x3f]; /* bits 21..16 of r1 */
764 l = r1 << 2;
765 *q++ = ascii64[(l >> 12) & 0x3f]; /* bits 15..10 of r1 */
766 *q++ = ascii64[(l >> 6) & 0x3f]; /* bits 9..4 of r1 */
767 *q++ = ascii64[l & 0x3f]; /* bits 3..0 of r1 + 00 */
768 *q = 0;
769}
770#else
771 /* Each call takes low-order 24 bits and stores 4 chars */ 718 /* Each call takes low-order 24 bits and stores 4 chars */
772 /* bits 31..8 of r0 */ 719 /* bits 31..8 of r0 */
773 to64_msb_first(output + 2, (r0 >> 8)); 720 num2str64_4chars_msb_first(output + 2, (r0 >> 8));
774 /* bits 7..0 of r0 and 31..16 of r1 */ 721 /* bits 7..0 of r0 and 31..16 of r1 */
775 to64_msb_first(output + 6, (r0 << 16) | (r1 >> 16)); 722 num2str64_4chars_msb_first(output + 6, (r0 << 16) | (r1 >> 16));
776 /* bits 15..0 of r1 and two zero bits (plus extra zero byte) */ 723 /* bits 15..0 of r1 and two zero bits (plus extra zero byte) */
777 to64_msb_first(output + 10, (r1 << 8)); 724 num2str64_4chars_msb_first(output + 10, (r1 << 8));
778 /* extra zero byte is encoded as '.', fixing it */ 725 /* extra zero byte is encoded as '.', fixing it */
779 output[13] = '\0'; 726 output[13] = '\0';
780#endif
781 727
782 return output; 728 return output;
783} 729}
diff --git a/libbb/pw_encrypt_md5.c b/libbb/pw_encrypt_md5.c
index 1e52ecaea..92d039f96 100644
--- a/libbb/pw_encrypt_md5.c
+++ b/libbb/pw_encrypt_md5.c
@@ -149,9 +149,9 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned
149 final[16] = final[5]; 149 final[16] = final[5];
150 for (i = 0; i < 5; i++) { 150 for (i = 0; i < 5; i++) {
151 unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12]; 151 unsigned l = (final[i] << 16) | (final[i+6] << 8) | final[i+12];
152 p = to64(p, l, 4); 152 p = num2str64_lsb_first(p, l, 4);
153 } 153 }
154 p = to64(p, final[11], 2); 154 p = num2str64_lsb_first(p, final[11], 2);
155 *p = '\0'; 155 *p = '\0';
156 156
157 /* Don't leave anything around in vm they could use. */ 157 /* Don't leave anything around in vm they could use. */
diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c
index 5457d7ab6..695a5c07f 100644
--- a/libbb/pw_encrypt_sha.c
+++ b/libbb/pw_encrypt_sha.c
@@ -84,8 +84,7 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
84 as a scratch space later. */ 84 as a scratch space later. */
85 salt_data = xstrndup(salt_data, salt_len); 85 salt_data = xstrndup(salt_data, salt_len);
86 /* add "salt$" to result */ 86 /* add "salt$" to result */
87 strcpy(resptr, salt_data); 87 resptr = stpcpy(resptr, salt_data);
88 resptr += salt_len;
89 *resptr++ = '$'; 88 *resptr++ = '$';
90 /* key data doesn't need much processing */ 89 /* key data doesn't need much processing */
91 key_len = strlen(key_data); 90 key_len = strlen(key_data);
@@ -198,7 +197,7 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data)
198#define b64_from_24bit(B2, B1, B0, N) \ 197#define b64_from_24bit(B2, B1, B0, N) \
199do { \ 198do { \
200 unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ 199 unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \
201 resptr = to64(resptr, w, N); \ 200 resptr = num2str64_lsb_first(resptr, w, N); \
202} while (0) 201} while (0)
203 if (_32or64 == 32) { /* sha256 */ 202 if (_32or64 == 32) { /* sha256 */
204 unsigned i = 0; 203 unsigned i = 0;
diff --git a/libbb/pw_encrypt_yes.c b/libbb/pw_encrypt_yes.c
new file mode 100644
index 000000000..50bd06418
--- /dev/null
+++ b/libbb/pw_encrypt_yes.c
@@ -0,0 +1,24 @@
1/*
2 * Utility routines.
3 *
4 * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8#include "yescrypt/alg-yescrypt.h"
9
10static char *
11yes_crypt(const char *passwd, const char *salt_data)
12{
13 /* prefix, '$', hash, NUL */
14 char buf[YESCRYPT_PREFIX_LEN + 1 + YESCRYPT_HASH_LEN + 1];
15 char *retval;
16
17 retval = yescrypt_r(
18 (const uint8_t *)passwd, strlen(passwd),
19 (const uint8_t *)salt_data,
20 buf, sizeof(buf));
21 /* The returned value is either buf[], or NULL on error */
22
23 return xstrdup(retval);
24}
diff --git a/libbb/read_key.c b/libbb/read_key.c
index 54886cc9c..2414105ee 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -11,7 +11,7 @@
11 11
12int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) 12int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
13{ 13{
14 struct pollfd pfd; 14 struct pollfd pfd[1];
15 const char *seq; 15 const char *seq;
16 int n; 16 int n;
17 17
@@ -117,8 +117,8 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
117 return windows_read_key(fd, buffer, timeout); 117 return windows_read_key(fd, buffer, timeout);
118#endif 118#endif
119 119
120 pfd.fd = fd; 120 pfd->fd = fd;
121 pfd.events = POLLIN; 121 pfd->events = POLLIN;
122 122
123 buffer++; /* saved chars counter is in buffer[-1] now */ 123 buffer++; /* saved chars counter is in buffer[-1] now */
124 124
@@ -126,12 +126,16 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
126 errno = 0; 126 errno = 0;
127 n = (unsigned char)buffer[-1]; 127 n = (unsigned char)buffer[-1];
128 if (n == 0) { 128 if (n == 0) {
129 /* If no data, wait for input. 129 /* No data. Wait for input. */
130 * If requested, wait TIMEOUT ms. TIMEOUT = -1 is useful 130
131 * if fd can be in non-blocking mode. 131 /* timeout == -2 means "do not poll". Else: */
132 */
133 if (timeout >= -1) { 132 if (timeout >= -1) {
134 n = poll(&pfd, 1, timeout); 133 /* We must poll even if timeout == -1:
134 * we want to be interrupted if signal arrives,
135 * regardless of SA_RESTART-ness of that signal!
136 */
137 /* test bb_got_signal, then poll(), atomically wrt signals */
138 n = check_got_signal_and_poll(pfd, timeout);
135 if (n < 0 && errno == EINTR) 139 if (n < 0 && errno == EINTR)
136 return n; 140 return n;
137 if (n == 0) { 141 if (n == 0) {
@@ -140,6 +144,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
140 return -1; 144 return -1;
141 } 145 }
142 } 146 }
147
143 /* It is tempting to read more than one byte here, 148 /* It is tempting to read more than one byte here,
144 * but it breaks pasting. Example: at shell prompt, 149 * but it breaks pasting. Example: at shell prompt,
145 * user presses "c","a","t" and then pastes "\nline\n". 150 * user presses "c","a","t" and then pastes "\nline\n".
@@ -178,7 +183,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
178 * so if we block for long it's not really an escape sequence. 183 * so if we block for long it's not really an escape sequence.
179 * Timeout is needed to reconnect escape sequences 184 * Timeout is needed to reconnect escape sequences
180 * split up by transmission over a serial console. */ 185 * split up by transmission over a serial console. */
181 if (safe_poll(&pfd, 1, 50) == 0) { 186 if (safe_poll(pfd, 1, 50) == 0) {
182 /* No more data! 187 /* No more data!
183 * Array is sorted from shortest to longest, 188 * Array is sorted from shortest to longest,
184 * we can't match anything later in array - 189 * we can't match anything later in array -
@@ -227,7 +232,7 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
227 * n = bytes read. Try to read more until we time out. 232 * n = bytes read. Try to read more until we time out.
228 */ 233 */
229 while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */ 234 while (n < KEYCODE_BUFFER_SIZE-1) { /* 1 for count byte at buffer[-1] */
230 if (safe_poll(&pfd, 1, 50) == 0) { 235 if (safe_poll(pfd, 1, 50) == 0) {
231 /* No more data! */ 236 /* No more data! */
232 break; 237 break;
233 } 238 }
diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c
index ef2b6f891..e233849c5 100644
--- a/libbb/u_signal_names.c
+++ b/libbb/u_signal_names.c
@@ -27,10 +27,6 @@
27 27
28#include "libbb.h" 28#include "libbb.h"
29 29
30#if ENABLE_PLATFORM_MINGW32
31# undef SIGPIPE
32#endif
33
34#if ENABLE_PLATFORM_POSIX || defined(SIGSTKFLT) || defined(SIGVTALRM) 30#if ENABLE_PLATFORM_POSIX || defined(SIGSTKFLT) || defined(SIGVTALRM)
35# define SIGLEN 7 31# define SIGLEN 7
36#elif defined(SIGWINCH) || (ENABLE_FEATURE_RTMINMAX && \ 32#elif defined(SIGWINCH) || (ENABLE_FEATURE_RTMINMAX && \
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index 7df1a4cd3..5609858d1 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -333,7 +333,7 @@ int FAST_FUNC get_termios_and_make_raw(int fd, struct termios *newterm, struct t
333 *newterm = *oldterm; 333 *newterm = *oldterm;
334 334
335#if ENABLE_PLATFORM_MINGW32 335#if ENABLE_PLATFORM_MINGW32
336 newterm->imode &= 336 newterm->w_mode &=
337 ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT); 337 ~(ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
338#else 338#else
339 /* Turn off buffered input (ICANON) 339 /* Turn off buffered input (ICANON)
diff --git a/libbb/yescrypt/Kbuild.src b/libbb/yescrypt/Kbuild.src
new file mode 100644
index 000000000..a61211a29
--- /dev/null
+++ b/libbb/yescrypt/Kbuild.src
@@ -0,0 +1,9 @@
1# Makefile for busybox
2#
3# Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com>
4#
5# Licensed under GPLv2, see file LICENSE in this source tree.
6
7lib-y:=
8
9INSERT
diff --git a/libbb/yescrypt/PARAMETERS b/libbb/yescrypt/PARAMETERS
new file mode 100644
index 000000000..d9f5d24e6
--- /dev/null
+++ b/libbb/yescrypt/PARAMETERS
@@ -0,0 +1,196 @@
1 Optimal yescrypt configuration.
2
3yescrypt is very flexible, but configuring it optimally is complicated.
4Here are some guidelines to simplify near-optimal configuration. We
5start by listing the parameters and their typical values, and then give
6currently recommended parameter sets by use case.
7
8
9 Parameters and their typical values.
10
11Set flags (yescrypt flavor) to YESCRYPT_DEFAULTS to use the currently
12recommended flavor. (Other flags values exist for compatibility and for
13specialized cases where you think you know what you're doing.)
14
15Set N (block count) based on target memory usage and running time, as
16well as on the value of r (block size in 128 byte units). N must be a
17power of two.
18
19Set r (block size) to 8 (so that N is in KiB, which is convenient) or to
20another small value (if more optimal or for fine-tuning of the total
21size and/or running time). Reasonable values for r are from 8 to 96.
22
23Set p (parallelism) to 1 meaning no thread-level parallelism within one
24computation of yescrypt. (Use of thread-level parallelism within
25yescrypt makes sense for ROM initialization and for key derivation at
26high memory usage, but usually not for password hashing where
27parallelism is available through concurrent authentication attempts.
28Don't use p > 1 unnecessarily.)
29
30Set t (time) to 0 to use the optimal running time for a given memory
31usage. This will allow you to maximize the memory usage (the value of
32N*r) while staying within your running time constraints. (Non-zero t
33makes sense in specialized cases where you can't afford higher memory
34usage but can afford more time.)
35
36Set g (upgrades) to 0 because there have been no hash upgrades yet.
37
38Set NROM (block count of ROM) to 0 unless you use a ROM (see below).
39NROM must be a power of two.
40
41
42 Password hashing for user authentication, no ROM.
43
44Small and fast (memory usage 2 MiB, performance like bcrypt cost 2^5 -
45latency 2-3 ms and throughput 10,000+ per second on a 16-core server):
46
47flags = YESCRYPT_DEFAULTS, N = 2048, r = 8, p = 1, t = 0, g = 0, NROM = 0
48
49Large and slow (memory usage 16 MiB, performance like bcrypt cost 2^8 -
50latency 10-30 ms and throughput 1000+ per second on a 16-core server):
51
52flags = YESCRYPT_DEFAULTS, N = 4096, r = 32, p = 1, t = 0, g = 0, NROM = 0
53
54Of course, even heavier and slower settings are possible, if affordable.
55Simply double the value of N as many times as needed. Since N must be a
56power of two, you may use r (in the range of 8 to 32) or/and t (in the
57range of 0 to 2) for fine-tuning the running time, but first bring N to
58the maximum you can afford. If this feels too complicated, just use one
59of the two parameter sets given above (preferably the second) as-is.
60
61
62 Password hashing for user authentication, with ROM.
63
64It's similar to the above, except that you need to adjust r, set NROM,
65and initialize the ROM.
66
67First decide on a ROM size, such as making it a large portion of your
68dedicated authentication servers' RAM sizes. Since NROM (block count)
69must be a power of two, you might need to choose r (block size) based on
70how your desired ROM size corresponds to a power of two. Also tuning
71for performance on current hardware, you'll likely end up with r in the
72range from slightly below 16 to 32. For example, to use 15/16 of a
73server's 256 GiB RAM as ROM (thus, making it 240 GiB), you could use
74r=15 or r=30. To use 23/24 of a server's 384 GiB RAM as ROM (thus,
75making it 368 GiB), you'd use r=23. Then set NROM to your desired ROM
76size in KiB divided by 128*r. Note that these examples might (or might
77not) be too extreme, leaving little memory for the rest of the system.
78You could as well opt for 7/8 with r=14 or 11/12 with r=11 or r=22.
79
80Note that higher r may make placing of ROM in e.g. NVMe flash memory
81instead of in RAM more reasonable (or less unreasonable) than it would
82have been with a lower r. If this is a concern as it relates to
83possible attacks and you do not intend to ever do it defensively, you
84might want to keep r lower (e.g., prefer r=15 over r=30 in the example
85above, even if 30 performs slightly faster).
86
87Your adjustments to r, if you deviate from powers of two, will also
88result in weirder memory usage per hash. Like 1.75 MiB at r=14 instead
89of 2 MiB at r=8 that you would have used without a ROM. That's OK.
90
91For ROM initialization, which you do with yescrypt_init_shared(), use
92the same r and NROM that you'd later use for password hashing, choose p
93based on your servers' physical and/or logical CPU count (maybe
94considering eventual upgrades as you won't be able to change this later,
95but without going unnecessarily high - e.g., p=28, p=56, or p=112 make
96sense on servers that currently have 28 physical / 56 logical CPUs), and
97set the rest of the parameters to:
98
99flags = YESCRYPT_DEFAULTS, N = 0, t = 0, g = 0
100
101N is set to 0 because it isn't relevant during ROM initialization (you
102can use different values of N for hashing passwords with the same ROM).
103
104To keep the ROM in e.g. SysV shared memory and reuse it across your
105authentication service restarts, you'd need to allocate the memory and
106set the flags to "YESCRYPT_DEFAULTS | YESCRYPT_SHARED_PREALLOCATED".
107
108For actual password hashing, you'd use your chosen values for N, r,
109NROM, and set the rest of the parameters to:
110
111flags = YESCRYPT_DEFAULTS, p = 1, t = 0, g = 0
112
113Note that although you'd use a large p for ROM initialization, you
114should use p=1 for actual password hashing like you would without a ROM.
115
116Do not forget to pass the ROM into the actual password hashing (and keep
117r and NROM set accordingly).
118
119Since N must be a power of two and r is dependent on ROM size, you may
120use t (in the range of 0 to 2) for fine-tuning the running time, but
121first bring N to the maximum you can afford.
122
123If this feels too complicated, or even if it doesn't, please consider
124engaging Openwall for your yescrypt deployment. We'd be happy to help.
125
126
127 Password-based key derivation.
128
129(Or rather passphrase-based.)
130
131Use settings similar to those for password hashing without a ROM, but
132adjusted for higher memory usage and running time, and optionally with
133thread-level parallelism.
134
135Small and fast (memory usage 128 MiB, running time under 100 ms on a
136fast desktop):
137
138flags = YESCRYPT_DEFAULTS, N = 32768, r = 32, p = 1, t = 0, g = 0, NROM = 0
139
140Large and fast (memory usage 1 GiB, running time under 200 ms on a fast
141quad-core desktop not including memory allocation overhead, under 250 ms
142with the overhead included), but requires build with OpenMP support (or
143otherwise will run as slow as yet be weaker than its p=1 alternative):
144
145flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 0, g = 0, NROM = 0
146
147Large and slower (memory usage 1 GiB, running time under 300 ms on a
148fast quad-core desktop not including memory allocation overhead, under
149350 ms with the overhead included), also requires build with OpenMP
150support (or otherwise will run slower than the p=1 alternative below):
151
152flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 4, t = 2, g = 0, NROM = 0
153
154Large and slow (memory usage 1 GiB, running time under 600 ms on a fast
155desktop not including memory allocation overhead, under 650 ms with the
156overhead included):
157
158flags = YESCRYPT_DEFAULTS, N = 262144, r = 32, p = 1, t = 0, g = 0, NROM = 0
159
160Just like with password hashing, even heavier and slower settings are
161possible, if affordable, and you achieve them by adjusting N, r, t in
162the same way and in the same preferred ranges (please see the section on
163password hashing without a ROM, above). Unlike with password hashing,
164it makes some sense to go above t=2 if you expect that your users might
165not be able to afford more memory but can afford more time. However,
166increasing the memory usage provides better protection, and we don't
167recommend forcing your users to wait for more than 1 second as they
168could as well type more characters in that time. If this feels too
169complicated, just use one of the above parameter sets as-is.
170
171
172 Amortization of memory allocation overhead.
173
174It takes a significant fraction of yescrypt's total running time to
175allocate memory from the operating system, especially considering that
176the kernel zeroizes the memory before handing it over to your program.
177
178Unless you naturally need to compute yescrypt just once per process, you
179may achieve greater efficiency by fully using advanced yescrypt APIs
180that let you preserve and reuse the memory allocation across yescrypt
181invocations. This is done by reusing the structure pointed to by the
182"yescrypt_local_t *local" argument of yescrypt_r() or yescrypt_kdf()
183without calling yescrypt_free_local() inbetween the repeated invocations
184of yescrypt.
185
186
187 YESCRYPT_DEFAULTS macro.
188
189Please note that the value of the YESCRYPT_DEFAULTS macro might change
190later, so if you use the macro like it's recommended here then for
191results reproducible across versions you might need to store its value
192somewhere along with the hashes or the encrypted data.
193
194If you use yescrypt's standard hash string encoding, then yescrypt
195already encodes and decodes this value for you, so you don't need to
196worry about this.
diff --git a/libbb/yescrypt/README b/libbb/yescrypt/README
new file mode 100644
index 000000000..c1011c56a
--- /dev/null
+++ b/libbb/yescrypt/README
@@ -0,0 +1,4 @@
1The yescrypt code in this directory is adapted from libxcrypt-4.4.38
2with minimal edits, hopefully making it easier to track
3backports by resetting the tree to the commit which created this file,
4then comparing changes in upstream libxcrypt to the tree.
diff --git a/libbb/yescrypt/alg-sha256.c b/libbb/yescrypt/alg-sha256.c
new file mode 100644
index 000000000..20e8d1ee4
--- /dev/null
+++ b/libbb/yescrypt/alg-sha256.c
@@ -0,0 +1,86 @@
1/*-
2 * Copyright 2005-2016 Colin Percival
3 * Copyright 2016-2018,2021 Alexander Peslyak
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28/**
29 * PBKDF2_SHA256(passwd, passwdlen, salt, saltlen, c, buf, dkLen):
30 * Compute PBKDF2(passwd, salt, c, dkLen) using HMAC-SHA256 as the PRF, and
31 * write the output to buf. The value dkLen must be at most 32 * (2^32 - 1).
32 */
33static void
34PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen,
35 const uint8_t *salt, size_t saltlen,
36 uint64_t c, uint8_t *buf, size_t dkLen)
37{
38 hmac_ctx_t Phctx, PShctx;
39 uint32_t i;
40
41 /* Compute HMAC state after processing P. */
42 hmac_begin(&Phctx, passwd, passwdlen, sha256_begin);
43
44 /* Compute HMAC state after processing P and S. */
45 PShctx = Phctx;
46 hmac_hash(&PShctx, salt, saltlen);
47
48 /* Iterate through the blocks. */
49 for (i = 0; dkLen != 0; ) {
50 uint64_t U[32 / 8];
51 uint64_t T[32 / 8];
52 uint64_t j;
53 uint32_t ivec;
54 size_t clen;
55 int k;
56
57 /* Generate INT(i). */
58 i++;
59 ivec = SWAP_BE32(i);
60
61 /* Compute U_1 = PRF(P, S || INT(i)). */
62 hmac_peek_hash(&PShctx, (void*)T, &ivec, 4, NULL);
63//TODO: the above is a vararg function, might incur some ABI pain
64//does libbb need a non-vararg version with just one (buf,len)?
65
66 if (c > 1) {
67 /* T_i = U_1 ... */
68 memcpy(U, T, 32);
69 for (j = 2; j <= c; j++) {
70 /* Compute U_j. */
71 hmac_peek_hash(&Phctx, (void*)U, U, 32, NULL);
72 /* ... xor U_j ... */
73 for (k = 0; k < 32 / 8; k++)
74 T[k] ^= U[k];
75 //TODO: xorbuf32_aligned_long(T, U);
76 }
77 }
78
79 /* Copy as many bytes as necessary into buf. */
80 clen = dkLen;
81 if (clen > 32)
82 clen = 32;
83 buf = mempcpy(buf, T, clen);
84 dkLen -= clen;
85 }
86}
diff --git a/libbb/yescrypt/alg-yescrypt-common.c b/libbb/yescrypt/alg-yescrypt-common.c
new file mode 100644
index 000000000..c51823787
--- /dev/null
+++ b/libbb/yescrypt/alg-yescrypt-common.c
@@ -0,0 +1,408 @@
1/*-
2 * Copyright 2013-2018 Alexander Peslyak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted.
7 *
8 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
9 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
10 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
11 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
12 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
13 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
14 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
15 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
16 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
17 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
18 * SUCH DAMAGE.
19 */
20
21#if RESTRICTED_PARAMS
22
23#define decode64_uint32(dst, src, min) \
24({ \
25 uint32_t d32 = a2i64(*(src)); \
26 if (d32 > 47) \
27 goto fail; \
28 *(dst) = d32 + (min); \
29 ++src; \
30})
31#define test_decode64_uint32() ((void)0)
32#define FULL_PARAMS(...)
33
34#else
35
36#define FULL_PARAMS(...) __VA_ARGS__
37
38/* Not inlining:
39 * de/encode64 functions are only used to read
40 * yescrypt_params_t field, and convert salt to binary -
41 * both of these are negligible compared to main hashing operation
42 */
43static NOINLINE const uint8_t *decode64_uint32(
44 uint32_t *dst,
45 const uint8_t *src, uint32_t val)
46{
47 uint32_t start = 0, end = 47, bits = 0;
48 uint32_t c;
49
50 if (!src) /* previous decode failed already? */
51 goto fail;
52
53 c = a2i64(*src++);
54 if (c > 63)
55 goto fail;
56
57// The encoding of number N:
58// start = 0 end = 47
59// If N < 48, it is encoded verbatim, else
60// N -= 48
61// start = end+1 = 48
62// end += (64-end)/2 = 55
63// If N < (end+1-start)<<6 = 8<<6, it is encoded as 48+(N>>6)|low6bits (that is, 48...55|<6bit>), else
64// N -= 8<<6
65// start = end+1 = 56
66// end += (64-end)/2 = 59
67// If N < (end+1-start)<<2*6 = 4<<12, it is encoded as 56+(N>>2*6)|low12bits (that is, 56...59|<6bit>|<6bit>), else
68// ...same for 60..61|<6bit>|<6bit>|<6bit>
69// .......same for 62|<6bit>|<6bit>|<6bit>|<6bit>
70// .......same for 63|<6bit>|<6bit>|<6bit>|<6bit>|<6bit>
71 dbg_dec64("c:%d val:0x%08x", (int)c, (unsigned)val);
72 while (c > end) {
73 dbg_dec64("c:%d > end:%d", (int)c, (int)end);
74 val += (end + 1 - start) << bits;
75 dbg_dec64("val+=0x%08x", (int)((end + 1 - start) << bits));
76 dbg_dec64(" val:0x%08x", (unsigned)val);
77 start = end + 1;
78 end += (64 - end) / 2;
79 bits += 6;
80 dbg_dec64("start=%d", (int)start);
81 dbg_dec64("end=%d", (int)end);
82 dbg_dec64("bits=%d", (int)bits);
83 }
84
85 val += (c - start) << bits;
86 dbg_dec64("final val+=0x%08x", (int)((c - start) << bits));
87 dbg_dec64(" val:0x%08x", (unsigned)val);
88
89 while (bits != 0) {
90 c = a2i64(*src++);
91 if (c > 63)
92 goto fail;
93 bits -= 6;
94 val += c << bits;
95 dbg_dec64("low bits val+=0x%08x", (int)(c << bits));
96 dbg_dec64(" val:0x%08x", (unsigned)val);
97 }
98 ret:
99 *dst = val;
100 return src;
101 fail:
102 val = 0;
103 src = NULL;
104 goto ret;
105}
106
107#if TEST_DECODE64
108static void test_decode64_uint32(void)
109{
110 const uint8_t *src, *end;
111 uint32_t u32;
112 int a = 48;
113 int b = 8<<6; // 0x0200
114 int c = 4<<12; // 0x04000
115 int d = 2<<18; // 0x080000
116 int e = 1<<24; // 0x1000000
117
118 src = (void*)"wzzz";
119 end = decode64_uint32(&u32, src, 0);
120 if (u32 != 0x0003ffff+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
121 if (end != src + 4) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
122 src = (void*)"xzzz";
123 end = decode64_uint32(&u32, src, 0);
124 if (u32 != 0x0007ffff+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
125 if (end != src + 4) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
126 // Note how the last representable "x---" encoding, 0x7ffff, is exactly d-1!
127 // And if we now increment it, we get:
128 src = (void*)"y....";
129 end = decode64_uint32(&u32, src, 0);
130 if (u32 != 0x00000000+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
131 if (end != src + 5) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
132 src = (void*)"yzzzz";
133 end = decode64_uint32(&u32, src, 0);
134 if (u32 != 0x00ffffff+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
135 if (end != src + 5) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
136
137 src = (void*)"zzzzzz";
138 end = decode64_uint32(&u32, src, 0);
139 if (u32 != 0x3fffffff+e+d+c+b+a) bb_error_msg_and_die("Incorrect decode '%s':0x%08x", src, (unsigned)u32);
140 if (end != src + 6) bb_error_msg_and_die("Incorrect decode '%s': %p end:%p", src, src, end);
141
142 bb_error_msg("test_decode64_uint32() OK");
143}
144#else
145# define test_decode64_uint32() ((void)0)
146#endif
147
148#endif /* !RESTRICTED_PARAMS */
149
150#if 1
151static const uint8_t *decode64(
152 uint8_t *dst, size_t *dstlen,
153 const uint8_t *src)
154{
155 unsigned dstpos = 0;
156
157 dbg_dec64("src:'%s'", src);
158 for (;;) {
159 uint32_t c, value = 0;
160 int bits = 0;
161 while (*src != '\0' && *src != '$') {
162 c = a2i64(*src);
163 if (c > 63) { /* bad ascii64 char, stop decoding at it */
164 break;
165 }
166 src++;
167 value |= c << bits;
168 bits += 6;
169 if (bits == 24) /* got 4 chars */
170 goto store;
171 }
172 /* we read entire src, or met a non-ascii64 char (such as "$") */
173 if (bits == 0)
174 break;
175 /* else: we got last, partial bit block - store it */
176 store:
177 dbg_dec64(" storing bits:%d dstpos:%u v:%08x", bits, dstpos, (int)SWAP_BE32(value)); //BE to see lsb first
178 for (;;) {
179 if ((*src == '\0' || *src == '$')
180 && value == 0 && bits < 8
181 ) {
182 /* Example: mkpasswd PWD '$y$j9T$123':
183 * the "123" is bits:18 value:03,51,00
184 * is considered to be 2 bytes, not 3!
185 *
186 * '$y$j9T$zzz' in upstream fails outright (3rd byte isn't zero).
187 * IOW: for upstream, validity of salt depends on VALUE,
188 * not just size of salt. Which is a bug.
189 * The '$y$j9T$zzz.' salt is the same
190 * (it adds 6 zero msbits) but upstream works with it,
191 * thus '$y$j9T$zzz' should work too and give the same result.
192 */
193 goto end;
194 }
195 if (dstpos >= *dstlen) {
196 dbg_dec64(" ERR: bits:%d dstpos:%u dst[] is too small", bits, dstpos);
197 goto fail;
198 }
199 *dst++ = value;
200 dstpos++;
201 value >>= 8;
202 bits -= 8;
203 if (bits <= 0) /* can get negative, if we e.g. had 6 bits */
204 break;
205 }
206 if (*src == '\0' || *src == '$')
207 break;
208 }
209 end:
210 *dstlen = dstpos;
211 dbg_dec64("dec64: OK, dst[%d]", (int)dstpos);
212 return src;
213 fail:
214 /* *dstlen = 0; - not needed, caller detects error by seeing NULL */
215 return NULL;
216}
217#else
218/* Buggy (and larger) original code */
219static const uint8_t *decode64(
220 uint8_t *dst, size_t *dstlen,
221 const uint8_t *src, size_t srclen)
222{
223 size_t dstpos = 0;
224
225 while (dstpos <= *dstlen && srclen) {
226 uint32_t value = 0, bits = 0;
227 while (srclen--) {
228 uint32_t c = a2i64(*src);
229 if (c > 63) {
230 srclen = 0;
231 break;
232 }
233 src++;
234 value |= c << bits;
235 bits += 6;
236 if (bits >= 24)
237 break;
238 }
239 if (!bits)
240 break;
241 if (bits < 12) /* must have at least one full byte */
242 goto fail;
243 dbg_dec64(" storing bits:%d v:%08x", (int)bits, (int)SWAP_BE32(value)); //BE to see lsb first
244 while (dstpos++ < *dstlen) {
245 *dst++ = value;
246 value >>= 8;
247 bits -= 8;
248 if (bits < 8) { /* 2 or 4 */
249 if (value) /* must be 0 */
250 goto fail;
251 bits = 0;
252 break;
253 }
254 }
255 if (bits)
256 goto fail;
257 }
258
259 if (!srclen && dstpos <= *dstlen) {
260 *dstlen = dstpos;
261 dbg_dec64("dec64: OK, dst[%d]", (int)dstpos);
262 return src;
263 }
264 fail:
265 /* *dstlen = 0; - not needed, caller detects error by seeing NULL */
266 return NULL;
267}
268#endif
269
270static char *encode64(
271 char *dst, size_t dstlen,
272 const uint8_t *src, size_t srclen)
273{
274 while (srclen) {
275 uint32_t value = 0, b = 0;
276 do {
277 value |= (uint32_t)(*src++ << b);
278 b += 8;
279 srclen--;
280 } while (srclen && b < 24);
281
282 b >>= 3; /* number of bits to number of bytes */
283 b++; /* 1, 2 or 3 bytes will become 2, 3 or 4 ascii64 chars */
284 dstlen -= b;
285 if ((ssize_t)dstlen <= 0)
286 return NULL;
287 dst = num2str64_lsb_first(dst, value, b);
288 }
289 *dst = '\0';
290 return dst;
291}
292
293char *yescrypt_r(
294 const uint8_t *passwd, size_t passwdlen,
295 const uint8_t *setting,
296 char *buf, size_t buflen)
297{
298 struct {
299 yescrypt_ctx_t yctx[1];
300 unsigned char hashbin32[32];
301 } u;
302#define yctx u.yctx
303#define hashbin32 u.hashbin32
304 char *dst;
305 const uint8_t *src, *saltend;
306 size_t need, prefixlen;
307 uint32_t u32;
308
309 test_decode64_uint32();
310
311 memset(yctx, 0, sizeof(yctx));
312 FULL_PARAMS(yctx->param.p = 1;)
313
314 /* we assume setting starts with "$y$" (caller must ensure this) */
315 src = setting + 3;
316
317 src = decode64_uint32(&yctx->param.flags, src, 0);
318 /* "j9T" returns: 0x2f */
319 //if (!src)
320 // goto fail;
321
322 if (yctx->param.flags < YESCRYPT_RW) {
323 dbg("yctx->param.flags=0x%x", (unsigned)yctx->param.flags);
324 goto fail; // bbox: we don't support scrypt - only yescrypt
325 } else if (yctx->param.flags <= YESCRYPT_RW + (YESCRYPT_RW_FLAVOR_MASK >> 2)) {
326 /* "j9T" sets flags to 0xb6 */
327 yctx->param.flags = YESCRYPT_RW + ((yctx->param.flags - YESCRYPT_RW) << 2);
328 dbg("yctx->param.flags=0x%x", (unsigned)yctx->param.flags);
329 dbg(" YESCRYPT_RW:%u", !!(yctx->param.flags & YESCRYPT_RW));
330 dbg((yctx->param.flags & YESCRYPT_RW_FLAVOR_MASK) ==
331 (YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K)
332 ? " YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K"
333 : " flags are not standard"
334 );
335 } else {
336 goto fail;
337 }
338
339 src = decode64_uint32(&u32, src, 1);
340 if (/*!src ||*/ u32 > 63)
341 goto fail;
342 yctx->param.N = (uint64_t)1 << u32;
343 /* "j9T" sets to 4096 (1<<12) */
344 dbg("yctx->param.N=%llu (1<<%u)", (unsigned long long)yctx->param.N, (unsigned)u32);
345
346 src = decode64_uint32(&yctx->param.r, src, 1);
347 /* "j9T" sets to 32 */
348 dbg("yctx->param.r=%u", yctx->param.r);
349
350 if (!src)
351 goto fail;
352 if (*src != '$') {
353#if RESTRICTED_PARAMS
354 goto fail;
355#else
356 src = decode64_uint32(&u32, src, 1);
357 dbg("yescrypt has extended params:0x%x", (unsigned)u32);
358 if (u32 & 1)
359 src = decode64_uint32(&yctx->param.p, src, 2);
360 if (u32 & 2)
361 src = decode64_uint32(&yctx->param.t, src, 1);
362 if (u32 & 4)
363 src = decode64_uint32(&yctx->param.g, src, 1);
364 if (u32 & 8) {
365 src = decode64_uint32(&u32, src, 1);
366 if (/*!src ||*/ u32 > 63)
367 goto fail;
368 yctx->param.NROM = (uint64_t)1 << u32;
369 }
370 if (!src)
371 goto fail;
372 if (*src != '$')
373 goto fail;
374#endif
375 }
376
377 yctx->saltlen = sizeof(yctx->salt);
378 src++; /* now points to salt */
379 saltend = decode64(yctx->salt, &yctx->saltlen, src);
380 if (!saltend || (*saltend != '\0' && *saltend != '$'))
381 goto fail; /* salt[] is too small, or bad char during decode */
382 dbg_dec64("salt is %d ascii64 chars -> %d bytes (in binary)", (int)(saltend - src), (int)yctx->saltlen);
383
384 prefixlen = saltend - setting;
385 need = prefixlen + 1 + YESCRYPT_HASH_LEN + 1;
386 if (need > buflen /*overflow is quite unlikely: || need < prefixlen*/)
387 goto fail;
388
389 if (yescrypt_kdf32(yctx, passwd, passwdlen, hashbin32)) {
390 dbg("error in yescrypt_kdf32");
391 goto fail;
392 }
393
394 dst = mempcpy(buf, setting, prefixlen);
395 *dst++ = '$';
396 dst = encode64(dst, buflen - (dst - buf), hashbin32, sizeof(hashbin32));
397 if (!dst)
398 goto fail;
399 ret:
400 free_region(yctx->local);
401 explicit_bzero(&u, sizeof(u));
402 return buf;
403 fail:
404 buf = NULL;
405 goto ret;
406#undef yctx
407#undef hashbin32
408}
diff --git a/libbb/yescrypt/alg-yescrypt-kdf.c b/libbb/yescrypt/alg-yescrypt-kdf.c
new file mode 100644
index 000000000..a9a1bd591
--- /dev/null
+++ b/libbb/yescrypt/alg-yescrypt-kdf.c
@@ -0,0 +1,1212 @@
1/*-
2 * Copyright 2009 Colin Percival
3 * Copyright 2012-2018 Alexander Peslyak
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * This file was originally written by Colin Percival as part of the Tarsnap
28 * online backup system.
29 */
30
31#if __STDC_VERSION__ >= 199901L
32/* Have restrict */
33#elif defined(__GNUC__)
34#define restrict __restrict
35#else
36#define restrict
37#endif
38
39#ifdef __GNUC__
40#define unlikely(exp) __builtin_expect(exp, 0)
41#else
42#define unlikely(exp) (exp)
43#endif
44
45typedef union {
46 uint32_t w[16];
47 uint64_t d[8];
48} salsa20_blk_t;
49
50static void salsa20_simd_shuffle(
51 const salsa20_blk_t *Bin,
52 salsa20_blk_t *Bout)
53{
54#define COMBINE(out, in1, in2) \
55do { \
56 Bout->d[out] = Bin->w[in1 * 2] | ((uint64_t)Bin->w[in2 * 2 + 1] << 32); \
57} while (0)
58 COMBINE(0, 0, 2);
59 COMBINE(1, 5, 7);
60 COMBINE(2, 2, 4);
61 COMBINE(3, 7, 1);
62 COMBINE(4, 4, 6);
63 COMBINE(5, 1, 3);
64 COMBINE(6, 6, 0);
65 COMBINE(7, 3, 5);
66#undef COMBINE
67}
68
69static void salsa20_simd_unshuffle(
70 const salsa20_blk_t *Bin,
71 salsa20_blk_t *Bout)
72{
73#define UNCOMBINE(out, in1, in2) \
74do { \
75 Bout->w[out * 2] = Bin->d[in1]; \
76 Bout->w[out * 2 + 1] = Bin->d[in2] >> 32; \
77} while (0)
78 UNCOMBINE(0, 0, 6);
79 UNCOMBINE(1, 5, 3);
80 UNCOMBINE(2, 2, 0);
81 UNCOMBINE(3, 7, 5);
82 UNCOMBINE(4, 4, 2);
83 UNCOMBINE(5, 1, 7);
84 UNCOMBINE(6, 6, 4);
85 UNCOMBINE(7, 3, 1);
86#undef UNCOMBINE
87}
88
89#define DECL_X \
90 salsa20_blk_t X
91#define DECL_Y \
92 salsa20_blk_t Y
93
94#if KDF_UNROLL_COPY
95#define COPY(out, in) \
96do { \
97 (out).d[0] = (in).d[0]; \
98 (out).d[1] = (in).d[1]; \
99 (out).d[2] = (in).d[2]; \
100 (out).d[3] = (in).d[3]; \
101 (out).d[4] = (in).d[4]; \
102 (out).d[5] = (in).d[5]; \
103 (out).d[6] = (in).d[6]; \
104 (out).d[7] = (in).d[7]; \
105} while (0)
106#else
107#define COPY(out, in) \
108do { \
109 memcpy((out).d, (in).d, sizeof((in).d)); \
110} while (0)
111#endif
112
113#define READ_X(in) COPY(X, in)
114#define WRITE_X(out) COPY(out, X)
115
116/**
117 * salsa20(B):
118 * Apply the Salsa20 core to the provided block.
119 */
120static void salsa20(salsa20_blk_t *restrict B,
121 salsa20_blk_t *restrict Bout,
122 uint32_t doublerounds)
123{
124 salsa20_blk_t X;
125#define x X.w
126
127 salsa20_simd_unshuffle(B, &X);
128
129 do {
130#define R(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
131 /* Operate on columns */
132#if KDF_UNROLL_SALSA20
133 x[ 4] ^= R(x[ 0]+x[12], 7); // x[j] ^= R(x[k]+x[l], CONST)
134 x[ 8] ^= R(x[ 4]+x[ 0], 9);
135 x[12] ^= R(x[ 8]+x[ 4],13);
136 x[ 0] ^= R(x[12]+x[ 8],18);
137
138 x[ 9] ^= R(x[ 5]+x[ 1], 7);
139 x[13] ^= R(x[ 9]+x[ 5], 9);
140 x[ 1] ^= R(x[13]+x[ 9],13);
141 x[ 5] ^= R(x[ 1]+x[13],18);
142
143 x[14] ^= R(x[10]+x[ 6], 7);
144 x[ 2] ^= R(x[14]+x[10], 9);
145 x[ 6] ^= R(x[ 2]+x[14],13);
146 x[10] ^= R(x[ 6]+x[ 2],18);
147
148 x[ 3] ^= R(x[15]+x[11], 7);
149 x[ 7] ^= R(x[ 3]+x[15], 9);
150 x[11] ^= R(x[ 7]+x[ 3],13);
151 x[15] ^= R(x[11]+x[ 7],18);
152#else
153 {
154 unsigned j, k, l;
155 j = 4; k = 0; l = 12;
156 for (;;) {
157 uint32_t t;
158 x[j] ^= ({ t = x[k] + x[l]; R(t, 7); }); l = k; k = j; j = (j+4) & 0xf;
159 x[j] ^= ({ t = x[k] + x[l]; R(t, 9); }); l = k; k = j; j = (j+4) & 0xf;
160 x[j] ^= ({ t = x[k] + x[l]; R(t,13); }); l = k; k = j; j = (j+4) & 0xf;
161 x[j] ^= ({ t = x[k] + x[l]; R(t,18); });
162 if (j == 15) break;
163 l = j + 1; k = j + 5; j = (j+9) & 0xf;
164 }
165 }
166#endif
167 /* Operate on rows */
168#if KDF_UNROLL_SALSA20
169// i=0 n=0
170 x[ 1] ^= R(x[ 0]+x[ 3], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3]
171 x[ 2] ^= R(x[ 1]+x[ 0], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3]
172 x[ 3] ^= R(x[ 2]+x[ 1],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3]
173 x[ 0] ^= R(x[ 3]+x[ 2],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3]
174// i=4 n=1 ^^^j^^^ ^^^k^^^ ^^^l^^^
175 x[ 6] ^= R(x[ 5]+x[ 4], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3]
176 x[ 7] ^= R(x[ 6]+x[ 5], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3]
177 x[ 4] ^= R(x[ 7]+x[ 6],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3]
178 x[ 5] ^= R(x[ 4]+x[ 7],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3]
179// i=8 n=2
180 x[11] ^= R(x[10]+x[ 9], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3]
181 x[ 8] ^= R(x[11]+x[10], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3]
182 x[ 9] ^= R(x[ 8]+x[11],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3]
183 x[10] ^= R(x[ 9]+x[ 8],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3]
184// i=12 n=3
185 x[12] ^= R(x[15]+x[14], 7); // [i + (n+1)&3] [i + (n+0)&3] [i + (n+3)&3]
186 x[13] ^= R(x[12]+x[15], 9); // [i + (n+2)&3] [i + (n+1)&3] [i + (n+0)&3]
187 x[14] ^= R(x[13]+x[12],13); // [i + (n+3)&3] [i + (n+2)&3] [i + (n+1)&3]
188 x[15] ^= R(x[14]+x[13],18); // [i + (n+0)&3] [i + (n+3)&3] [i + (n+2)&3]
189#else
190 {
191 unsigned j, k, l;
192 uint32_t *xrow;
193 j = 1; k = 0; l = 3;
194 xrow = &x[0];
195 for (;;) {
196 uint32_t t;
197 xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t, 7); }); l = k; k = j; j = (j+1) & 3;
198 xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t, 9); }); l = k; k = j; j = (j+1) & 3;
199 xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t,13); }); l = k; k = j; j = (j+1) & 3;
200 xrow[j] ^= ({ t = xrow[k] + xrow[l]; R(t,18); });
201 if (j == 3) break;
202 l = j; k = j + 1; j = (j+2) & 3;
203 xrow += 4;
204 }
205 }
206#endif
207
208#undef R
209 } while (--doublerounds);
210#undef x
211
212 {
213 uint32_t i;
214 salsa20_simd_shuffle(&X, Bout);
215 for (i = 0; i < 16; i++) {
216 // bbox: note: was unrolled x4
217 B->w[i] = Bout->w[i] += B->w[i];
218 }
219 }
220#if 0
221 /* Too expensive */
222 explicit_bzero(&X, sizeof(X));
223#endif
224}
225
226/**
227 * Apply the Salsa20/2 core to the block provided in X.
228 */
229#define SALSA20_2(out) \
230 salsa20(&X, &out, 1)
231
232#if 0
233#define XOR(out, in1, in2) \
234do { \
235 (out).d[0] = (in1).d[0] ^ (in2).d[0]; \
236 (out).d[1] = (in1).d[1] ^ (in2).d[1]; \
237 (out).d[2] = (in1).d[2] ^ (in2).d[2]; \
238 (out).d[3] = (in1).d[3] ^ (in2).d[3]; \
239 (out).d[4] = (in1).d[4] ^ (in2).d[4]; \
240 (out).d[5] = (in1).d[5] ^ (in2).d[5]; \
241 (out).d[6] = (in1).d[6] ^ (in2).d[6]; \
242 (out).d[7] = (in1).d[7] ^ (in2).d[7]; \
243} while (0)
244#else
245#define XOR(out, in1, in2) \
246do { \
247 xorbuf64_3_aligned64(&(out).d, &(in1).d, &(in2).d); \
248} while (0)
249#endif
250
251#define XOR_X(in) XOR(X, X, in)
252#define XOR_X_2(in1, in2) XOR(X, in1, in2)
253#define XOR_X_WRITE_XOR_Y_2(out, in) \
254do { \
255 XOR(Y, out, in); \
256 COPY(out, Y); \
257 XOR(X, X, Y); \
258} while (0)
259
260/**
261 * Apply the Salsa20/8 core to the block provided in X ^ in.
262 */
263#define SALSA20_8_XOR_MEM(in, out) \
264do { \
265 XOR_X(in); \
266 salsa20(&X, &out, 4); \
267} while (0)
268
269#define INTEGERIFY ((uint32_t)X.d[0])
270
271/**
272 * blockmix_salsa8(Bin, Bout, r):
273 * Compute Bout = BlockMix_{salsa20/8, r}(Bin). The input Bin must be 128r
274 * bytes in length; the output Bout must also be the same size.
275 */
276static void blockmix_salsa8(
277 const salsa20_blk_t *restrict Bin,
278 salsa20_blk_t *restrict Bout,
279 size_t r)
280{
281 size_t i;
282 DECL_X;
283
284 READ_X(Bin[r * 2 - 1]);
285 for (i = 0; i < r; i++) {
286 SALSA20_8_XOR_MEM(Bin[i * 2], Bout[i]);
287 SALSA20_8_XOR_MEM(Bin[i * 2 + 1], Bout[r + i]);
288 }
289}
290
291static uint32_t blockmix_salsa8_xor(
292 const salsa20_blk_t *restrict Bin1,
293 const salsa20_blk_t *restrict Bin2,
294 salsa20_blk_t *restrict Bout,
295 size_t r)
296{
297 size_t i;
298 DECL_X;
299
300 XOR_X_2(Bin1[r * 2 - 1], Bin2[r * 2 - 1]);
301 for (i = 0; i < r; i++) {
302 XOR_X(Bin1[i * 2]);
303 SALSA20_8_XOR_MEM(Bin2[i * 2], Bout[i]);
304 XOR_X(Bin1[i * 2 + 1]);
305 SALSA20_8_XOR_MEM(Bin2[i * 2 + 1], Bout[r + i]);
306 }
307
308 return INTEGERIFY;
309}
310
311/* This is tunable */
312#define Swidth 8
313
314/* Not tunable in this implementation, hard-coded in a few places */
315#define PWXsimple 2
316#define PWXgather 4
317
318/* Derived values. Not tunable except via Swidth above. */
319#define PWXbytes (PWXgather * PWXsimple * 8)
320#define Sbytes (3 * (1 << Swidth) * PWXsimple * 8)
321#define Smask (((1 << Swidth) - 1) * PWXsimple * 8)
322#define Smask2 (((uint64_t)Smask << 32) | Smask)
323
324#define DECL_SMASK2REG do {} while (0)
325#define FORCE_REGALLOC_3 do {} while (0)
326#define MAYBE_MEMORY_BARRIER do {} while (0)
327
328#define PWXFORM_SIMD(x0, x1) \
329do { \
330 uint64_t x = x0 & Smask2; \
331 uint64_t *p0 = (uint64_t *)(S0 + (uint32_t)x); \
332 uint64_t *p1 = (uint64_t *)(S1 + (x >> 32)); \
333 x0 = ((x0 >> 32) * (uint32_t)x0 + p0[0]) ^ p1[0]; \
334 x1 = ((x1 >> 32) * (uint32_t)x1 + p0[1]) ^ p1[1]; \
335} while (0)
336
337#if KDF_UNROLL_PWXFORM_ROUND
338#define PWXFORM_ROUND \
339do { \
340 PWXFORM_SIMD(X.d[0], X.d[1]); \
341 PWXFORM_SIMD(X.d[2], X.d[3]); \
342 PWXFORM_SIMD(X.d[4], X.d[5]); \
343 PWXFORM_SIMD(X.d[6], X.d[7]); \
344} while (0)
345#else
346#define PWXFORM_ROUND \
347do { \
348 for (int pwxi=0; pwxi<8; pwxi+=2) \
349 PWXFORM_SIMD(X.d[pwxi], X.d[pwxi + 1]); \
350} while (0)
351#endif
352
353/*
354 * This offset helps address the 256-byte write block via the single-byte
355 * displacements encodable in x86(-64) instructions. It is needed because the
356 * displacements are signed. Without it, we'd get 4-byte displacements for
357 * half of the writes. Setting it to 0x80 instead of 0x7c would avoid needing
358 * a displacement for one of the writes, but then the LEA instruction would
359 * need a 4-byte displacement.
360 */
361#define PWXFORM_WRITE_OFFSET 0x7c
362
363#define PWXFORM_WRITE \
364do { \
365 WRITE_X(*(salsa20_blk_t *)(Sw - PWXFORM_WRITE_OFFSET)); \
366 Sw += 64; \
367} while (0)
368
369#if KDF_UNROLL_PWXFORM
370#define PWXFORM \
371do { \
372 uint8_t *Sw = S2 + w + PWXFORM_WRITE_OFFSET; \
373 FORCE_REGALLOC_3; \
374 MAYBE_MEMORY_BARRIER; \
375 PWXFORM_ROUND; \
376 PWXFORM_ROUND; PWXFORM_WRITE; \
377 PWXFORM_ROUND; PWXFORM_WRITE; \
378 PWXFORM_ROUND; PWXFORM_WRITE; \
379 PWXFORM_ROUND; PWXFORM_WRITE; \
380 PWXFORM_ROUND; \
381 w = (w + 64 * 4) & Smask2; \
382 { \
383 uint8_t *Stmp = S2; \
384 S2 = S1; \
385 S1 = S0; \
386 S0 = Stmp; \
387 } \
388} while (0)
389#else
390#define PWXFORM \
391do { \
392 uint8_t *Sw = S2 + w + PWXFORM_WRITE_OFFSET; \
393 FORCE_REGALLOC_3; \
394 MAYBE_MEMORY_BARRIER; \
395 PWXFORM_ROUND; \
396 for (int pwxj=0; pwxj<4; pwxj++) {\
397 PWXFORM_ROUND; PWXFORM_WRITE; \
398 } \
399 PWXFORM_ROUND; \
400 w = (w + 64 * 4) & Smask2; \
401 { \
402 uint8_t *Stmp = S2; \
403 S2 = S1; \
404 S1 = S0; \
405 S0 = Stmp; \
406 } \
407} while (0)
408#endif
409
410typedef struct {
411 uint8_t *S0, *S1, *S2;
412 size_t w;
413} pwxform_ctx_t;
414
415#define Salloc (Sbytes + ((sizeof(pwxform_ctx_t) + 63) & ~63U))
416
417/**
418 * blockmix_pwxform(Bin, Bout, r, S):
419 * Compute Bout = BlockMix_pwxform{salsa20/2, r, S}(Bin). The input Bin must
420 * be 128r bytes in length; the output Bout must also be the same size.
421 */
422static void blockmix(
423 const salsa20_blk_t *restrict Bin,
424 salsa20_blk_t *restrict Bout,
425 size_t r,
426 pwxform_ctx_t *restrict ctx)
427{
428 uint8_t *S0 = ctx->S0, *S1 = ctx->S1, *S2 = ctx->S2;
429 size_t w = ctx->w;
430 size_t i;
431 DECL_X;
432
433 /* Convert count of 128-byte blocks to max index of 64-byte block */
434 r = r * 2 - 1;
435
436 READ_X(Bin[r]);
437
438 DECL_SMASK2REG;
439
440 i = 0;
441 for (;;) {
442 XOR_X(Bin[i]);
443 PWXFORM;
444 if (unlikely(i >= r))
445 break;
446 WRITE_X(Bout[i]);
447 i++;
448 }
449
450 ctx->S0 = S0;
451 ctx->S1 = S1;
452 ctx->S2 = S2;
453 ctx->w = w;
454
455 SALSA20_2(Bout[i]);
456}
457
458static uint32_t blockmix_xor(
459 const salsa20_blk_t *Bin1,
460 const salsa20_blk_t *restrict Bin2,
461 salsa20_blk_t *Bout,
462 size_t r,
463 pwxform_ctx_t *restrict ctx)
464{
465 uint8_t *S0 = ctx->S0, *S1 = ctx->S1, *S2 = ctx->S2;
466 size_t w = ctx->w;
467 size_t i;
468 DECL_X;
469
470 /* Convert count of 128-byte blocks to max index of 64-byte block */
471 r = r * 2 - 1;
472
473 XOR_X_2(Bin1[r], Bin2[r]);
474
475 DECL_SMASK2REG;
476
477 i = 0;
478 r--;
479 for (;;) {
480 XOR_X(Bin1[i]);
481 XOR_X(Bin2[i]);
482 PWXFORM;
483 if (unlikely(i > r))
484 break;
485 WRITE_X(Bout[i]);
486 i++;
487 }
488
489 ctx->S0 = S0;
490 ctx->S1 = S1;
491 ctx->S2 = S2;
492 ctx->w = w;
493
494 SALSA20_2(Bout[i]);
495
496 return INTEGERIFY;
497}
498
499static uint32_t blockmix_xor_save(
500 salsa20_blk_t *restrict Bin1out,
501 salsa20_blk_t *restrict Bin2,
502 size_t r,
503 pwxform_ctx_t *restrict ctx)
504{
505 uint8_t *S0 = ctx->S0, *S1 = ctx->S1, *S2 = ctx->S2;
506 size_t w = ctx->w;
507 size_t i;
508 DECL_X;
509 DECL_Y;
510
511 /* Convert count of 128-byte blocks to max index of 64-byte block */
512 r = r * 2 - 1;
513
514 XOR_X_2(Bin1out[r], Bin2[r]);
515
516 DECL_SMASK2REG;
517
518 i = 0;
519 r--;
520 for (;;) {
521 XOR_X_WRITE_XOR_Y_2(Bin2[i], Bin1out[i]);
522 PWXFORM;
523 if (unlikely(i > r))
524 break;
525 WRITE_X(Bin1out[i]);
526 i++;
527 }
528
529 ctx->S0 = S0;
530 ctx->S1 = S1;
531 ctx->S2 = S2;
532 ctx->w = w;
533
534 SALSA20_2(Bin1out[i]);
535
536 return INTEGERIFY;
537}
538
539/**
540 * integerify(B, r):
541 * Return the result of parsing B_{2r-1} as a little-endian integer.
542 */
543static inline uint32_t integerify(const salsa20_blk_t *B, size_t r)
544{
545/*
546 * Our 64-bit words are in host byte order, which is why we don't just read
547 * w[0] here (would be wrong on big-endian). Also, our 32-bit words are
548 * SIMD-shuffled (so the next 32 bits would be part of d[6]), but currently
549 * this does not matter as we only care about the least significant 32 bits.
550 */
551 return (uint32_t)B[2 * r - 1].d[0];
552}
553
554/**
555 * smix1(B, r, N, flags, V, NROM, VROM, XY, ctx):
556 * Compute first loop of B = SMix_r(B, N). The input B must be 128r bytes in
557 * length; the temporary storage V must be 128rN bytes in length; the temporary
558 * storage XY must be 128r+64 bytes in length. N must be even and at least 4.
559 * The array V must be aligned to a multiple of 64 bytes, and arrays B and XY
560 * to a multiple of at least 16 bytes.
561 */
562#if DISABLE_NROM_CODE
563#define smix1(B,r,N,flags,V,NROM,VROM,XY,ctx) \
564 smix1(B,r,N,flags,V,XY,ctx)
565#endif
566static void smix1(uint8_t *B, size_t r, uint32_t N,
567 uint32_t flags,
568 salsa20_blk_t *V,
569 uint32_t NROM, const salsa20_blk_t *VROM,
570 salsa20_blk_t *XY,
571 pwxform_ctx_t *ctx)
572{
573#if DISABLE_NROM_CODE
574 uint32_t NROM = 0;
575 const salsa20_blk_t *VROM = NULL;
576#endif
577 size_t s = 2 * r;
578 salsa20_blk_t *X = V, *Y = &V[s];
579 uint32_t i, j;
580
581 for (i = 0; i < 2 * r; i++) {
582 const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64];
583 salsa20_blk_t *tmp = Y;
584 salsa20_blk_t *dst = &X[i];
585 size_t k;
586 for (k = 0; k < 16; k++)
587 tmp->w[k] = SWAP_LE32(src->w[k]);
588 salsa20_simd_shuffle(tmp, dst);
589 }
590
591 if (VROM) {
592 uint32_t n;
593 const salsa20_blk_t *V_j;
594
595 V_j = &VROM[(NROM - 1) * s];
596 j = blockmix_xor(X, V_j, Y, r, ctx) & (NROM - 1);
597 V_j = &VROM[j * s];
598 X = Y + s;
599 j = blockmix_xor(Y, V_j, X, r, ctx);
600
601 for (n = 2; n < N; n <<= 1) {
602 uint32_t m = (n < N / 2) ? n : (N - 1 - n);
603 for (i = 1; i < m; i += 2) {
604 j &= n - 1;
605 j += i - 1;
606 V_j = &V[j * s];
607 Y = X + s;
608 j = blockmix_xor(X, V_j, Y, r, ctx) & (NROM - 1);
609 V_j = &VROM[j * s];
610 X = Y + s;
611 j = blockmix_xor(Y, V_j, X, r, ctx);
612 }
613 }
614 n >>= 1;
615
616 j &= n - 1;
617 j += N - 2 - n;
618 V_j = &V[j * s];
619 Y = X + s;
620 j = blockmix_xor(X, V_j, Y, r, ctx) & (NROM - 1);
621 V_j = &VROM[j * s];
622 blockmix_xor(Y, V_j, XY, r, ctx);
623 } else if (flags & YESCRYPT_RW) {
624//can't use flags___YESCRYPT_RW, smix1() may be called with flags = 0
625 uint32_t n;
626 salsa20_blk_t *V_j;
627
628 blockmix(X, Y, r, ctx);
629 X = Y + s;
630 blockmix(Y, X, r, ctx);
631 j = integerify(X, r);
632
633 for (n = 2; n < N; n <<= 1) {
634 uint32_t m = (n < N / 2) ? n : (N - 1 - n);
635 for (i = 1; i < m; i += 2) {
636 Y = X + s;
637 j &= n - 1;
638 j += i - 1;
639 V_j = &V[j * s];
640 j = blockmix_xor(X, V_j, Y, r, ctx);
641 j &= n - 1;
642 j += i;
643 V_j = &V[j * s];
644 X = Y + s;
645 j = blockmix_xor(Y, V_j, X, r, ctx);
646 }
647 }
648 n >>= 1;
649
650 j &= n - 1;
651 j += N - 2 - n;
652 V_j = &V[j * s];
653 Y = X + s;
654 j = blockmix_xor(X, V_j, Y, r, ctx);
655 j &= n - 1;
656 j += N - 1 - n;
657 V_j = &V[j * s];
658 blockmix_xor(Y, V_j, XY, r, ctx);
659 } else {
660 N -= 2;
661 do {
662 blockmix_salsa8(X, Y, r);
663 X = Y + s;
664 blockmix_salsa8(Y, X, r);
665 Y = X + s;
666 } while ((N -= 2));
667
668 blockmix_salsa8(X, Y, r);
669 blockmix_salsa8(Y, XY, r);
670 }
671
672 for (i = 0; i < 2 * r; i++) {
673 const salsa20_blk_t *src = &XY[i];
674 salsa20_blk_t *tmp = &XY[s];
675 salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64];
676 size_t k;
677 for (k = 0; k < 16; k++)
678 tmp->w[k] = SWAP_LE32(src->w[k]);
679 salsa20_simd_unshuffle(tmp, dst);
680 }
681}
682
683/**
684 * smix2(B, r, N, Nloop, flags, V, NROM, VROM, XY, ctx):
685 * Compute second loop of B = SMix_r(B, N). The input B must be 128r bytes in
686 * length; the temporary storage V must be 128rN bytes in length; the temporary
687 * storage XY must be 256r bytes in length. N must be a power of 2 and at
688 * least 2. Nloop must be even. The array V must be aligned to a multiple of
689 * 64 bytes, and arrays B and XY to a multiple of at least 16 bytes.
690 */
691#if DISABLE_NROM_CODE
692#define smix2(B,r,N,Nloop,flags,V,NROM,VROM,XY,ctx) \
693 smix2(B,r,N,Nloop,flags,V,XY,ctx)
694#endif
695static void smix2(uint8_t *B, size_t r, uint32_t N, uint64_t Nloop,
696 uint32_t flags,
697 salsa20_blk_t *V,
698 uint32_t NROM, const salsa20_blk_t *VROM,
699 salsa20_blk_t *XY,
700 pwxform_ctx_t *ctx)
701{
702#if DISABLE_NROM_CODE
703 uint32_t NROM = 0;
704 const salsa20_blk_t *VROM = NULL;
705#endif
706 size_t s = 2 * r;
707 salsa20_blk_t *X = XY, *Y = &XY[s];
708 uint32_t i, j;
709
710 if (Nloop == 0)
711 return;
712
713 for (i = 0; i < 2 * r; i++) {
714 const salsa20_blk_t *src = (salsa20_blk_t *)&B[i * 64];
715 salsa20_blk_t *tmp = Y;
716 salsa20_blk_t *dst = &X[i];
717 size_t k;
718 for (k = 0; k < 16; k++)
719 tmp->w[k] = SWAP_LE32(src->w[k]);
720 salsa20_simd_shuffle(tmp, dst);
721 }
722
723 j = integerify(X, r) & (N - 1);
724
725/*
726 * Normally, VROM implies YESCRYPT_RW, but we check for these separately
727 * because our SMix resets YESCRYPT_RW for the smix2() calls operating on the
728 * entire V when p > 1.
729 */
730//and this is why bbox can't use flags___YESCRYPT_RW in this function
731 if (VROM && (flags & YESCRYPT_RW)) {
732 do {
733 salsa20_blk_t *V_j = &V[j * s];
734 const salsa20_blk_t *VROM_j;
735 j = blockmix_xor_save(X, V_j, r, ctx) & (NROM - 1);
736 VROM_j = &VROM[j * s];
737 j = blockmix_xor(X, VROM_j, X, r, ctx) & (N - 1);
738 } while (Nloop -= 2);
739 } else if (VROM) {
740 do {
741 const salsa20_blk_t *V_j = &V[j * s];
742 j = blockmix_xor(X, V_j, X, r, ctx) & (NROM - 1);
743 V_j = &VROM[j * s];
744 j = blockmix_xor(X, V_j, X, r, ctx) & (N - 1);
745 } while (Nloop -= 2);
746 } else if (flags & YESCRYPT_RW) {
747 do {
748 salsa20_blk_t *V_j = &V[j * s];
749 j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1);
750 V_j = &V[j * s];
751 j = blockmix_xor_save(X, V_j, r, ctx) & (N - 1);
752 } while (Nloop -= 2);
753 } else if (ctx) {
754 do {
755 const salsa20_blk_t *V_j = &V[j * s];
756 j = blockmix_xor(X, V_j, X, r, ctx) & (N - 1);
757 V_j = &V[j * s];
758 j = blockmix_xor(X, V_j, X, r, ctx) & (N - 1);
759 } while (Nloop -= 2);
760 } else {
761 do {
762 const salsa20_blk_t *V_j = &V[j * s];
763 j = blockmix_salsa8_xor(X, V_j, Y, r) & (N - 1);
764 V_j = &V[j * s];
765 j = blockmix_salsa8_xor(Y, V_j, X, r) & (N - 1);
766 } while (Nloop -= 2);
767 }
768
769 for (i = 0; i < 2 * r; i++) {
770 const salsa20_blk_t *src = &X[i];
771 salsa20_blk_t *tmp = Y;
772 salsa20_blk_t *dst = (salsa20_blk_t *)&B[i * 64];
773 size_t k;
774 for (k = 0; k < 16; k++)
775 tmp->w[k] = SWAP_LE32(src->w[k]);
776 salsa20_simd_unshuffle(tmp, dst);
777 }
778}
779
780/**
781 * p2floor(x):
782 * Largest power of 2 not greater than argument.
783 */
784static uint64_t p2floor(uint64_t x)
785{
786 uint64_t y;
787 while ((y = x & (x - 1)))
788 x = y;
789 return x;
790}
791
792/**
793 * smix(B, r, N, p, t, flags, V, NROM, VROM, XY, S, passwd):
794 * Compute B = SMix_r(B, N). The input B must be 128rp bytes in length; the
795 * temporary storage V must be 128rN bytes in length; the temporary storage
796 * XY must be 256r or 256rp bytes in length (the larger size is required with
797 * OpenMP-enabled builds). N must be a power of 2 and at least 4. The array V
798 * must be aligned to a multiple of 64 bytes, and arrays B and XY to a multiple
799 * of at least 16 bytes (aligning them to 64 bytes as well saves cache lines
800 * and helps avoid false sharing in OpenMP-enabled builds when p > 1, but it
801 * might also result in cache bank conflicts).
802 */
803#if DISABLE_NROM_CODE
804#define smix(B,r,N,p,t,flags,V,NROM,VROM,XY,S,passwd) \
805 smix(B,r,N,p,t,flags,V,XY,S,passwd)
806#endif
807static void smix(uint8_t *B, size_t r, uint32_t N, uint32_t p, uint32_t t,
808 uint32_t flags,
809 salsa20_blk_t *V,
810 uint32_t NROM, const salsa20_blk_t *VROM,
811 salsa20_blk_t *XY,
812 uint8_t *S, uint8_t *passwd)
813{
814 size_t s = 2 * r;
815 uint32_t Nchunk;
816 uint64_t Nloop_all, Nloop_rw;
817 uint32_t i;
818
819 Nchunk = N / p;
820 Nloop_all = Nchunk;
821 if (flags___YESCRYPT_RW) {
822 if (t <= 1) {
823 if (t)
824 Nloop_all *= 2; /* 2/3 */
825 Nloop_all = (Nloop_all + 2) / 3; /* 1/3, round up */
826 } else {
827 Nloop_all *= t - 1;
828 }
829 } else if (t) {
830 if (t == 1)
831 Nloop_all += (Nloop_all + 1) / 2; /* 1.5, round up */
832 Nloop_all *= t;
833 }
834
835 Nloop_rw = 0;
836 if (flags___YESCRYPT_RW)
837 Nloop_rw = Nloop_all / p;
838
839 Nchunk &= ~(uint32_t)1; /* round down to even */
840 Nloop_all++; Nloop_all &= ~(uint64_t)1; /* round up to even */
841 Nloop_rw++; Nloop_rw &= ~(uint64_t)1; /* round up to even */
842
843 for (i = 0; i < p; i++) {
844 uint32_t Vchunk = i * Nchunk;
845 uint32_t Np = (i < p - 1) ? Nchunk : (N - Vchunk);
846 uint8_t *Bp = &B[128 * r * i];
847 salsa20_blk_t *Vp = &V[Vchunk * s];
848 salsa20_blk_t *XYp = XY;
849 pwxform_ctx_t *ctx_i = NULL;
850 if (flags___YESCRYPT_RW) {
851 uint8_t *Si = S + i * Salloc;
852 smix1(Bp, 1, Sbytes / 128, 0 /* no flags */,
853 (salsa20_blk_t *)Si, 0, NULL, XYp, NULL);
854 ctx_i = (pwxform_ctx_t *)(Si + Sbytes);
855 ctx_i->S2 = Si;
856 ctx_i->S1 = Si + Sbytes / 3;
857 ctx_i->S0 = Si + Sbytes / 3 * 2;
858 ctx_i->w = 0;
859 if (i == 0)
860 hmac_block(
861 /* key,len: */ Bp + (128 * r - 64), 64,
862 /* hash fn: */ sha256_begin,
863 /* in,len: */ passwd, 32,
864 /* outbuf: */ passwd
865 );
866 }
867 smix1(Bp, r, Np, flags, Vp, NROM, VROM, XYp, ctx_i);
868 smix2(Bp, r, p2floor(Np), Nloop_rw, flags, Vp,
869 NROM, VROM, XYp, ctx_i);
870 }
871
872 if (Nloop_all > Nloop_rw) {
873 for (i = 0; i < p; i++) {
874 uint8_t *Bp = &B[128 * r * i];
875 salsa20_blk_t *XYp = XY;
876 pwxform_ctx_t *ctx_i = NULL;
877 if (flags___YESCRYPT_RW) {
878 uint8_t *Si = S + i * Salloc;
879 ctx_i = (pwxform_ctx_t *)(Si + Sbytes);
880 }
881 smix2(Bp, r, N, Nloop_all - Nloop_rw,
882 flags & (uint32_t)~YESCRYPT_RW,
883 V, NROM, VROM, XYp, ctx_i);
884 }
885 }
886}
887
888/* Allocator code */
889
890static void alloc_region(yescrypt_region_t *region, size_t size)
891{
892 uint8_t *base;
893 int flags =
894# ifdef MAP_NOCORE /* huh? */
895 MAP_NOCORE |
896# endif
897 MAP_ANON | MAP_PRIVATE;
898
899 base = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, -1, 0);
900 if (base == MAP_FAILED)
901 bb_die_memory_exhausted();
902
903#if defined(MADV_HUGEPAGE)
904 /* Reduces mkpasswd qweRTY123@-+ '$y$jHT$123'
905 * (which allocates 4 Gbytes)
906 * run time from 10.543s to 5.635s
907 * Seen on linux-5.18.0.
908 */
909 madvise(base, size, MADV_HUGEPAGE);
910#endif
911 //region->base = base;
912 //region->base_size = size;
913 region->aligned = base;
914 region->aligned_size = size;
915}
916
917static void free_region(yescrypt_region_t *region)
918{
919 if (region->aligned)
920 munmap(region->aligned, region->aligned_size);
921 //region->base = NULL;
922 //region->base_size = 0;
923 region->aligned = NULL;
924 region->aligned_size = 0;
925}
926/**
927 * yescrypt_kdf_body(shared, local, passwd, passwdlen, salt, saltlen,
928 * flags, N, r, p, t, NROM, buf, buflen):
929 * Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
930 * p, buflen), or a revision of scrypt as requested by flags and shared, and
931 * write the result into buf.
932 *
933 * shared and flags may request special modes as described in yescrypt.h.
934 *
935 * local is the thread-local data structure, allowing to preserve and reuse a
936 * memory allocation across calls, thereby reducing its overhead.
937 *
938 * t controls computation time while not affecting peak memory usage.
939 *
940 * Return 0 on success; or -1 on error.
941 *
942 * This optimized implementation currently limits N to the range from 4 to
943 * 2^31, but other implementations might not.
944 */
945static int yescrypt_kdf32_body(
946 yescrypt_ctx_t *yctx,
947 const uint8_t *passwd, size_t passwdlen,
948 uint32_t flags, uint64_t N, uint32_t t,
949 uint8_t *buf32)
950{
951#if !DISABLE_NROM_CODE
952 const salsa20_blk_t *VROM;
953#endif
954 size_t B_size, V_size, XY_size, need;
955 uint8_t *B, *S;
956 salsa20_blk_t *V, *XY;
957 struct {
958 uint8_t sha256[32];
959 uint8_t dk[32];
960 } u;
961#define sha256 u.sha256
962#define dk u.dk
963 uint8_t *dkp = buf32;
964 uint32_t r, p;
965
966 /* Sanity-check parameters */
967 switch (flags___YESCRYPT_MODE_MASK) {
968 case 0: /* classic scrypt - can't have anything non-standard */
969 if (flags || t || YCTX_param_NROM)
970 goto out_EINVAL;
971 break;
972 case YESCRYPT_WORM:
973 if (flags != YESCRYPT_WORM || YCTX_param_NROM)
974 goto out_EINVAL;
975 break;
976 case YESCRYPT_RW:
977 if (flags != (flags & YESCRYPT_KNOWN_FLAGS))
978 goto out_EINVAL;
979#if PWXsimple == 2 && PWXgather == 4 && Sbytes == 12288
980 if ((flags & YESCRYPT_RW_FLAVOR_MASK) ==
981 (YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 |
982 YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K))
983 break;
984#else
985#error "Unsupported pwxform settings"
986#endif
987 /* FALLTHRU */
988 default:
989 goto out_EINVAL;
990 }
991
992 r = YCTX_param_r;
993 p = YCTX_param_p;
994 if ((uint64_t)r * (uint64_t)p >= 1 << 30) {
995 dbg("r * n >= 2^30");
996 goto out_EINVAL;
997 }
998 if (N > UINT32_MAX) {
999 dbg("N > 0x%lx", (long)UINT32_MAX);
1000 goto out_EINVAL;
1001 }
1002 if (N <= 3
1003 || r < 1
1004 || p < 1
1005 ) {
1006 dbg("bad N, r or p");
1007 goto out_EINVAL;
1008 }
1009 if (r > SIZE_MAX / 256 / p
1010 || N > SIZE_MAX / 128 / r
1011 ) {
1012 /* 32-bit testcase: mkpasswd qweRTY123@-+ '$y$jHT$123'
1013 * (works on 64-bit, needs buffer > 4Gbytes)
1014 */
1015 dbg("r > SIZE_MAX / 256 / p? %c", "NY"[r > SIZE_MAX / 256 / p]);
1016 dbg("N > SIZE_MAX / 128 / r? %c", "NY"[N > SIZE_MAX / 128 / r]);
1017 goto out_EINVAL;
1018 }
1019 if (flags___YESCRYPT_RW) {
1020 /* p cannot be greater than SIZE_MAX/Salloc on 64-bit systems,
1021 but it can on 32-bit systems. */
1022#pragma GCC diagnostic push
1023#pragma GCC diagnostic ignored "-Wtype-limits"
1024 if (N / p <= 3 || p > SIZE_MAX / Salloc) {
1025 dbg("bad p:%ld", (long)p);
1026 goto out_EINVAL;
1027 }
1028#pragma GCC diagnostic pop
1029 }
1030
1031#if !DISABLE_NROM_CODE
1032 VROM = NULL;
1033 if (YCTX_param_NROM)
1034 goto out_EINVAL;
1035#endif
1036
1037 /* Allocate memory */
1038 V = NULL;
1039 V_size = (size_t)128 * r * N;
1040 need = V_size;
1041 B_size = (size_t)128 * r * p;
1042 need += B_size;
1043 if (need < B_size) {
1044 dbg("integer overflow at += B_size(%lu)", (long)B_size);
1045 goto out_EINVAL;
1046 }
1047 XY_size = (size_t)256 * r;
1048 need += XY_size;
1049 if (need < XY_size) {
1050 dbg("integer overflow at += XY_size(%lu)", (long)XY_size);
1051 goto out_EINVAL;
1052 }
1053 if (flags___YESCRYPT_RW) {
1054 size_t S_size = (size_t)Salloc * p;
1055 need += S_size;
1056 if (need < S_size) {
1057 dbg("integer overflow at += S_size(%lu)", (long)S_size);
1058 goto out_EINVAL;
1059 }
1060 }
1061 if (yctx->local->aligned_size < need) {
1062 free_region(yctx->local);
1063 alloc_region(yctx->local, need);
1064 dbg("allocated local:%lu 0x%lx", (long)need, (long)need);
1065 /* standard "j9T" params allocate 16Mbytes here */
1066 }
1067 if (flags & YESCRYPT_ALLOC_ONLY)
1068 return -3; /* expected "failure" */
1069 B = (uint8_t *)yctx->local->aligned;
1070 V = (salsa20_blk_t *)((uint8_t *)B + B_size);
1071 XY = (salsa20_blk_t *)((uint8_t *)V + V_size);
1072 S = NULL;
1073 if (flags___YESCRYPT_RW)
1074 S = (uint8_t *)XY + XY_size;
1075
1076 if (flags) {
1077 hmac_block(
1078 /* key,len: */ (const void*)"yescrypt-prehash", (flags & YESCRYPT_PREHASH) ? 16 : 8,
1079 /* hash fn: */ sha256_begin,
1080 /* in,len: */ passwd, passwdlen,
1081 /* outbuf: */ sha256
1082 );
1083 passwd = sha256;
1084 passwdlen = sizeof(sha256);
1085 }
1086
1087 PBKDF2_SHA256(passwd, passwdlen, yctx->salt, yctx->saltlen, 1, B, B_size);
1088
1089 if (flags)
1090 memcpy(sha256, B, sizeof(sha256));
1091
1092 if (p == 1 || (flags___YESCRYPT_RW)) {
1093 smix(B, r, N, p, t, flags, V, YCTX_param_NROM, VROM, XY, S, sha256);
1094 } else {
1095 uint32_t i;
1096 for (i = 0; i < p; i++) {
1097 smix(&B[(size_t)128 * r * i], r, N, 1, t, flags, V,
1098 YCTX_param_NROM, VROM, XY, NULL, NULL);
1099 }
1100 }
1101
1102 dkp = buf32;
1103 if (flags && /*buflen:*/32 < sizeof(dk)) {
1104 PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, dk, sizeof(dk));
1105 dkp = dk;
1106 }
1107
1108 PBKDF2_SHA256(passwd, passwdlen, B, B_size, 1, buf32, /*buflen:*/32);
1109
1110 /*
1111 * Except when computing classic scrypt, allow all computation so far
1112 * to be performed on the client. The final steps below match those of
1113 * SCRAM (RFC 5802), so that an extension of SCRAM (with the steps so
1114 * far in place of SCRAM's use of PBKDF2 and with SHA-256 in place of
1115 * SCRAM's use of SHA-1) would be usable with yescrypt hashes.
1116 */
1117 if (flags && !(flags & YESCRYPT_PREHASH)) {
1118 /* Compute ClientKey */
1119 hmac_block(
1120 /* key,len: */ dkp, sizeof(dk),
1121 /* hash fn: */ sha256_begin,
1122 /* in,len: */ "Client Key", 10,
1123 /* outbuf: */ sha256
1124 );
1125 /* Compute StoredKey */
1126 {
1127 size_t clen = /*buflen:*/32;
1128 if (clen > sizeof(dk))
1129 clen = sizeof(dk);
1130 if (sizeof(dk) != 32) { /* not true, optimize it out */
1131 sha256_block(sha256, sizeof(sha256), dk);
1132 memcpy(buf32, dk, clen);
1133 } else {
1134 sha256_block(sha256, sizeof(sha256), buf32);
1135 }
1136 }
1137 }
1138
1139 explicit_bzero(&u, sizeof(u));
1140
1141 /* Success! */
1142 return 0;
1143
1144 out_EINVAL:
1145 //bbox does not need this: errno = EINVAL;
1146 return -1;
1147#undef sha256
1148#undef dk
1149}
1150
1151/**
1152 * yescrypt_kdf(shared, local, passwd, passwdlen, salt, saltlen, params,
1153 * buf, buflen):
1154 * Compute scrypt or its revision as requested by the parameters. The inputs
1155 * to this function are the same as those for yescrypt_kdf_body() above, with
1156 * the addition of g, which controls hash upgrades (0 for no upgrades so far).
1157 */
1158static
1159int yescrypt_kdf32(
1160 yescrypt_ctx_t *yctx,
1161 const uint8_t *passwd, size_t passwdlen,
1162 uint8_t *buf32)
1163{
1164 uint32_t flags = YCTX_param_flags;
1165 uint64_t N = YCTX_param_N;
1166 uint32_t r = YCTX_param_r;
1167 uint32_t p = YCTX_param_p;
1168 uint32_t t = YCTX_param_t;
1169 uint32_t g = YCTX_param_g;
1170 uint8_t dk32[32];
1171 int retval;
1172
1173 /* Support for hash upgrades has been temporarily removed */
1174 if (g) {
1175 //bbox does not need this: errno = EINVAL;
1176 return -1;
1177 }
1178
1179 if ((flags___YESCRYPT_RW)
1180 && p >= 1
1181 && N / p >= 0x100
1182 && N / p * r >= 0x20000
1183 ) {
1184 if (yescrypt_kdf32_body(yctx,
1185 passwd, passwdlen,
1186 flags | YESCRYPT_ALLOC_ONLY, N, t,
1187 buf32) != -3
1188 ) {
1189 dbg("yescrypt_kdf32_body: not -3");
1190 return -1;
1191 }
1192 retval = yescrypt_kdf32_body(yctx,
1193 passwd, passwdlen,
1194 flags | YESCRYPT_PREHASH, N >> 6, 0,
1195 dk32);
1196 if (retval) {
1197 dbg("yescrypt_kdf32_body(PREHASH):%d", retval);
1198 return retval;
1199 }
1200 passwd = dk32;
1201 passwdlen = sizeof(dk32);
1202 }
1203
1204 retval = yescrypt_kdf32_body(yctx,
1205 passwd, passwdlen,
1206 flags, N, t, buf32);
1207
1208 explicit_bzero(dk32, sizeof(dk32));
1209
1210 dbg("yescrypt_kdf32_body:%d", retval);
1211 return retval;
1212}
diff --git a/libbb/yescrypt/alg-yescrypt.h b/libbb/yescrypt/alg-yescrypt.h
new file mode 100644
index 000000000..b69843f5d
--- /dev/null
+++ b/libbb/yescrypt/alg-yescrypt.h
@@ -0,0 +1,247 @@
1/*-
2 * Copyright 2009 Colin Percival
3 * Copyright 2013-2018 Alexander Peslyak
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * This file was originally written by Colin Percival as part of the Tarsnap
28 * online backup system.
29 */
30
31// busybox debug and size-reduction configuration
32
33#ifdef YESCRYPT_INTERNAL
34# if 1
35# define dbg(...) ((void)0)
36# else
37# define dbg(...) bb_error_msg(__VA_ARGS__)
38# endif
39# if 1
40# define dbg_dec64(...) ((void)0)
41# else
42# define dbg_dec64(...) bb_error_msg(__VA_ARGS__)
43# endif
44# define TEST_DECODE64 0
45#endif
46
47// Only accept one-char parameters in salt, and only first three?
48// Almost any reasonable yescrypt hashes in /etc/shadow should
49// only ever use "jXY" parameters which set N and r.
50// Fancy multi-byte-encoded wide integers are not needed for that.
51#define RESTRICTED_PARAMS 1
52// Note: if you enable the above, please also enable
53// YCTX_param_p, YCTX_param_t, YCTX_param_g, YCTX_param_NROM
54// optimizations, and DISABLE_NROM_CODE.
55
56#define DISABLE_NROM_CODE 1
57
58// How much we save by forcing "standard" value by commenting the next line:
59// 160 bytes
60//#define YCTX_param_flags yctx->param.flags
61// 260 bytes
62//#define flags___YESCRYPT_RW (flags & YESCRYPT_RW)
63// 140 bytes
64//#define flags___YESCRYPT_MODE_MASK (flags & YESCRYPT_MODE_MASK)
65// ^^^^ forcing the above since the code already requires (checks for) this
66// 50 bytes
67#define YCTX_param_N yctx->param.N
68// -100 bytes (negative!!!)
69#define YCTX_param_r yctx->param.r
70// 400 bytes
71//#define YCTX_param_p yctx->param.p
72// 130 bytes
73//#define YCTX_param_t yctx->param.t
74// 2 bytes
75//#define YCTX_param_g yctx->param.g
76// 1 bytes
77// ^^^^ this looks wrong, compiler should be able to constant-propagate the fact that NROM code is dead
78//#define YCTX_param_NROM yctx->param.NROM
79
80#ifndef YCTX_param_flags
81#define YCTX_param_flags (YESCRYPT_RW | YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | YESCRYPT_SBOX_12K)
82#endif
83#ifndef flags___YESCRYPT_RW
84#define flags___YESCRYPT_RW ((void)flags, YESCRYPT_RW)
85#endif
86#ifndef flags___YESCRYPT_MODE_MASK
87#define flags___YESCRYPT_MODE_MASK ((void)flags, YESCRYPT_RW)
88#endif
89// standard ("j9T") values:
90#ifndef YCTX_param_N
91#define YCTX_param_N 4096
92#endif
93#ifndef YCTX_param_r
94#define YCTX_param_r 32
95#endif
96#ifndef YCTX_param_p
97#define YCTX_param_p 1
98#endif
99#ifndef YCTX_param_t
100#define YCTX_param_t 0
101#endif
102#ifndef YCTX_param_g
103#define YCTX_param_g 0
104#endif
105#ifndef YCTX_param_NROM
106#define YCTX_param_NROM 0
107#endif
108
109// "Faster/smaller code" knobs:
110// -941 bytes:
111#define KDF_UNROLL_COPY 0
112// -5324 bytes if 0:
113#define KDF_UNROLL_PWXFORM_ROUND 0
114// -4864 bytes if 0:
115#define KDF_UNROLL_PWXFORM 0
116// if both this ^^^^^^^^^^ and PWXFORM_ROUND set to 0: -7666 bytes
117// -464 bytes:
118#define KDF_UNROLL_SALSA20 0
119
120/**
121 * Type and possible values for the flags argument of yescrypt_kdf(),
122 * yescrypt_encode_params_r(), yescrypt_encode_params(). Most of these may be
123 * OR'ed together, except that YESCRYPT_WORM stands on its own.
124 * Please refer to the description of yescrypt_kdf() below for the meaning of
125 * these flags.
126 */
127/* yescrypt flags:
128 * bits pos: 7654321076543210
129 * ss r w
130 * sbox gg y
131 */
132/* Public */
133#define YESCRYPT_WORM 1
134#define YESCRYPT_RW 0x002
135#define YESCRYPT_ROUNDS_3 0x000 //r=0
136#define YESCRYPT_ROUNDS_6 0x004 //r=1
137#define YESCRYPT_GATHER_1 0x000 //gg=00
138#define YESCRYPT_GATHER_2 0x008 //gg=01
139#define YESCRYPT_GATHER_4 0x010 //gg=10
140#define YESCRYPT_GATHER_8 0x018 //gg=11
141#define YESCRYPT_SIMPLE_1 0x000 //ss=00
142#define YESCRYPT_SIMPLE_2 0x020 //ss=01
143#define YESCRYPT_SIMPLE_4 0x040 //ss=10
144#define YESCRYPT_SIMPLE_8 0x060 //ss=11
145#define YESCRYPT_SBOX_6K 0x000 //sbox=0000
146#define YESCRYPT_SBOX_12K 0x080 //sbox=0001
147#define YESCRYPT_SBOX_24K 0x100 //sbox=0010
148#define YESCRYPT_SBOX_48K 0x180 //sbox=0011
149#define YESCRYPT_SBOX_96K 0x200 //sbox=0100
150#define YESCRYPT_SBOX_192K 0x280 //sbox=0101
151#define YESCRYPT_SBOX_384K 0x300 //sbox=0110
152#define YESCRYPT_SBOX_768K 0x380 //sbox=0111
153
154#ifdef YESCRYPT_INTERNAL
155/* Private */
156#define YESCRYPT_MODE_MASK 0x003
157#define YESCRYPT_RW_FLAVOR_MASK 0x3fc
158#define YESCRYPT_ALLOC_ONLY 0x08000000
159#define YESCRYPT_PREHASH 0x10000000
160#endif
161
162#define YESCRYPT_RW_DEFAULTS \
163 (YESCRYPT_RW | \
164 YESCRYPT_ROUNDS_6 | YESCRYPT_GATHER_4 | YESCRYPT_SIMPLE_2 | \
165 YESCRYPT_SBOX_12K)
166
167#define YESCRYPT_DEFAULTS YESCRYPT_RW_DEFAULTS
168
169#ifdef YESCRYPT_INTERNAL
170#define YESCRYPT_KNOWN_FLAGS \
171 (YESCRYPT_MODE_MASK | YESCRYPT_RW_FLAVOR_MASK | \
172 YESCRYPT_ALLOC_ONLY | YESCRYPT_PREHASH)
173#endif
174
175/* How many chars base-64 encoded bytes require? */
176#define YESCRYPT_BYTES2CHARS(bytes) ((((bytes) * 8) + 5) / 6)
177/* The /etc/passwd-style hash is "<prefix>$<hash><NUL>" */
178/*
179 * "$y$", up to 8 params of up to 6 chars each, '$', salt
180 * Alternatively, but that's smaller:
181 * "$7$", 3 params encoded as 1+5+5 chars, salt
182 */
183#define YESCRYPT_PREFIX_LEN (3 + 8 * 6 + 1 + YESCRYPT_BYTES2CHARS(32))
184
185#define YESCRYPT_HASH_SIZE 32
186#define YESCRYPT_HASH_LEN YESCRYPT_BYTES2CHARS(YESCRYPT_HASH_SIZE)
187
188/**
189 * Internal type used by the memory allocator. Please do not use it directly.
190 * Use yescrypt_shared_t and yescrypt_local_t as appropriate instead, since
191 * they might differ from each other in a future version.
192 */
193typedef struct {
194// void *base;
195 void *aligned;
196// size_t base_size;
197 size_t aligned_size;
198} yescrypt_region_t;
199
200/**
201 * yescrypt parameters combined into one struct. N, r, p are the same as in
202 * classic scrypt, except that the meaning of p changes when YESCRYPT_RW is
203 * set. flags, t, g, NROM are special to yescrypt.
204 */
205typedef struct {
206 uint32_t flags;
207 uint32_t r;
208 uint64_t N;
209#if !RESTRICTED_PARAMS
210 uint32_t p, t, g;
211 uint64_t NROM;
212#endif
213} yescrypt_params_t;
214
215typedef struct {
216 yescrypt_params_t param;
217
218 /* salt in binary form */
219 /* stored here to cut down on the amount of function paramaters */
220 unsigned char salt[64];
221 size_t saltlen;
222
223 /* used by the memory allocator */
224 //yescrypt_region_t shared[1];
225 yescrypt_region_t local[1];
226} yescrypt_ctx_t;
227
228/**
229 * yescrypt_r(shared, local, passwd, passwdlen, setting, key, buf, buflen):
230 * Compute and encode an scrypt or enhanced scrypt hash of passwd given the
231 * parameters and salt value encoded in setting. If shared is not NULL, a ROM
232 * is used and YESCRYPT_RW is required. Otherwise, whether to compute classic
233 * scrypt, YESCRYPT_WORM (a slight deviation from classic scrypt), or
234 * YESCRYPT_RW (time-memory tradeoff discouraging modification) is determined
235 * by the setting string. shared (if not NULL) and local must be initialized
236 * as described above for yescrypt_kdf(). buf must be large enough (as
237 * indicated by buflen) to hold the encoded hash string.
238 *
239 * Return the encoded hash string on success; or NULL on error.
240 *
241 * MT-safe as long as local and buf are local to the thread.
242 */
243extern char *yescrypt_r(
244 const uint8_t *passwd, size_t passwdlen,
245 const uint8_t *setting,
246 char *buf, size_t buflen
247);
diff --git a/libbb/yescrypt/y.c b/libbb/yescrypt/y.c
new file mode 100644
index 000000000..d5ab8903f
--- /dev/null
+++ b/libbb/yescrypt/y.c
@@ -0,0 +1,16 @@
1/*
2 * The compilation unit for yescrypt-related code.
3 *
4 * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com>
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8//kbuild:lib-$(CONFIG_USE_BB_CRYPT_YES) += y.o
9
10#include "libbb.h"
11
12#define YESCRYPT_INTERNAL
13#include "alg-yescrypt.h"
14#include "alg-sha256.c"
15#include "alg-yescrypt-kdf.c"
16#include "alg-yescrypt-common.c"
diff --git a/loginutils/Config.src b/loginutils/Config.src
index cbb09646b..a7812bd32 100644
--- a/loginutils/Config.src
+++ b/loginutils/Config.src
@@ -91,6 +91,17 @@ config USE_BB_CRYPT_SHA
91 With this option off, login will fail password check for any 91 With this option off, login will fail password check for any
92 user which has password encrypted with these algorithms. 92 user which has password encrypted with these algorithms.
93 93
94config USE_BB_CRYPT_YES
95 bool "Enable yescrypt functions"
96 default y
97 depends on USE_BB_CRYPT
98 help
99 Enable this if you have passwords starting with "$y$" or
100 in your /etc/passwd or /etc/shadow files. These passwords
101 are hashed using yescrypt algorithms.
102 With this option off, login will fail password check for any
103 user which has password encrypted with these algorithms.
104
94INSERT 105INSERT
95 106
96endmenu 107endmenu
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c
index 65530b614..353f19961 100644
--- a/loginutils/chpasswd.c
+++ b/loginutils/chpasswd.c
@@ -17,7 +17,7 @@
17//config: default "des" 17//config: default "des"
18//config: depends on PASSWD || CRYPTPW || CHPASSWD 18//config: depends on PASSWD || CRYPTPW || CHPASSWD
19//config: help 19//config: help
20//config: Possible choices are "d[es]", "m[d5]", "s[ha256]" or "sha512". 20//config: Possible choices: "d[es]", "m[d5]", "s[ha256]", "sha512", "yescrypt"
21 21
22//applet:IF_CHPASSWD(APPLET(chpasswd, BB_DIR_USR_SBIN, BB_SUID_DROP)) 22//applet:IF_CHPASSWD(APPLET(chpasswd, BB_DIR_USR_SBIN, BB_SUID_DROP))
23 23
diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c
index 1c338540f..666deff0b 100644
--- a/loginutils/cryptpw.c
+++ b/loginutils/cryptpw.c
@@ -84,8 +84,7 @@ to cryptpw. -a option (alias for -m) came from cryptpw.
84int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 84int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
85int cryptpw_main(int argc UNUSED_PARAM, char **argv) 85int cryptpw_main(int argc UNUSED_PARAM, char **argv)
86{ 86{
87 /* Supports: cryptpw -m sha256 PASS 'rounds=999999999$SALT' */ 87 char salt[MAX_PW_SALT_LEN];
88 char salt[MAX_PW_SALT_LEN + sizeof("rounds=999999999$")];
89 char *salt_ptr; 88 char *salt_ptr;
90 char *password; 89 char *password;
91 const char *opt_m, *opt_S; 90 const char *opt_m, *opt_S;
@@ -100,7 +99,7 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv)
100 ; 99 ;
101#endif 100#endif
102 fd = STDIN_FILENO; 101 fd = STDIN_FILENO;
103 opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; 102 opt_m = NULL;
104 opt_S = NULL; 103 opt_S = NULL;
105 /* at most two non-option arguments; -P NUM */ 104 /* at most two non-option arguments; -P NUM */
106 getopt32long(argv, "^" "sP:+S:m:a:" "\0" "?2", 105 getopt32long(argv, "^" "sP:+S:m:a:" "\0" "?2",
@@ -114,10 +113,34 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv)
114 if (argv[0] && !opt_S) 113 if (argv[0] && !opt_S)
115 opt_S = argv[1]; 114 opt_S = argv[1];
116 115
117 salt_ptr = crypt_make_pw_salt(salt, opt_m); 116 if (opt_S && !opt_S[0]) {
118 if (opt_S) 117 /* mkpasswd 5.6.2 compat: SALT of ""
119 /* put user's data after the "$N$" prefix */ 118 * is treated as not specified
120 safe_strncpy(salt_ptr, opt_S, sizeof(salt) - (sizeof("$N$")-1)); 119 * (both forms: -S "" and argv[1] of "")
120 */
121 opt_S = NULL;
122 }
123
124 if (opt_m) {
125 /* "cryptpw -m ALGO PASSWORD [SALT]" */
126 /* generate "$x$" algo prefix + random salt */
127 salt_ptr = crypt_make_pw_salt(salt, opt_m);
128 if (opt_S) {
129 /* "cryptpw -m ALGO PASSWORD SALT" */
130 /* put SALT data after the "$x$" prefix */
131 safe_strncpy(salt_ptr, opt_S, sizeof(salt) - (sizeof("$N$")-1));
132 }
133 } else {
134 if (!opt_S) {
135 /* "cryptpw PASSWORD" */
136 /* generate random salt with default algo */
137 crypt_make_pw_salt(salt, CONFIG_FEATURE_DEFAULT_PASSWD_ALGO);
138 } else {
139 /* "cryptpw PASSWORD '$x$SALT'" */
140 /* use given salt; algo will be detected by pw_encrypt() */
141 safe_strncpy(salt, opt_S, sizeof(salt));
142 }
143 }
121 144
122 xmove_fd(fd, STDIN_FILENO); 145 xmove_fd(fd, STDIN_FILENO);
123 146
diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c
index 9c927ed79..984889915 100644
--- a/loginutils/sulogin.c
+++ b/loginutils/sulogin.c
@@ -79,7 +79,7 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv)
79 break; 79 break;
80 } 80 }
81 pause_after_failed_login(); 81 pause_after_failed_login();
82 bb_simple_info_msg("Login incorrect"); 82 bb_simple_error_msg("Login incorrect");
83 } 83 }
84 84
85 /* util-linux 2.36.1 compat: no message */ 85 /* util-linux 2.36.1 compat: no message */
@@ -119,9 +119,12 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv)
119 } 119 }
120 120
121 /* 121 /*
122 * Note: login does this (should we do it too?): 122 * Note: login does this. util-linux's sulogin does NOT.
123 * But it's rather unpleasant to have non-functioning ^C in a shell,
124 * and surprisingly, there is no easy way to remove SIG_IGN from ^C
125 * in the shell. So, we are doing it:
123 */ 126 */
124 /*signal(SIGINT, SIG_DFL);*/ 127 signal(SIGINT, SIG_DFL);
125 128
126 /* Exec shell with no additional parameters. Never returns. */ 129 /* Exec shell with no additional parameters. Never returns. */
127 exec_shell(shell, /* -p? then shell is login:*/(opts & 1), NULL); 130 exec_shell(shell, /* -p? then shell is login:*/(opts & 1), NULL);
diff --git a/loginutils/suw32.c b/loginutils/suw32.c
index b3976dcfd..77c038582 100644
--- a/loginutils/suw32.c
+++ b/loginutils/suw32.c
@@ -48,8 +48,8 @@ int suw32_main(int argc UNUSED_PARAM, char **argv)
48 char *opt_command = NULL; 48 char *opt_command = NULL;
49 char *opt_shell = NULL; 49 char *opt_shell = NULL;
50 SHELLEXECUTEINFO info; 50 SHELLEXECUTEINFO info;
51 char *bb_path, *cwd, *realcwd, *q, *args; 51 const char *bb_path;
52 DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *); 52 char *cwd, *realcwd, *q, *args;
53 53
54 opt = getopt32(argv, "^c:s:tNW" "\0" "s--N:N--s", &opt_command, &opt_shell); 54 opt = getopt32(argv, "^c:s:tNW" "\0" "s--N:N--s", &opt_command, &opt_shell);
55 argv += optind; 55 argv += optind;
@@ -70,19 +70,17 @@ int suw32_main(int argc UNUSED_PARAM, char **argv)
70 } 70 }
71#endif 71#endif
72 72
73 /* ShellExecuteEx() needs backslash as separator in UNC paths. */
74 if (opt_shell) { 73 if (opt_shell) {
75 bb_path = file_is_win32_exe(opt_shell); 74 bb_path = file_is_win32_exe(opt_shell);
76 if (!bb_path) 75 if (!bb_path)
77 bb_error_msg_and_die("%s: Not found", opt_shell); 76 bb_error_msg_and_die("%s: Not found", opt_shell);
78 args = NULL; 77 args = NULL;
79 } else { 78 } else {
80 bb_path = xstrdup(bb_busybox_exec_path); 79 bb_path = bb_busybox_exec_path;
81 args = xstrdup("--busybox ash"); 80 args = xstrdup("--busybox ash");
82 if (!test_mode) 81 if (!test_mode)
83 args = xappendword(args, "-t \"BusyBox ash (Admin)\""); 82 args = xappendword(args, "-t \"BusyBox ash (Admin)\"");
84 } 83 }
85 slash_to_bs(bb_path);
86 84
87 memset(&info, 0, sizeof(SHELLEXECUTEINFO)); 85 memset(&info, 0, sizeof(SHELLEXECUTEINFO));
88 info.cbSize = sizeof(SHELLEXECUTEINFO); 86 info.cbSize = sizeof(SHELLEXECUTEINFO);
@@ -137,12 +135,7 @@ int suw32_main(int argc UNUSED_PARAM, char **argv)
137 /* info.lpDirectory = NULL; */ 135 /* info.lpDirectory = NULL; */
138 info.nShow = SW_SHOWNORMAL; 136 info.nShow = SW_SHOWNORMAL;
139 137
140 if (!INIT_PROC_ADDR(shell32.dll, ShellExecuteExA)) { 138 if (!mingw_shell_execute(&info)) {
141 ret = -1;
142 goto end;
143 }
144
145 if (!ShellExecuteExA(&info)) {
146 ret = 1; 139 ret = 1;
147 goto end; 140 goto end;
148 } 141 }
@@ -159,7 +152,8 @@ int suw32_main(int argc UNUSED_PARAM, char **argv)
159 } 152 }
160 end: 153 end:
161 if (ENABLE_FEATURE_CLEAN_UP) { 154 if (ENABLE_FEATURE_CLEAN_UP) {
162 free(bb_path); 155 if (bb_path != bb_busybox_exec_path)
156 free((void *)bb_path);
163 free(cwd); 157 free(cwd);
164 free(realcwd); 158 free(realcwd);
165 free(args); 159 free(args);
diff --git a/miscutils/crond.c b/miscutils/crond.c
index b3762d327..96131cae4 100644
--- a/miscutils/crond.c
+++ b/miscutils/crond.c
@@ -177,7 +177,7 @@ static void crondlog(unsigned level, const char *msg, va_list va)
177{ 177{
178 if (level >= G.log_level) { 178 if (level >= G.log_level) {
179 /* 179 /*
180 * We are called only for info meesages. 180 * We are called only for info messages.
181 * Warnings/errors use plain bb_[p]error_msg's, which 181 * Warnings/errors use plain bb_[p]error_msg's, which
182 * need not touch syslog_level 182 * need not touch syslog_level
183 * (they are ok with LOG_ERR default). 183 * (they are ok with LOG_ERR default).
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index 2934d8eb7..912a501a3 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -382,7 +382,7 @@ static void fb_drawimage(void)
382 if (LONE_DASH(G.image_filename)) { 382 if (LONE_DASH(G.image_filename)) {
383 theme_file = stdin; 383 theme_file = stdin;
384 } else { 384 } else {
385 int fd = open_zipped(G.image_filename, /*fail_if_not_compressed:*/ 0); 385 int fd = open_zipped(G.image_filename, /*die_if_not_compressed:*/ 0);
386 if (fd < 0) 386 if (fd < 0)
387 bb_simple_perror_msg_and_die(G.image_filename); 387 bb_simple_perror_msg_and_die(G.image_filename);
388 theme_file = xfdopen_for_read(fd); 388 theme_file = xfdopen_for_read(fd);
diff --git a/miscutils/less.c b/miscutils/less.c
index 467c76e2a..5a8fc5a74 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -1178,7 +1178,7 @@ static int64_t getch_nowait(void)
1178 1178
1179 /* We have kbd_fd in O_NONBLOCK mode, read inside safe_read_key() 1179 /* We have kbd_fd in O_NONBLOCK mode, read inside safe_read_key()
1180 * would not block even if there is no input available */ 1180 * would not block even if there is no input available */
1181 key64 = safe_read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); 1181 key64 = safe_read_key(kbd_fd, kbd_input, /*do not poll:*/ -2);
1182 if ((int)key64 == -1) { 1182 if ((int)key64 == -1) {
1183 if (errno == EAGAIN) { 1183 if (errno == EAGAIN) {
1184 /* No keyboard input available. Since poll() did return, 1184 /* No keyboard input available. Since poll() did return,
diff --git a/miscutils/make.c b/miscutils/make.c
index 7316408bf..a165274aa 100644
--- a/miscutils/make.c
+++ b/miscutils/make.c
@@ -257,6 +257,11 @@ enum {
257#define MAKE_FAILURE 0x01 257#define MAKE_FAILURE 0x01
258#define MAKE_DIDSOMETHING 0x02 258#define MAKE_DIDSOMETHING 0x02
259 259
260// Return TRUE if c is allowed in a POSIX 2017 macro or target name
261#define ispname(c) (isalpha(c) || isdigit(c) || c == '.' || c == '_')
262// Return TRUE if c is in the POSIX 'portable filename character set'
263#define isfname(c) (ispname(c) || c == '-')
264
260#define HTABSIZE 39 265#define HTABSIZE 39
261 266
262struct globals { 267struct globals {
@@ -320,11 +325,8 @@ struct globals {
320#endif 325#endif
321 326
322static int make(struct name *np, int level); 327static int make(struct name *np, int level);
323 328static struct name *dyndep(struct name *np, struct rule *infrule,
324// Return TRUE if c is allowed in a POSIX 2017 macro or target name 329 const char **ptsuff);
325#define ispname(c) (isalpha(c) || isdigit(c) || c == '.' || c == '_')
326// Return TRUE if c is in the POSIX 'portable filename character set'
327#define isfname(c) (ispname(c) || c == '-')
328 330
329/* 331/*
330 * Utility functions. 332 * Utility functions.
@@ -469,8 +471,7 @@ newcmd(struct cmd **cphead, char *str)
469 /*(*cphead)->c_next = NULL; - xzalloc did it */ 471 /*(*cphead)->c_next = NULL; - xzalloc did it */
470 (*cphead)->c_cmd = xstrdup(str); 472 (*cphead)->c_cmd = xstrdup(str);
471 /*(*cphead)->c_refcnt = 0; */ 473 /*(*cphead)->c_refcnt = 0; */
472 if (makefile) 474 (*cphead)->c_makefile = xstrdup(makefile);
473 (*cphead)->c_makefile = xstrdup(makefile);
474 (*cphead)->c_dispno = dispno; 475 (*cphead)->c_dispno = dispno;
475} 476}
476 477
@@ -993,38 +994,27 @@ suffix(const char *name)
993} 994}
994 995
995/* 996/*
996 * Dynamic dependency. This routine applies the suffix rules 997 * Search for an inference rule to convert some suffix ('psuff')
997 * to try and find a source and a set of rules for a missing 998 * to the target suffix 'tsuff'. The basename of the prerequisite
998 * target. NULL is returned on failure. On success the name of 999 * is 'base'.
999 * the implicit prerequisite is returned and the details are
1000 * placed in the imprule structure provided by the caller.
1001 */ 1000 */
1002static struct name * 1001static struct name *
1003dyndep(struct name *np, struct rule *imprule) 1002dyndep0(char *base, const char *tsuff, struct rule *infrule)
1004{ 1003{
1005 char *suff, *newsuff; 1004 char *psuff;
1006 char *base, *name, *member;
1007 struct name *xp; // Suffixes 1005 struct name *xp; // Suffixes
1008 struct name *sp; // Suffix rule 1006 struct name *sp; // Suffix rule
1009 struct name *pp = NULL; // Implicit prerequisite
1010 struct rule *rp; 1007 struct rule *rp;
1011 struct depend *dp; 1008 struct depend *dp;
1012 bool chain = FALSE; 1009 bool chain = FALSE;
1013 1010
1014 member = NULL;
1015 name = splitlib(np->n_name, &member);
1016
1017 suff = xstrdup(suffix(name));
1018 base = member ? member : name;
1019 *suffix(base) = '\0';
1020
1021 xp = newname(".SUFFIXES"); 1011 xp = newname(".SUFFIXES");
1022 retry: 1012 retry:
1023 for (rp = xp->n_rule; rp; rp = rp->r_next) { 1013 for (rp = xp->n_rule; rp; rp = rp->r_next) {
1024 for (dp = rp->r_dep; dp; dp = dp->d_next) { 1014 for (dp = rp->r_dep; dp; dp = dp->d_next) {
1025 // Generate new suffix rule to try 1015 // Generate new suffix rule to try
1026 newsuff = dp->d_name->n_name; 1016 psuff = dp->d_name->n_name;
1027 sp = findname(auto_concat(newsuff, suff)); 1017 sp = findname(auto_concat(psuff, tsuff));
1028 if (sp && sp->n_rule) { 1018 if (sp && sp->n_rule) {
1029 struct name *ip; 1019 struct name *ip;
1030 int got_ip; 1020 int got_ip;
@@ -1032,9 +1022,8 @@ dyndep(struct name *np, struct rule *imprule)
1032 // Has rule already been used in this chain? 1022 // Has rule already been used in this chain?
1033 if ((sp->n_flag & N_MARK)) 1023 if ((sp->n_flag & N_MARK))
1034 continue; 1024 continue;
1035
1036 // Generate a name for an implicit prerequisite 1025 // Generate a name for an implicit prerequisite
1037 ip = newname(auto_concat(base, newsuff)); 1026 ip = newname(auto_concat(base, psuff));
1038 if ((ip->n_flag & N_DOING)) 1027 if ((ip->n_flag & N_DOING))
1039 continue; 1028 continue;
1040 1029
@@ -1045,20 +1034,19 @@ dyndep(struct name *np, struct rule *imprule)
1045 got_ip = ip->n_tim.tv_sec || (ip->n_flag & N_TARGET); 1034 got_ip = ip->n_tim.tv_sec || (ip->n_flag & N_TARGET);
1046 } else { 1035 } else {
1047 sp->n_flag |= N_MARK; 1036 sp->n_flag |= N_MARK;
1048 got_ip = dyndep(ip, NULL) != NULL; 1037 got_ip = dyndep(ip, NULL, NULL) != NULL;
1049 sp->n_flag &= ~N_MARK; 1038 sp->n_flag &= ~N_MARK;
1050 } 1039 }
1051 1040
1052 if (got_ip) { 1041 if (got_ip) {
1053 // Prerequisite exists or we know how to make it 1042 // Prerequisite exists or we know how to make it
1054 if (imprule) { 1043 if (infrule) {
1055 dp = NULL; 1044 dp = NULL;
1056 newdep(&dp, ip); 1045 newdep(&dp, ip);
1057 imprule->r_dep = dp; 1046 infrule->r_dep = dp;
1058 imprule->r_cmd = sp->n_rule->r_cmd; 1047 infrule->r_cmd = sp->n_rule->r_cmd;
1059 } 1048 }
1060 pp = ip; 1049 return ip;
1061 goto finish;
1062 } 1050 }
1063 } 1051 }
1064 } 1052 }
@@ -1069,9 +1057,87 @@ dyndep(struct name *np, struct rule *imprule)
1069 chain = TRUE; 1057 chain = TRUE;
1070 goto retry; 1058 goto retry;
1071 } 1059 }
1072 finish: 1060 return NULL;
1073 free(suff); 1061}
1062
1063/*
1064 * If 'name' ends with 'suffix' return an allocated string containing
1065 * the name with the suffix removed, else return NULL.
1066 */
1067static char *
1068has_suffix(const char *name, const char *suffix)
1069{
1070 ssize_t delta = strlen(name) - strlen(suffix);
1071 char *base = NULL;
1072
1073 if (delta > 0 && strcmp(name + delta, suffix) == 0) {
1074 base = xstrdup(name);
1075 base[delta] = '\0';
1076 }
1077
1078 return base;
1079}
1080
1081/*
1082 * Dynamic dependency. This routine applies the suffix rules
1083 * to try and find a source and a set of rules for a missing
1084 * target. NULL is returned on failure. On success the name of
1085 * the implicit prerequisite is returned and the rule used is
1086 * placed in the infrule structure provided by the caller.
1087 */
1088static struct name *
1089dyndep(struct name *np, struct rule *infrule, const char **ptsuff)
1090{
1091 const char *tsuff;
1092 char *base, *name, *member;
1093 struct name *pp = NULL; // Implicit prerequisite
1094
1095 member = NULL;
1096 name = splitlib(np->n_name, &member);
1097
1098 // POSIX only allows inference rules with one or two periods.
1099 // As an extension this restriction is lifted, but not for
1100 // targets of the form lib.a(member.o).
1101 if (!posix && member == NULL) {
1102 struct name *xp = newname(".SUFFIXES");
1103 int found_suffix = FALSE;
1104
1105 for (struct rule *rp = xp->n_rule; rp; rp = rp->r_next) {
1106 for (struct depend *dp = rp->r_dep; dp; dp = dp->d_next) {
1107 tsuff = dp->d_name->n_name;
1108 base = has_suffix(name, tsuff);
1109 if (base) {
1110 found_suffix = TRUE;
1111 pp = dyndep0(base, tsuff, infrule);
1112 free(base);
1113 if (pp) {
1114 goto done;
1115 }
1116 }
1117 }
1118 }
1119
1120 if (!found_suffix) {
1121 // The name didn't have a known suffix. Try single-suffix rule.
1122 tsuff = "";
1123 pp = dyndep0(name, tsuff, infrule);
1124 if (pp) {
1125 done:
1126 if (ptsuff) {
1127 *ptsuff = tsuff;
1128 }
1129 }
1130 }
1131 } else {
1132 tsuff = xstrdup(suffix(name));
1133 base = member ? member : name;
1134 *suffix(base) = '\0';
1135
1136 pp = dyndep0(base, tsuff, infrule);
1137 free((void *)tsuff);
1138 }
1074 free(name); 1139 free(name);
1140
1075 return pp; 1141 return pp;
1076} 1142}
1077 1143
@@ -1789,9 +1855,10 @@ readline(FILE *fd, int want_command)
1789} 1855}
1790 1856
1791/* 1857/*
1792 * Return TRUE if the argument is a known suffix. 1858 * Return a pointer to the suffix name if the argument is a known suffix
1859 * or NULL if it isn't.
1793 */ 1860 */
1794static int 1861static const char *
1795is_suffix(const char *s) 1862is_suffix(const char *s)
1796{ 1863{
1797 struct name *np; 1864 struct name *np;
@@ -1802,7 +1869,39 @@ is_suffix(const char *s)
1802 for (rp = np->n_rule; rp; rp = rp->r_next) { 1869 for (rp = np->n_rule; rp; rp = rp->r_next) {
1803 for (dp = rp->r_dep; dp; dp = dp->d_next) { 1870 for (dp = rp->r_dep; dp; dp = dp->d_next) {
1804 if (strcmp(s, dp->d_name->n_name) == 0) { 1871 if (strcmp(s, dp->d_name->n_name) == 0) {
1805 return TRUE; 1872 return dp->d_name->n_name;
1873 }
1874 }
1875 }
1876 return NULL;
1877}
1878
1879/*
1880 * Return TRUE if the argument is formed by concatenating two
1881 * known suffixes.
1882 */
1883static int
1884is_inference_target(const char *s)
1885{
1886 struct name *np;
1887 struct rule *rp1, *rp2;
1888 struct depend *dp1, *dp2;
1889
1890 np = newname(".SUFFIXES");
1891 for (rp1 = np->n_rule; rp1; rp1 = rp1->r_next) {
1892 for (dp1 = rp1->r_dep; dp1; dp1 = dp1->d_next) {
1893 const char *suff1 = dp1->d_name->n_name;
1894 size_t len = strlen(suff1);
1895
1896 if (strncmp(s, suff1, len) == 0) {
1897 for (rp2 = np->n_rule; rp2; rp2 = rp2->r_next) {
1898 for (dp2 = rp2->r_dep; dp2; dp2 = dp2->d_next) {
1899 const char *suff2 = dp2->d_name->n_name;
1900 if (strcmp(s + len, suff2) == 0) {
1901 return TRUE;
1902 }
1903 }
1904 }
1806 } 1905 }
1807 } 1906 }
1808 } 1907 }
@@ -1824,7 +1923,6 @@ enum {
1824static int 1923static int
1825target_type(char *s) 1924target_type(char *s)
1826{ 1925{
1827 char *sfx;
1828 int ret; 1926 int ret;
1829 static const char *s_name = 1927 static const char *s_name =
1830 ".DEFAULT\0" 1928 ".DEFAULT\0"
@@ -1854,9 +1952,6 @@ target_type(char *s)
1854 T_SPECIAL, 1952 T_SPECIAL,
1855 }; 1953 };
1856 1954
1857 if (*s != '.')
1858 return T_NORMAL;
1859
1860 // Check for one of the known special targets 1955 // Check for one of the known special targets
1861 ret = index_in_strings(s_name, s); 1956 ret = index_in_strings(s_name, s);
1862 if (ret >= 0) 1957 if (ret >= 0)
@@ -1864,16 +1959,23 @@ target_type(char *s)
1864 1959
1865 // Check for an inference rule 1960 // Check for an inference rule
1866 ret = T_NORMAL; 1961 ret = T_NORMAL;
1867 sfx = suffix(s); 1962 if (!posix) {
1868 if (is_suffix(sfx)) { 1963 if (is_suffix(s) || is_inference_target(s)) {
1869 if (s == sfx) { // Single suffix rule
1870 ret = T_INFERENCE | T_NOPREREQ | T_COMMAND; 1964 ret = T_INFERENCE | T_NOPREREQ | T_COMMAND;
1871 } else { 1965 }
1872 // Suffix is valid, check that prefix is too 1966 } else {
1873 *sfx = '\0'; 1967 // In POSIX inference rule targets must contain one or two dots
1874 if (is_suffix(s)) 1968 char *sfx = suffix(s);
1969 if (*s == '.' && is_suffix(sfx)) {
1970 if (s == sfx) { // Single suffix rule
1875 ret = T_INFERENCE | T_NOPREREQ | T_COMMAND; 1971 ret = T_INFERENCE | T_NOPREREQ | T_COMMAND;
1876 *sfx = '.'; 1972 } else {
1973 // Suffix is valid, check that prefix is too
1974 *sfx = '\0';
1975 if (is_suffix(s))
1976 ret = T_INFERENCE | T_NOPREREQ | T_COMMAND;
1977 *sfx = '.';
1978 }
1877 } 1979 }
1878 } 1980 }
1879 return ret; 1981 return ret;
@@ -2069,6 +2171,20 @@ pragmas_from_env(void)
2069#endif 2171#endif
2070 2172
2071/* 2173/*
2174 * Determine if a line is a target rule with an inline command.
2175 * Return a pointer to the semicolon separator if it is, else NULL.
2176 */
2177static char *
2178inline_command(char *line)
2179{
2180 char *p = find_char(line, ':');
2181
2182 if (p)
2183 p = strchr(p, ';');
2184 return p;
2185}
2186
2187/*
2072 * Parse input from the makefile and construct a tree structure of it. 2188 * Parse input from the makefile and construct a tree structure of it.
2073 */ 2189 */
2074static void 2190static void
@@ -2287,9 +2403,9 @@ input(FILE *fd, int ilevel)
2287 cp = NULL; 2403 cp = NULL;
2288 s = strchr(q, ';'); 2404 s = strchr(q, ';');
2289 if (s) { 2405 if (s) {
2290 // Retrieve command from expanded copy of line 2406 // Retrieve command from original or expanded copy of line
2291 char *copy3 = expand_macros(copy, FALSE); 2407 char *copy3 = expand_macros(copy, FALSE);
2292 if ((p = find_colon(copy3)) && (p = strchr(p, ';'))) 2408 if ((p = inline_command(copy)) || (p = inline_command(copy3)))
2293 newcmd(&cp, process_command(p + 1)); 2409 newcmd(&cp, process_command(p + 1));
2294 free(copy3); 2410 free(copy3);
2295 *s = '\0'; 2411 *s = '\0';
@@ -2585,9 +2701,34 @@ docmds(struct name *np, struct cmd *cp)
2585 return estat; 2701 return estat;
2586} 2702}
2587 2703
2704/*
2705 * Remove the suffix from a name, either the one provided in 'tsuff'
2706 * or, if 'tsuff' is NULL, one of the known suffixes.
2707 */
2708static char *
2709remove_suffix(const char *name, const char *tsuff)
2710{
2711 char *base = NULL;
2712
2713 if (tsuff != NULL) {
2714 base = has_suffix(name, tsuff);
2715 } else {
2716 struct name *xp = newname(".SUFFIXES");
2717 for (struct rule *rp = xp->n_rule; rp; rp = rp->r_next) {
2718 for (struct depend *dp = rp->r_dep; dp; dp = dp->d_next) {
2719 base = has_suffix(name, dp->d_name->n_name);
2720 if (base) {
2721 return base;
2722 }
2723 }
2724 }
2725 }
2726 return base;
2727}
2728
2588static int 2729static int
2589make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc, 2730make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc,
2590 char *dedup, struct name *implicit) 2731 char *dedup, struct name *implicit, const char *tsuff)
2591{ 2732{
2592 char *name, *member = NULL, *base = NULL, *prereq = NULL; 2733 char *name, *member = NULL, *base = NULL, *prereq = NULL;
2593 2734
@@ -2603,7 +2744,7 @@ make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc,
2603 char *s; 2744 char *s;
2604 2745
2605 // As an extension, if we're not dealing with an implicit 2746 // As an extension, if we're not dealing with an implicit
2606 // rule set $< to the first out-of-date prerequisite. 2747 // prerequisite set $< to the first out-of-date prerequisite.
2607 if (implicit == NULL) { 2748 if (implicit == NULL) {
2608 if (oodate) { 2749 if (oodate) {
2609 s = strchr(oodate, ' '); 2750 s = strchr(oodate, ' ');
@@ -2614,15 +2755,26 @@ make1(struct name *np, struct cmd *cp, char *oodate, char *allsrc,
2614 } else 2755 } else
2615 prereq = implicit->n_name; 2756 prereq = implicit->n_name;
2616 2757
2617 base = member ? member : name; 2758 if (!posix && member == NULL) {
2618 s = suffix(base); 2759 // As an extension remove a suffix that doesn't necessarily
2619 // As an extension, if we're not dealing with an implicit 2760 // start with a period from a target, but not for targets
2620 // rule and the target ends with a known suffix, remove it 2761 // of the form lib.a(member.o).
2621 // and set $* to the stem, else to an empty string. 2762 base = remove_suffix(name, tsuff);
2622 if (implicit == NULL && !is_suffix(s)) 2763 if (base) {
2623 base = NULL; 2764 free(name);
2624 else 2765 name = base;
2625 *s = '\0'; 2766 }
2767 } else {
2768 base = member ? member : name;
2769 s = suffix(base);
2770 // As an extension, if we're not dealing with an implicit
2771 // prerequisite and the target ends with a known suffix,
2772 // remove it and set $* to the stem, else to an empty string.
2773 if (implicit == NULL && !is_suffix(s))
2774 base = NULL;
2775 else
2776 *s = '\0';
2777 }
2626 } 2778 }
2627 setmacro("<", prereq, 0 | M_VALID); 2779 setmacro("<", prereq, 0 | M_VALID);
2628 setmacro("*", base, 0 | M_VALID); 2780 setmacro("*", base, 0 | M_VALID);
@@ -2667,11 +2819,12 @@ make(struct name *np, int level)
2667 struct depend *dp; 2819 struct depend *dp;
2668 struct rule *rp; 2820 struct rule *rp;
2669 struct name *impdep = NULL; // implicit prerequisite 2821 struct name *impdep = NULL; // implicit prerequisite
2670 struct rule imprule; 2822 struct rule infrule;
2671 struct cmd *sc_cmd = NULL; // commands for single-colon rule 2823 struct cmd *sc_cmd = NULL; // commands for single-colon rule
2672 char *oodate = NULL; 2824 char *oodate = NULL;
2673 char *allsrc = NULL; 2825 char *allsrc = NULL;
2674 char *dedup = NULL; 2826 char *dedup = NULL;
2827 const char *tsuff = NULL;
2675 struct timespec dtim = {1, 0}; 2828 struct timespec dtim = {1, 0};
2676 int estat = 0; 2829 int estat = 0;
2677 2830
@@ -2690,10 +2843,10 @@ make(struct name *np, int level)
2690 // as an extension, not for phony targets) 2843 // as an extension, not for phony targets)
2691 sc_cmd = getcmd(np); 2844 sc_cmd = getcmd(np);
2692 if (!sc_cmd && (posix || !(np->n_flag & N_PHONY))) { 2845 if (!sc_cmd && (posix || !(np->n_flag & N_PHONY))) {
2693 impdep = dyndep(np, &imprule); 2846 impdep = dyndep(np, &infrule, &tsuff);
2694 if (impdep) { 2847 if (impdep) {
2695 sc_cmd = imprule.r_cmd; 2848 sc_cmd = infrule.r_cmd;
2696 addrule(np, imprule.r_dep, NULL, FALSE); 2849 addrule(np, infrule.r_dep, NULL, FALSE);
2697 } 2850 }
2698 } 2851 }
2699 2852
@@ -2708,14 +2861,15 @@ make(struct name *np, int level)
2708 } 2861 }
2709 impdep = np; 2862 impdep = np;
2710 } 2863 }
2711 } 2864 } else {
2712 else {
2713 // If any double-colon rule has no commands we need 2865 // If any double-colon rule has no commands we need
2714 // an inference rule (but, as an extension, not for phony targets) 2866 // an inference rule.
2715 for (rp = np->n_rule; rp; rp = rp->r_next) { 2867 for (rp = np->n_rule; rp; rp = rp->r_next) {
2716 if (!rp->r_cmd) { 2868 if (!rp->r_cmd) {
2717 if (posix || !(np->n_flag & N_PHONY)) 2869 // Phony targets don't need an inference rule.
2718 impdep = dyndep(np, &imprule); 2870 if (!posix && (np->n_flag & N_PHONY))
2871 continue;
2872 impdep = dyndep(np, &infrule, &tsuff);
2719 if (!impdep) { 2873 if (!impdep) {
2720 if (doinclude) 2874 if (doinclude)
2721 return 1; 2875 return 1;
@@ -2741,11 +2895,14 @@ make(struct name *np, int level)
2741 // Each double-colon rule is handled separately. 2895 // Each double-colon rule is handled separately.
2742 if ((np->n_flag & N_DOUBLE)) { 2896 if ((np->n_flag & N_DOUBLE)) {
2743 // If the rule has no commands use the inference rule. 2897 // If the rule has no commands use the inference rule.
2898 // Unless there isn't one, as allowed for phony targets.
2744 if (!rp->r_cmd) { 2899 if (!rp->r_cmd) {
2745 locdep = impdep; 2900 if (impdep) {
2746 imprule.r_dep->d_next = rp->r_dep; 2901 locdep = impdep;
2747 rp->r_dep = imprule.r_dep; 2902 infrule.r_dep->d_next = rp->r_dep;
2748 rp->r_cmd = imprule.r_cmd; 2903 rp->r_dep = infrule.r_dep;
2904 rp->r_cmd = infrule.r_cmd;
2905 }
2749 } 2906 }
2750 // A rule with no prerequisities is executed unconditionally. 2907 // A rule with no prerequisities is executed unconditionally.
2751 if (!rp->r_dep) 2908 if (!rp->r_dep)
@@ -2776,7 +2933,7 @@ make(struct name *np, int level)
2776 if (((np->n_flag & N_PHONY) || timespec_le(&np->n_tim, &dtim))) { 2933 if (((np->n_flag & N_PHONY) || timespec_le(&np->n_tim, &dtim))) {
2777 if (!(estat & MAKE_FAILURE)) { 2934 if (!(estat & MAKE_FAILURE)) {
2778 estat |= make1(np, rp->r_cmd, oodate, allsrc, 2935 estat |= make1(np, rp->r_cmd, oodate, allsrc,
2779 dedup, locdep); 2936 dedup, locdep, tsuff);
2780 dtim = (struct timespec){1, 0}; 2937 dtim = (struct timespec){1, 0};
2781 } 2938 }
2782 free(oodate); 2939 free(oodate);
@@ -2792,7 +2949,7 @@ make(struct name *np, int level)
2792 } 2949 }
2793 } 2950 }
2794 if ((np->n_flag & N_DOUBLE) && impdep) 2951 if ((np->n_flag & N_DOUBLE) && impdep)
2795 free(imprule.r_dep); 2952 free(infrule.r_dep);
2796 2953
2797 np->n_flag |= N_DONE; 2954 np->n_flag |= N_DONE;
2798 np->n_flag &= ~N_DOING; 2955 np->n_flag &= ~N_DOING;
@@ -2801,7 +2958,8 @@ make(struct name *np, int level)
2801 ((np->n_flag & N_PHONY) || (timespec_le(&np->n_tim, &dtim)))) { 2958 ((np->n_flag & N_PHONY) || (timespec_le(&np->n_tim, &dtim)))) {
2802 if (!(estat & MAKE_FAILURE)) { 2959 if (!(estat & MAKE_FAILURE)) {
2803 if (sc_cmd) 2960 if (sc_cmd)
2804 estat |= make1(np, sc_cmd, oodate, allsrc, dedup, impdep); 2961 estat |= make1(np, sc_cmd, oodate, allsrc, dedup,
2962 impdep, tsuff);
2805 else if (!doinclude && level == 0 && !(estat & MAKE_DIDSOMETHING)) 2963 else if (!doinclude && level == 0 && !(estat & MAKE_DIDSOMETHING))
2806 warning("nothing to be done for %s", np->n_name); 2964 warning("nothing to be done for %s", np->n_name);
2807 } else if (!doinclude && !quest) { 2965 } else if (!doinclude && !quest) {
diff --git a/miscutils/man.c b/miscutils/man.c
index 3954455b4..38c1b9aa3 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -143,7 +143,7 @@ static int run_pipe(char *man_filename, int man, int level)
143 143
144 ordinary_manpage: 144 ordinary_manpage:
145 close(STDIN_FILENO); 145 close(STDIN_FILENO);
146 open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */ 146 open_zipped(man_filename, /*die_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */
147 if (man) { 147 if (man) {
148 int w = get_terminal_width(-1); 148 int w = get_terminal_width(-1);
149 if (w > 10) 149 if (w > 10)
diff --git a/networking/Config.src b/networking/Config.src
index 0942645c3..aa0806a18 100644
--- a/networking/Config.src
+++ b/networking/Config.src
@@ -72,9 +72,28 @@ config FEATURE_HWIB
72 help 72 help
73 Support for printing infiniband addresses in network applets. 73 Support for printing infiniband addresses in network applets.
74 74
75choice
76 prompt "TLS implementation"
77 default FEATURE_TLS_INTERNAL
78
79config FEATURE_TLS_INTERNAL
80 bool "Internal"
81 depends on TLS
82 help
83 Use the BusyBox default internal TLS implementation.
84
85config FEATURE_TLS_SCHANNEL
86 bool "Schannel SSP"
87 depends on TLS && PLATFORM_MINGW32
88 help
89 Use the Schannel SSP to provide TLS support.
90 Reduces code size and enables certificate checking.
91
92endchoice
93
75config FEATURE_TLS_SHA1 94config FEATURE_TLS_SHA1
76 bool "In TLS code, support ciphers which use deprecated SHA1" 95 bool "In TLS code, support ciphers which use deprecated SHA1"
77 depends on TLS 96 depends on FEATURE_TLS_INTERNAL
78 default n 97 default n
79 help 98 help
80 Selecting this option increases interoperability with very old 99 Selecting this option increases interoperability with very old
@@ -83,6 +102,15 @@ config FEATURE_TLS_SHA1
83 Most TLS servers support SHA256 today (2018), since SHA1 is 102 Most TLS servers support SHA256 today (2018), since SHA1 is
84 considered possibly insecure (although not yet definitely broken). 103 considered possibly insecure (although not yet definitely broken).
85 104
105config FEATURE_TLS_SCHANNEL_1_3
106 bool "Enable TLS 1.3 support for Schannel"
107 depends on FEATURE_TLS_SCHANNEL
108 default n
109 help
110 Enable TLS 1.3 support for Schannel.
111 This only works on Windows 11/Server 2022
112 and up.
113
86INSERT 114INSERT
87 115
88source networking/udhcp/Config.in 116source networking/udhcp/Config.in
diff --git a/networking/hostname.c b/networking/hostname.c
index 36cb70866..101b89e77 100644
--- a/networking/hostname.c
+++ b/networking/hostname.c
@@ -25,8 +25,8 @@
25//applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) 25//applet:IF_DNSDOMAINNAME(APPLET_NOEXEC(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname))
26//applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname )) 26//applet:IF_HOSTNAME( APPLET_NOEXEC(hostname, hostname, BB_DIR_BIN, BB_SUID_DROP, hostname ))
27 27
28//kbuild: lib-$(CONFIG_HOSTNAME) += hostname.o 28//kbuild:lib-$(CONFIG_HOSTNAME) += hostname.o
29//kbuild: lib-$(CONFIG_DNSDOMAINNAME) += hostname.o 29//kbuild:lib-$(CONFIG_DNSDOMAINNAME) += hostname.o
30 30
31//usage:#define hostname_trivial_usage 31//usage:#define hostname_trivial_usage
32//usage: "[-sidf] [HOSTNAME | -F FILE]" 32//usage: "[-sidf] [HOSTNAME | -F FILE]"
diff --git a/networking/httpd.c b/networking/httpd.c
index 1dae602ee..50595104c 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -3074,7 +3074,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv)
3074 salt[0] = '$'; 3074 salt[0] = '$';
3075 salt[1] = '1'; 3075 salt[1] = '1';
3076 salt[2] = '$'; 3076 salt[2] = '$';
3077 crypt_make_salt(salt + 3, 4); 3077 crypt_make_rand64encoded(salt + 3, 8 / 2); /* 8 chars */
3078 puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); 3078 puts(pw_encrypt(pass, salt, /*cleanup:*/ 0));
3079 return 0; 3079 return 0;
3080 } 3080 }
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index cd77f642f..a30f070eb 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
@@ -302,24 +302,22 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
302 printf("notify "); 302 printf("notify ");
303 } 303 }
304 304
305 if (r->rtm_family == AF_INET6) { 305 if (r->rtm_family == AF_INET || r->rtm_family == AF_INET6) {
306 struct rta_cacheinfo *ci = NULL; 306 if (r->rtm_family == AF_INET) {
307 if (tb[RTA_CACHEINFO]) {
308 ci = RTA_DATA(tb[RTA_CACHEINFO]);
309 }
310 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
311 if (r->rtm_flags & RTM_F_CLONED) { 307 if (r->rtm_flags & RTM_F_CLONED) {
312 printf("%c cache ", _SL_); 308 printf("%c cache ", _SL_);
309 /* upstream: print_cache_flags() prints more here */
313 } 310 }
311 }
312 if (tb[RTA_CACHEINFO]) {
313 struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]);
314 if (ci->rta_expires) { 314 if (ci->rta_expires) {
315 printf(" expires %dsec", ci->rta_expires / get_hz()); 315 printf(" expires %dsec", ci->rta_expires / get_hz());
316 } 316 }
317 if (ci->rta_error != 0) { 317 if (ci->rta_error != 0) {
318 printf(" error %d", ci->rta_error); 318 printf(" error %d", ci->rta_error);
319 } 319 }
320 } else if (ci) { 320 /* upstream: print_rta_cacheinfo() prints more here */
321 if (ci->rta_error != 0)
322 printf(" error %d", ci->rta_error);
323 } 321 }
324 } 322 }
325 if (tb[RTA_IIF] && G_filter.iif == 0) { 323 if (tb[RTA_IIF] && G_filter.iif == 0) {
diff --git a/networking/ntpd.c b/networking/ntpd.c
index dcbdb8e60..dd0a9c91f 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -205,7 +205,7 @@
205#define MINDISP 0.01 /* minimum dispersion (sec) */ 205#define MINDISP 0.01 /* minimum dispersion (sec) */
206#define MAXDISP 16 /* maximum dispersion (sec) */ 206#define MAXDISP 16 /* maximum dispersion (sec) */
207#define MAXSTRAT 16 /* maximum stratum (infinity metric) */ 207#define MAXSTRAT 16 /* maximum stratum (infinity metric) */
208#define MAXDIST 1 /* distance threshold (sec) */ 208#define MAXDIST 3 /* distance threshold (sec): do not use peers who are farther away */
209#define MIN_SELECTED 1 /* minimum intersection survivors */ 209#define MIN_SELECTED 1 /* minimum intersection survivors */
210#define MIN_CLUSTERED 3 /* minimum cluster survivors */ 210#define MIN_CLUSTERED 3 /* minimum cluster survivors */
211 211
@@ -1057,7 +1057,7 @@ step_time(double offset)
1057 } 1057 }
1058 tval = tvn.tv_sec; 1058 tval = tvn.tv_sec;
1059 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); 1059 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval);
1060 bb_info_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); 1060 bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset);
1061 //maybe? G.FREQHOLD_cnt = 0; 1061 //maybe? G.FREQHOLD_cnt = 0;
1062 1062
1063 /* Correct various fields which contain time-relative values: */ 1063 /* Correct various fields which contain time-relative values: */
@@ -1976,7 +1976,7 @@ recv_and_process_peer_pkt(peer_t *p)
1976 1976
1977 p->reachable_bits |= 1; 1977 p->reachable_bits |= 1;
1978 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { 1978 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) {
1979 bb_info_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", 1979 bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x",
1980 p->p_dotted, 1980 p->p_dotted,
1981 offset, 1981 offset,
1982 p->p_raw_delay, 1982 p->p_raw_delay,
diff --git a/networking/telnetd.c b/networking/telnetd.c
index bfeea1400..a5a783047 100644
--- a/networking/telnetd.c
+++ b/networking/telnetd.c
@@ -104,8 +104,8 @@
104//usage:#define telnetd_full_usage "\n\n" 104//usage:#define telnetd_full_usage "\n\n"
105//usage: "Handle incoming telnet connections" 105//usage: "Handle incoming telnet connections"
106//usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" 106//usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n"
107//usage: "\n -l LOGIN Exec LOGIN on connect" 107//usage: "\n -l LOGIN Exec LOGIN on connect (default /bin/login)"
108//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" 108//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue.net"
109//usage: "\n -K Close connection as soon as login exits" 109//usage: "\n -K Close connection as soon as login exits"
110//usage: "\n (normally wait until all programs close slave pty)" 110//usage: "\n (normally wait until all programs close slave pty)"
111//usage: IF_FEATURE_TELNETD_STANDALONE( 111//usage: IF_FEATURE_TELNETD_STANDALONE(
diff --git a/networking/tftp.c b/networking/tftp.c
index f5b4367ca..b698a9288 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -250,7 +250,7 @@ static int tftp_blksize_check(const char *blksize_str, int maxsize)
250 return -1; 250 return -1;
251 } 251 }
252# if ENABLE_TFTP_DEBUG 252# if ENABLE_TFTP_DEBUG
253 bb_info_msg("using blksize %u", blksize); 253 bb_error_msg("using blksize %u", blksize);
254# endif 254# endif
255 return blksize; 255 return blksize;
256} 256}
diff --git a/networking/tls.c b/networking/tls.c
index 9f1dd67ec..9c05364ea 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -10,18 +10,19 @@
10//Config.src also defines FEATURE_TLS_SHA1 option 10//Config.src also defines FEATURE_TLS_SHA1 option
11 11
12//kbuild:lib-$(CONFIG_TLS) += tls.o 12//kbuild:lib-$(CONFIG_TLS) += tls.o
13//kbuild:lib-$(CONFIG_TLS) += tls_pstm.o 13//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm.o
14//kbuild:lib-$(CONFIG_TLS) += tls_pstm_montgomery_reduce.o 14//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_montgomery_reduce.o
15//kbuild:lib-$(CONFIG_TLS) += tls_pstm_mul_comba.o 15//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_mul_comba.o
16//kbuild:lib-$(CONFIG_TLS) += tls_pstm_sqr_comba.o 16//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_pstm_sqr_comba.o
17//kbuild:lib-$(CONFIG_TLS) += tls_aes.o 17//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aes.o
18//kbuild:lib-$(CONFIG_TLS) += tls_aesgcm.o 18//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_aesgcm.o
19//kbuild:lib-$(CONFIG_TLS) += tls_rsa.o 19//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_rsa.o
20//kbuild:lib-$(CONFIG_TLS) += tls_fe.o 20//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_fe.o
21//kbuild:lib-$(CONFIG_TLS) += tls_sp_c32.o 21//kbuild:lib-$(CONFIG_FEATURE_TLS_INTERNAL) += tls_sp_c32.o
22 22
23#include "tls.h" 23#include "tls.h"
24 24
25#if !ENABLE_FEATURE_TLS_SCHANNEL
25// Usually enabled. You can disable some of them to force only 26// Usually enabled. You can disable some of them to force only
26// specific ciphers to be advertized to server. 27// specific ciphers to be advertized to server.
27// (this would not exclude code to handle disabled ciphers, no code size win) 28// (this would not exclude code to handle disabled ciphers, no code size win)
@@ -188,8 +189,6 @@
188#define TLS_MAX_OUTBUF (1 << 14) 189#define TLS_MAX_OUTBUF (1 << 14)
189 190
190enum { 191enum {
191 SHA_INSIZE = 64,
192
193 AES128_KEYSIZE = 16, 192 AES128_KEYSIZE = 16,
194 AES256_KEYSIZE = 32, 193 AES256_KEYSIZE = 32,
195 194
@@ -335,34 +334,6 @@ void FAST_FUNC tls_get_random(void *buf, unsigned len)
335 xfunc_die(); 334 xfunc_die();
336} 335}
337 336
338static void xorbuf3(void *dst, const void *src1, const void *src2, unsigned count)
339{
340 uint8_t *d = dst;
341 const uint8_t *s1 = src1;
342 const uint8_t* s2 = src2;
343 while (count--)
344 *d++ = *s1++ ^ *s2++;
345}
346
347void FAST_FUNC xorbuf(void *dst, const void *src, unsigned count)
348{
349 xorbuf3(dst, dst, src, count);
350}
351
352void FAST_FUNC xorbuf_aligned_AES_BLOCK_SIZE(void *dst, const void *src)
353{
354 unsigned long *d = dst;
355 const unsigned long *s = src;
356 d[0] ^= s[0];
357#if ULONG_MAX <= 0xffffffffffffffff
358 d[1] ^= s[1];
359 #if ULONG_MAX == 0xffffffff
360 d[2] ^= s[2];
361 d[3] ^= s[3];
362 #endif
363#endif
364}
365
366#if !TLS_DEBUG_HASH 337#if !TLS_DEBUG_HASH
367# define hash_handshake(tls, fmt, buffer, len) \ 338# define hash_handshake(tls, fmt, buffer, len) \
368 hash_handshake(tls, buffer, len) 339 hash_handshake(tls, buffer, len)
@@ -393,128 +364,6 @@ static void hash_handshake(tls_state_t *tls, const char *fmt, const void *buffer
393# define TLS_MAC_SIZE(tls) (tls)->MAC_size 364# define TLS_MAC_SIZE(tls) (tls)->MAC_size
394#endif 365#endif
395 366
396// RFC 2104:
397// HMAC(key, text) based on a hash H (say, sha256) is:
398// ipad = [0x36 x INSIZE]
399// opad = [0x5c x INSIZE]
400// HMAC(key, text) = H((key XOR opad) + H((key XOR ipad) + text))
401//
402// H(key XOR opad) and H(key XOR ipad) can be precomputed
403// if we often need HMAC hmac with the same key.
404//
405// text is often given in disjoint pieces.
406typedef struct hmac_precomputed {
407 md5sha_ctx_t hashed_key_xor_ipad;
408 md5sha_ctx_t hashed_key_xor_opad;
409} hmac_precomputed_t;
410
411typedef void md5sha_begin_func(md5sha_ctx_t *ctx) FAST_FUNC;
412#if !ENABLE_FEATURE_TLS_SHA1
413#define hmac_begin(pre,key,key_size,begin) \
414 hmac_begin(pre,key,key_size)
415#define begin sha256_begin
416#endif
417static void hmac_begin(hmac_precomputed_t *pre, uint8_t *key, unsigned key_size, md5sha_begin_func *begin)
418{
419 uint8_t key_xor_ipad[SHA_INSIZE];
420 uint8_t key_xor_opad[SHA_INSIZE];
421// uint8_t tempkey[SHA1_OUTSIZE < SHA256_OUTSIZE ? SHA256_OUTSIZE : SHA1_OUTSIZE];
422 unsigned i;
423
424 // "The authentication key can be of any length up to INSIZE, the
425 // block length of the hash function. Applications that use keys longer
426 // than INSIZE bytes will first hash the key using H and then use the
427 // resultant OUTSIZE byte string as the actual key to HMAC."
428 if (key_size > SHA_INSIZE) {
429 bb_simple_error_msg_and_die("HMAC key>64"); //does not happen (yet?)
430// md5sha_ctx_t ctx;
431// begin(&ctx);
432// md5sha_hash(&ctx, key, key_size);
433// key_size = sha_end(&ctx, tempkey);
434// //key = tempkey; - right? RIGHT? why does it work without this?
435// // because SHA_INSIZE is 64, but hmac() is always called with
436// // key_size = tls->MAC_size = SHA1/256_OUTSIZE (20 or 32),
437// // and prf_hmac_sha256() -> hmac_sha256() key sizes are:
438// // - RSA_PREMASTER_SIZE is 48
439// // - CURVE25519_KEYSIZE is 32
440// // - master_secret[] is 48
441 }
442
443 for (i = 0; i < key_size; i++) {
444 key_xor_ipad[i] = key[i] ^ 0x36;
445 key_xor_opad[i] = key[i] ^ 0x5c;
446 }
447 for (; i < SHA_INSIZE; i++) {
448 key_xor_ipad[i] = 0x36;
449 key_xor_opad[i] = 0x5c;
450 }
451
452 begin(&pre->hashed_key_xor_ipad);
453 begin(&pre->hashed_key_xor_opad);
454 md5sha_hash(&pre->hashed_key_xor_ipad, key_xor_ipad, SHA_INSIZE);
455 md5sha_hash(&pre->hashed_key_xor_opad, key_xor_opad, SHA_INSIZE);
456}
457#undef begin
458
459static unsigned hmac_sha_precomputed_v(
460 hmac_precomputed_t *pre,
461 uint8_t *out,
462 va_list va)
463{
464 uint8_t *text;
465 unsigned len;
466
467 /* pre->hashed_key_xor_ipad contains unclosed "H((key XOR ipad) +" state */
468 /* pre->hashed_key_xor_opad contains unclosed "H((key XOR opad) +" state */
469
470 /* calculate out = H((key XOR ipad) + text) */
471 while ((text = va_arg(va, uint8_t*)) != NULL) {
472 unsigned text_size = va_arg(va, unsigned);
473 md5sha_hash(&pre->hashed_key_xor_ipad, text, text_size);
474 }
475 len = sha_end(&pre->hashed_key_xor_ipad, out);
476
477 /* out = H((key XOR opad) + out) */
478 md5sha_hash(&pre->hashed_key_xor_opad, out, len);
479 return sha_end(&pre->hashed_key_xor_opad, out);
480}
481
482static unsigned hmac_sha_precomputed(hmac_precomputed_t *pre_init, uint8_t *out, ...)
483{
484 hmac_precomputed_t pre;
485 va_list va;
486 unsigned len;
487
488 va_start(va, out);
489 pre = *pre_init; /* struct copy */
490 len = hmac_sha_precomputed_v(&pre, out, va);
491 va_end(va);
492 return len;
493}
494
495#if !ENABLE_FEATURE_TLS_SHA1
496#define hmac(tls,out,key,key_size,...) \
497 hmac(out,key,key_size, __VA_ARGS__)
498#endif
499static unsigned hmac(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...)
500{
501 hmac_precomputed_t pre;
502 va_list va;
503 unsigned len;
504
505 va_start(va, key_size);
506
507 hmac_begin(&pre, key, key_size,
508 (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE)
509 ? sha1_begin
510 : sha256_begin
511 );
512 len = hmac_sha_precomputed_v(&pre, out, va);
513
514 va_end(va);
515 return len;
516}
517
518// RFC 5246: 367// RFC 5246:
519// 5. HMAC and the Pseudorandom Function 368// 5. HMAC and the Pseudorandom Function
520//... 369//...
@@ -559,7 +408,7 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/
559 const char *label, 408 const char *label,
560 uint8_t *seed, unsigned seed_size) 409 uint8_t *seed, unsigned seed_size)
561{ 410{
562 hmac_precomputed_t pre; 411 hmac_ctx_t ctx;
563 uint8_t a[TLS_MAX_MAC_SIZE]; 412 uint8_t a[TLS_MAX_MAC_SIZE];
564 uint8_t *out_p = outbuf; 413 uint8_t *out_p = outbuf;
565 unsigned label_size = strlen(label); 414 unsigned label_size = strlen(label);
@@ -569,26 +418,27 @@ static void prf_hmac_sha256(/*tls_state_t *tls,*/
569#define SEED label, label_size, seed, seed_size 418#define SEED label, label_size, seed, seed_size
570#define A a, MAC_size 419#define A a, MAC_size
571 420
572 hmac_begin(&pre, secret, secret_size, sha256_begin); 421 hmac_begin(&ctx, secret, secret_size, sha256_begin_hmac);
573 422
574 /* A(1) = HMAC_hash(secret, seed) */ 423 /* A(1) = HMAC_hash(secret, seed) */
575 hmac_sha_precomputed(&pre, a, SEED, NULL); 424 hmac_peek_hash(&ctx, a, SEED, NULL);
576 425
577 for (;;) { 426 for (;;) {
578 /* HMAC_hash(secret, A(1) + seed) */ 427 /* HMAC_hash(secret, A(1) + seed) */
579 if (outbuf_size <= MAC_size) { 428 if (outbuf_size <= MAC_size) {
580 /* Last, possibly incomplete, block */ 429 /* Last, possibly incomplete, block */
581 /* (use a[] as temp buffer) */ 430 /* (use a[] as temp buffer) */
582 hmac_sha_precomputed(&pre, a, A, SEED, NULL); 431 hmac_peek_hash(&ctx, a, A, SEED, NULL);
583 memcpy(out_p, a, outbuf_size); 432 memcpy(out_p, a, outbuf_size);
433 hmac_uninit(&ctx);
584 return; 434 return;
585 } 435 }
586 /* Not last block. Store directly to result buffer */ 436 /* Not last block. Store directly to result buffer */
587 hmac_sha_precomputed(&pre, out_p, A, SEED, NULL); 437 hmac_peek_hash(&ctx, out_p, A, SEED, NULL);
588 out_p += MAC_size; 438 out_p += MAC_size;
589 outbuf_size -= MAC_size; 439 outbuf_size -= MAC_size;
590 /* A(2) = HMAC_hash(secret, A(1)) */ 440 /* A(2) = HMAC_hash(secret, A(1)) */
591 hmac_sha_precomputed(&pre, a, A, NULL); 441 hmac_peek_hash(&ctx, a, A, NULL);
592 } 442 }
593#undef A 443#undef A
594#undef SECRET 444#undef SECRET
@@ -655,6 +505,32 @@ static void *tls_get_zeroed_outbuf(tls_state_t *tls, int len)
655 return record; 505 return record;
656} 506}
657 507
508/* Calculate the HMAC over the list of blocks */
509#if !ENABLE_FEATURE_TLS_SHA1
510#define hmac_blocks(tls,out,key,key_size,...) \
511 hmac_blocks(out,key,key_size, __VA_ARGS__)
512#endif
513static unsigned hmac_blocks(tls_state_t *tls, uint8_t *out, uint8_t *key, unsigned key_size, ...)
514{
515 hmac_ctx_t ctx;
516 va_list va;
517 unsigned len;
518
519 hmac_begin(&ctx, key, key_size,
520 (ENABLE_FEATURE_TLS_SHA1 && tls->MAC_size == SHA1_OUTSIZE)
521 ? sha1_begin_hmac
522 : sha256_begin_hmac
523 );
524
525 va_start(va, key_size);
526 hmac_hash_v(&ctx, va);
527 va_end(va);
528
529 len = hmac_end(&ctx, out);
530 hmac_uninit(&ctx);
531 return len;
532}
533
658static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type) 534static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, unsigned type)
659{ 535{
660 uint8_t *buf = tls->outbuf + OUTBUF_PFX; 536 uint8_t *buf = tls->outbuf + OUTBUF_PFX;
@@ -676,7 +552,7 @@ static void xwrite_encrypted_and_hmac_signed(tls_state_t *tls, unsigned size, un
676 xhdr->len16_lo = size & 0xff; 552 xhdr->len16_lo = size & 0xff;
677 553
678 /* Calculate MAC signature */ 554 /* Calculate MAC signature */
679 hmac(tls, buf + size, /* result */ 555 hmac_blocks(tls, buf + size, /* result */
680 tls->client_write_MAC_key, TLS_MAC_SIZE(tls), 556 tls->client_write_MAC_key, TLS_MAC_SIZE(tls),
681 &tls->write_seq64_be, sizeof(tls->write_seq64_be), 557 &tls->write_seq64_be, sizeof(tls->write_seq64_be),
682 xhdr, RECHDR_LEN, 558 xhdr, RECHDR_LEN,
@@ -865,8 +741,13 @@ static void xwrite_encrypted_aesgcm(tls_state_t *tls, unsigned size, unsigned ty
865 cnt++; 741 cnt++;
866 COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ 742 COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */
867 aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch); 743 aes_encrypt_one_block(&tls->aes_encrypt, nonce, scratch);
868 n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; 744 if (remaining >= AES_BLOCK_SIZE) {
869 xorbuf(buf, scratch, n); 745 n = AES_BLOCK_SIZE;
746 xorbuf_AES_BLOCK_SIZE(buf, scratch);
747 } else {
748 n = remaining;
749 xorbuf(buf, scratch, n);
750 }
870 buf += n; 751 buf += n;
871 remaining -= n; 752 remaining -= n;
872 } 753 }
@@ -1024,7 +905,7 @@ static void tls_aesgcm_decrypt(tls_state_t *tls, uint8_t *buf, int size)
1024 COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */ 905 COUNTER(nonce) = htonl(cnt); /* yes, first cnt here is 2 (!) */
1025 aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch); 906 aes_encrypt_one_block(&tls->aes_decrypt, nonce, scratch);
1026 n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining; 907 n = remaining > AES_BLOCK_SIZE ? AES_BLOCK_SIZE : remaining;
1027 xorbuf3(buf, scratch, buf + 8, n); 908 xorbuf_3(buf, scratch, buf + 8, n);
1028 buf += n; 909 buf += n;
1029 remaining -= n; 910 remaining -= n;
1030 } 911 }
@@ -2481,3 +2362,549 @@ void FAST_FUNC tls_run_copy_loop(tls_state_t *tls, unsigned flags)
2481 } 2362 }
2482 } 2363 }
2483} 2364}
2365#else
2366
2367#if ENABLE_FEATURE_TLS_SCHANNEL_1_3
2368#include <subauth.h>
2369#endif
2370
2371#define SCHANNEL_USE_BLACKLISTS
2372
2373#include <security.h>
2374#include <schannel.h>
2375
2376
2377#define BB_SCHANNEL_ISC_FLAGS \
2378 (ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_CONFIDENTIALITY | ISC_REQ_INTEGRITY | ISC_REQ_REPLAY_DETECT | \
2379 ISC_REQ_SEQUENCE_DETECT | ISC_REQ_STREAM | ISC_REQ_USE_SUPPLIED_CREDS)
2380
2381static char *hresult_to_error_string(HRESULT result) {
2382 char *output = NULL;
2383
2384 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
2385 | FORMAT_MESSAGE_IGNORE_INSERTS |
2386 FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, result,
2387 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
2388 (char *) &output, 0, NULL);
2389 return output;
2390}
2391
2392static ssize_t tls_read(struct tls_state *state, char *buf, ssize_t len) {
2393 ssize_t amount_read = 0;
2394
2395 if (state->closed) {
2396 return 0;
2397 }
2398
2399 while (len > 0) {
2400 if (state->out_buffer && (state->out_buffer_size > 0)) {
2401 unsigned long copy_amount =
2402 min(len, (ssize_t) state->out_buffer_size);
2403 memcpy(buf, state->out_buffer, copy_amount);
2404
2405 amount_read += copy_amount;
2406 buf += copy_amount;
2407 len -= copy_amount;
2408
2409 if (copy_amount == state->out_buffer_size) {
2410 // We've used all the decrypted data
2411 // Move extra data to the front
2412 memmove(state->in_buffer,
2413 state->in_buffer + state->out_buffer_used,
2414 state->in_buffer_size - state->out_buffer_used);
2415 state->in_buffer_size -= state->out_buffer_used;
2416
2417 state->out_buffer = NULL;
2418 state->out_buffer_used = 0;
2419 state->out_buffer_size = 0;
2420 } else {
2421 state->out_buffer_size -= copy_amount;
2422 state->out_buffer += copy_amount;
2423 }
2424 } else {
2425 SECURITY_STATUS status;
2426
2427 int received;
2428
2429 SecBuffer buffers[4];
2430
2431 SecBufferDesc desc;
2432
2433 buffers[0].BufferType = SECBUFFER_DATA;
2434 buffers[0].pvBuffer = state->in_buffer;
2435 buffers[0].cbBuffer = state->in_buffer_size;
2436
2437 buffers[1].BufferType = SECBUFFER_EMPTY;
2438 buffers[1].pvBuffer = NULL;
2439 buffers[1].cbBuffer = 0;
2440
2441 buffers[2].BufferType = SECBUFFER_EMPTY;
2442 buffers[2].pvBuffer = NULL;
2443 buffers[2].cbBuffer = 0;
2444
2445 buffers[3].BufferType = SECBUFFER_EMPTY;
2446 buffers[3].pvBuffer = NULL;
2447 buffers[3].cbBuffer = 0;
2448
2449 desc.ulVersion = SECBUFFER_VERSION;
2450 desc.pBuffers = buffers;
2451 desc.cBuffers = _countof(buffers);
2452
2453 status = DecryptMessage(&state->ctx_handle, &desc, 0, NULL);
2454
2455 switch (status) {
2456 case SEC_E_OK:{
2457 state->out_buffer = buffers[1].pvBuffer;
2458 state->out_buffer_size = buffers[1].cbBuffer;
2459
2460 state->out_buffer_used = state->in_buffer_size;
2461 if (buffers[3].BufferType == SECBUFFER_EXTRA) {
2462 state->out_buffer_used -= buffers[3].cbBuffer;
2463 }
2464
2465 continue;
2466 }
2467 case SEC_I_CONTEXT_EXPIRED:{
2468 state->closed = 1;
2469 goto Success;
2470 }
2471 case SEC_I_RENEGOTIATE:{
2472 // Renegotiate the TLS connection.
2473 // Microsoft repurposed this flag
2474 // for TLS 1.3 support.
2475 int i;
2476
2477 DWORD flags;
2478
2479 SecBuffer in_buffers[2];
2480
2481 SecBuffer out_buffers[2];
2482
2483 SecBufferDesc in_desc;
2484
2485 SecBufferDesc out_desc;
2486
2487
2488 for (i = 0; i < 4; i++) {
2489 if (buffers[i].BufferType == SECBUFFER_EXTRA)
2490 break;
2491 }
2492
2493 flags = BB_SCHANNEL_ISC_FLAGS;
2494
2495 in_buffers[0].BufferType = SECBUFFER_TOKEN;
2496 in_buffers[0].pvBuffer = buffers[i].pvBuffer;
2497 in_buffers[0].cbBuffer = buffers[i].cbBuffer;
2498
2499 in_buffers[1].BufferType = SECBUFFER_EMPTY;
2500 in_buffers[1].pvBuffer = NULL;
2501 in_buffers[1].cbBuffer = 0;
2502
2503 out_buffers[0].BufferType = SECBUFFER_TOKEN;
2504 out_buffers[0].pvBuffer = NULL;
2505 out_buffers[0].cbBuffer = 0;
2506
2507 out_buffers[1].BufferType = SECBUFFER_ALERT;
2508 out_buffers[1].pvBuffer = NULL;
2509 out_buffers[1].cbBuffer = 0;
2510
2511 in_desc.ulVersion = SECBUFFER_VERSION;
2512 in_desc.pBuffers = in_buffers;
2513 in_desc.cBuffers = _countof(in_buffers);
2514
2515 out_desc.ulVersion = SECBUFFER_VERSION;
2516 out_desc.pBuffers = out_buffers;
2517 out_desc.cBuffers = _countof(out_buffers);
2518
2519 status = InitializeSecurityContext(&state->cred_handle,
2520 state->initialized ?
2521 &state->ctx_handle : NULL,
2522 state->initialized ? NULL :
2523 state->hostname, flags, 0,
2524 0,
2525 state->initialized ?
2526 &in_desc : NULL, 0,
2527 state->initialized ? NULL :
2528 &state->ctx_handle,
2529 &out_desc, &flags, 0);
2530
2531 if (status != SEC_E_OK) {
2532 bb_error_msg_and_die("schannel: renegotiate failed: (0x%08lx): %s",
2533 status, hresult_to_error_string(status));
2534 }
2535
2536 if (in_buffers[1].BufferType == SECBUFFER_EXTRA) {
2537 memmove(state->in_buffer,
2538 state->in_buffer + (state->in_buffer_size -
2539 in_buffers[1].cbBuffer),
2540 in_buffers[1].cbBuffer);
2541 }
2542
2543 state->out_buffer_used =
2544 state->in_buffer_size - in_buffers[1].cbBuffer;
2545 state->in_buffer_size = in_buffers[1].cbBuffer;
2546
2547 continue;
2548 }
2549 case SEC_E_INCOMPLETE_MESSAGE:{
2550 break;
2551 }
2552 default:{
2553 bb_error_msg_and_die("schannel: DecryptMessage failed: (0x%08lx): %s", status,
2554 hresult_to_error_string(status));
2555 }
2556 }
2557
2558 received =
2559 safe_read(state->ifd,
2560 state->in_buffer + state->in_buffer_size,
2561 sizeof(state->in_buffer) - state->in_buffer_size);
2562 if (received == 0) {
2563 state->closed = 1;
2564 goto Success;
2565 } else if (received < 0) {
2566 bb_error_msg_and_die("schannel: read() failed");
2567 }
2568
2569 state->in_buffer_size += received;
2570 }
2571 }
2572
2573 Success:
2574 return amount_read;
2575}
2576
2577static void tls_write(struct tls_state *state, char *buf, size_t len) {
2578 if (state->closed) {
2579 bb_error_msg_and_die("schannel: attempted to write to a closed connection");
2580 }
2581
2582 while (len > 0) {
2583 unsigned long copy_amount =
2584 min(len, (size_t) state->stream_sizes.cbMaximumMessage);
2585 char *write_buffer = _alloca(sizeof(state->in_buffer));
2586
2587 SECURITY_STATUS status;
2588
2589 SecBuffer buffers[4];
2590
2591 SecBufferDesc desc;
2592
2593 buffers[0].BufferType = SECBUFFER_STREAM_HEADER;
2594 buffers[0].pvBuffer = write_buffer;
2595 buffers[0].cbBuffer = state->stream_sizes.cbHeader;
2596
2597 buffers[1].BufferType = SECBUFFER_DATA;
2598 buffers[1].pvBuffer = write_buffer + state->stream_sizes.cbHeader;
2599 buffers[1].cbBuffer = copy_amount;
2600
2601 buffers[2].BufferType = SECBUFFER_STREAM_TRAILER;
2602 buffers[2].pvBuffer =
2603 write_buffer + state->stream_sizes.cbHeader + copy_amount;
2604 buffers[2].cbBuffer = state->stream_sizes.cbTrailer;
2605
2606 buffers[3].BufferType = SECBUFFER_EMPTY;
2607 buffers[3].pvBuffer = NULL;
2608 buffers[3].cbBuffer = 0;
2609
2610 memcpy(buffers[1].pvBuffer, buf, copy_amount);
2611
2612 desc.ulVersion = SECBUFFER_VERSION;
2613 desc.pBuffers = buffers;
2614 desc.cBuffers = _countof(buffers);
2615
2616 status = EncryptMessage(&state->ctx_handle, 0, &desc, 0);
2617 if (status != SEC_E_OK) {
2618 bb_error_msg_and_die("schannel: EncryptMessage failed: (0x%08lx): %s", status,
2619 hresult_to_error_string(status));
2620 }
2621
2622 xwrite(state->ofd, write_buffer,
2623 buffers[0].cbBuffer + buffers[1].cbBuffer +
2624 buffers[2].cbBuffer);
2625
2626 len -= copy_amount;
2627 }
2628}
2629
2630static void tls_disconnect(tls_state_t * state) {
2631 SECURITY_STATUS status;
2632 DWORD token = SCHANNEL_SHUTDOWN;
2633 DWORD flags = BB_SCHANNEL_ISC_FLAGS;
2634
2635 SecBuffer buf_token;
2636
2637 SecBufferDesc buf_token_desc;
2638
2639 SecBuffer in_buffers[2];
2640 SecBuffer out_buffers[2];
2641
2642 SecBufferDesc in_desc;
2643 SecBufferDesc out_desc;
2644
2645 buf_token.BufferType = SECBUFFER_TOKEN;
2646 buf_token.pvBuffer = &token;
2647 buf_token.cbBuffer = sizeof(token);
2648
2649 buf_token_desc.ulVersion = SECBUFFER_VERSION;
2650 buf_token_desc.pBuffers = &buf_token;
2651 buf_token_desc.cBuffers = 1;
2652
2653 ApplyControlToken(&state->ctx_handle, &buf_token_desc);
2654
2655 // attempt to send any final data
2656
2657 in_buffers[0].BufferType = SECBUFFER_TOKEN;
2658 in_buffers[0].pvBuffer = state->in_buffer;
2659 in_buffers[0].cbBuffer = state->in_buffer_size;
2660
2661 in_buffers[1].BufferType = SECBUFFER_EMPTY;
2662 in_buffers[1].pvBuffer = NULL;
2663 in_buffers[1].cbBuffer = 0;
2664
2665 out_buffers[0].BufferType = SECBUFFER_TOKEN;
2666 out_buffers[0].pvBuffer = NULL;
2667 out_buffers[0].cbBuffer = 0;
2668
2669 out_buffers[1].BufferType = SECBUFFER_ALERT;
2670 out_buffers[1].pvBuffer = NULL;
2671 out_buffers[1].cbBuffer = 0;
2672
2673 in_desc.ulVersion = SECBUFFER_VERSION;
2674 in_desc.pBuffers = in_buffers;
2675 in_desc.cBuffers = _countof(in_buffers);
2676
2677 out_desc.ulVersion = SECBUFFER_VERSION;
2678 out_desc.pBuffers = out_buffers;
2679 out_desc.cBuffers = _countof(out_buffers);
2680
2681 status = InitializeSecurityContext(&state->cred_handle,
2682 state->
2683 initialized ? &state->ctx_handle :
2684 NULL,
2685 state->
2686 initialized ? NULL : state->hostname,
2687 flags, 0, 0,
2688 state->initialized ? &in_desc : NULL,
2689 0,
2690 state->
2691 initialized ? NULL :
2692 &state->ctx_handle, &out_desc, &flags,
2693 0);
2694
2695 if (status == SEC_E_OK) {
2696 // attempt to write any extra data
2697 write(state->ofd, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer);
2698 }
2699
2700 DeleteSecurityContext(&state->ctx_handle);
2701 FreeCredentialsHandle(&state->cred_handle);
2702 free(state->hostname);
2703}
2704
2705
2706void FAST_FUNC tls_handshake(tls_state_t * state, const char *hostname) {
2707 SECURITY_STATUS status;
2708 int received;
2709
2710#if ENABLE_FEATURE_TLS_SCHANNEL_1_3
2711 SCH_CREDENTIALS credential = {.dwVersion = SCH_CREDENTIALS_VERSION,
2712 .dwCredFormat = 0,
2713 .cCreds = 0,
2714 .paCred = NULL,
2715 .hRootStore = NULL,
2716 .cMappers = 0,
2717 .aphMappers = NULL,
2718 .dwSessionLifespan = 0,
2719 .dwFlags =
2720 SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS |
2721 SCH_USE_STRONG_CRYPTO,
2722 .cTlsParameters = 0,
2723 .pTlsParameters = NULL
2724 };
2725#else
2726 SCHANNEL_CRED credential = {.dwVersion = SCHANNEL_CRED_VERSION,
2727 .cCreds = 0,
2728 .paCred = NULL,
2729 .hRootStore = NULL,
2730 .cMappers = 0,
2731 .aphMappers = NULL,
2732 .cSupportedAlgs = 0,
2733 .palgSupportedAlgs = NULL,
2734 .grbitEnabledProtocols =
2735 SP_PROT_TLS1_0_CLIENT | SP_PROT_TLS1_1_CLIENT |
2736 SP_PROT_TLS1_2_CLIENT,
2737 .dwMinimumCipherStrength = 0,
2738 .dwMaximumCipherStrength = 0,
2739 .dwSessionLifespan = 0,
2740 .dwFlags =
2741 SCH_CRED_AUTO_CRED_VALIDATION | SCH_CRED_NO_DEFAULT_CREDS |
2742 SCH_USE_STRONG_CRYPTO,
2743 .dwCredFormat = 0
2744 };
2745#endif
2746
2747 if ((status = AcquireCredentialsHandleA(NULL, (SEC_CHAR *) UNISP_NAME_A,
2748 SECPKG_CRED_OUTBOUND, NULL,
2749 &credential,
2750 NULL, NULL, &state->cred_handle,
2751 NULL)) != SEC_E_OK) {
2752 bb_error_msg_and_die("schannel: AcquireCredentialsHandleA failed: (0x%08lx): %s",
2753 status, hresult_to_error_string(status));
2754 }
2755
2756 state->in_buffer_size = 0;
2757 state->out_buffer_size = 0;
2758 state->out_buffer_used = 0;
2759
2760 state->out_buffer = NULL;
2761
2762 state->hostname = strdup(hostname);
2763
2764 state->initialized = 0;
2765 state->closed = 0;
2766
2767 while (1) {
2768 DWORD flags = BB_SCHANNEL_ISC_FLAGS;
2769
2770 SecBuffer in_buffers[2];
2771 SecBuffer out_buffers[2];
2772
2773 SecBufferDesc in_desc;
2774 SecBufferDesc out_desc;
2775
2776 in_buffers[0].BufferType = SECBUFFER_TOKEN;
2777 in_buffers[0].pvBuffer = state->in_buffer;
2778 in_buffers[0].cbBuffer = state->in_buffer_size;
2779
2780 in_buffers[1].BufferType = SECBUFFER_EMPTY;
2781 in_buffers[1].pvBuffer = NULL;
2782 in_buffers[1].cbBuffer = 0;
2783
2784 out_buffers[0].BufferType = SECBUFFER_TOKEN;
2785 out_buffers[0].pvBuffer = NULL;
2786 out_buffers[0].cbBuffer = 0;
2787
2788 out_buffers[1].BufferType = SECBUFFER_ALERT;
2789 out_buffers[1].pvBuffer = NULL;
2790 out_buffers[1].cbBuffer = 0;
2791
2792 in_desc.ulVersion = SECBUFFER_VERSION;
2793 in_desc.pBuffers = in_buffers;
2794 in_desc.cBuffers = _countof(in_buffers);
2795
2796 out_desc.ulVersion = SECBUFFER_VERSION;
2797 out_desc.pBuffers = out_buffers;
2798 out_desc.cBuffers = _countof(out_buffers);
2799
2800 status = InitializeSecurityContext(&state->cred_handle,
2801 state->
2802 initialized ? &state->ctx_handle :
2803 NULL,
2804 state->
2805 initialized ? NULL :
2806 state->hostname, flags, 0, 0,
2807 state->initialized ? &in_desc :
2808 NULL, 0,
2809 state->initialized ? NULL :
2810 &state->ctx_handle, &out_desc,
2811 &flags, 0);
2812
2813 state->initialized = 1;
2814
2815 if (in_buffers[1].BufferType == SECBUFFER_EXTRA) {
2816 memmove(state->in_buffer,
2817 state->in_buffer + (state->in_buffer_size -
2818 in_buffers[1].cbBuffer),
2819 in_buffers[1].cbBuffer);
2820 state->in_buffer_size = in_buffers[1].cbBuffer;
2821 } else if (status != SEC_E_INCOMPLETE_MESSAGE) {
2822 state->in_buffer_size = 0;
2823 }
2824
2825 switch (status) {
2826 case SEC_E_OK:{
2827 if (out_buffers[0].cbBuffer > 0) {
2828 xwrite(state->ofd, out_buffers[0].pvBuffer,
2829 out_buffers[0].cbBuffer);
2830 FreeContextBuffer(out_buffers[0].pvBuffer);
2831 }
2832 goto Success;
2833 }
2834 case SEC_I_CONTINUE_NEEDED:{
2835 xwrite(state->ofd, out_buffers[0].pvBuffer,
2836 out_buffers[0].cbBuffer);
2837 FreeContextBuffer(out_buffers[0].pvBuffer);
2838 break;
2839 }
2840 case SEC_I_INCOMPLETE_CREDENTIALS:{
2841 // we don't support this
2842 bb_error_msg_and_die("schannel: client certificates not supported");
2843 }
2844 case SEC_E_INCOMPLETE_MESSAGE:{
2845 break;
2846 }
2847 default:{
2848 bb_error_msg_and_die("schannel: handshake failed: (0x%08lx): %s",
2849 status, hresult_to_error_string(status));
2850 }
2851 }
2852
2853 received =
2854 safe_read(state->ifd, state->in_buffer + state->in_buffer_size,
2855 sizeof(state->in_buffer) - state->in_buffer_size);
2856 if (received <= 0) {
2857 bb_error_msg_and_die("schannel: handshake read() failed");
2858 }
2859 state->in_buffer_size += received;
2860 }
2861
2862 Success:
2863 QueryContextAttributes(&state->ctx_handle, SECPKG_ATTR_STREAM_SIZES,
2864 &state->stream_sizes);
2865
2866 //SecPkgContext_ConnectionInfo info;
2867 //QueryContextAttributes(&state->ctx_handle, SECPKG_ATTR_CONNECTION_INFO,
2868 // &info);
2869 //
2870 //fprintf(stderr, "TLS 1.%d\n", (((uint32_t)(8 * sizeof(unsigned long long) - __builtin_clzll((info.dwProtocol)) - 1)) - 7)/2);
2871}
2872
2873void FAST_FUNC tls_run_copy_loop(tls_state_t * tls, unsigned flags) {
2874 char buffer[65536];
2875
2876 struct pollfd pfds[2];
2877
2878 pfds[0].fd = STDIN_FILENO;
2879 pfds[0].events = POLLIN;
2880 pfds[1].fd = tls->ifd;
2881 pfds[1].events = POLLIN;
2882
2883 for (;;) {
2884 int nread;
2885
2886 if (safe_poll(pfds, 2, -1) < 0)
2887 bb_simple_perror_msg_and_die("poll");
2888
2889 if (pfds[0].revents) {
2890 nread = safe_read(STDIN_FILENO, buffer, sizeof(buffer));
2891 if (nread < 1) {
2892 pfds[0].fd = -1;
2893 tls_disconnect(tls);
2894 if (flags & TLSLOOP_EXIT_ON_LOCAL_EOF)
2895 break;
2896 } else {
2897 tls_write(tls, buffer, nread);
2898 }
2899 }
2900 if (pfds[1].revents) {
2901 nread = tls_read(tls, buffer, sizeof(buffer));
2902 if (nread < 1) {
2903 tls_disconnect(tls);
2904 break;
2905 }
2906 xwrite(STDOUT_FILENO, buffer, nread);
2907 }
2908 }
2909}
2910#endif
diff --git a/networking/tls.h b/networking/tls.h
index 0173b87b2..eee5a7617 100644
--- a/networking/tls.h
+++ b/networking/tls.h
@@ -11,6 +11,7 @@
11#include "libbb.h" 11#include "libbb.h"
12 12
13 13
14#if !ENABLE_FEATURE_TLS_SCHANNEL
14/* Config tweaks */ 15/* Config tweaks */
15#define HAVE_NATIVE_INT64 16#define HAVE_NATIVE_INT64
16#undef USE_1024_KEY_SPEED_OPTIMIZATIONS 17#undef USE_1024_KEY_SPEED_OPTIMIZATIONS
@@ -82,10 +83,9 @@ typedef int16_t int16;
82 83
83void tls_get_random(void *buf, unsigned len) FAST_FUNC; 84void tls_get_random(void *buf, unsigned len) FAST_FUNC;
84 85
85void xorbuf(void* buf, const void* mask, unsigned count) FAST_FUNC;
86
87#define ALIGNED_long ALIGNED(sizeof(long)) 86#define ALIGNED_long ALIGNED(sizeof(long))
88void xorbuf_aligned_AES_BLOCK_SIZE(void* buf, const void* mask) FAST_FUNC; 87#define xorbuf_aligned_AES_BLOCK_SIZE(dst,src) xorbuf16_aligned_long(dst,src)
88#define xorbuf_AES_BLOCK_SIZE(dst,src) xorbuf16(dst,src)
89 89
90#define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS) 90#define matrixCryptoGetPrngData(buf, len, userPtr) (tls_get_random(buf, len), PS_SUCCESS)
91 91
@@ -120,3 +120,4 @@ void curve_P256_compute_pubkey_and_premaster(
120void curve_P256_compute_pubkey_and_premaster_NEW( 120void curve_P256_compute_pubkey_and_premaster_NEW(
121 uint8_t *pubkey2x32, uint8_t *premaster32, 121 uint8_t *pubkey2x32, uint8_t *premaster32,
122 const uint8_t *peerkey2x32) FAST_FUNC; 122 const uint8_t *peerkey2x32) FAST_FUNC;
123#endif
diff --git a/networking/tls_aesgcm.c b/networking/tls_aesgcm.c
index 5ddcdd2ad..9c2381a57 100644
--- a/networking/tls_aesgcm.c
+++ b/networking/tls_aesgcm.c
@@ -167,10 +167,7 @@ void FAST_FUNC aesgcm_GHASH(byte* h,
167 blocks = cSz / AES_BLOCK_SIZE; 167 blocks = cSz / AES_BLOCK_SIZE;
168 partial = cSz % AES_BLOCK_SIZE; 168 partial = cSz % AES_BLOCK_SIZE;
169 while (blocks--) { 169 while (blocks--) {
170 if (BB_UNALIGNED_MEMACCESS_OK) // c is not guaranteed to be aligned 170 xorbuf_AES_BLOCK_SIZE(x, c);
171 xorbuf_aligned_AES_BLOCK_SIZE(x, c);
172 else
173 xorbuf(x, c, AES_BLOCK_SIZE);
174 GMULT(x, h); 171 GMULT(x, h);
175 c += AES_BLOCK_SIZE; 172 c += AES_BLOCK_SIZE;
176 } 173 }
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 79cef1999..19c961d5c 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -148,10 +148,11 @@ enum {
148 OPT_o = 1 << 12, 148 OPT_o = 1 << 12,
149 OPT_x = 1 << 13, 149 OPT_x = 1 << 13,
150 OPT_f = 1 << 14, 150 OPT_f = 1 << 14,
151 OPT_l = 1 << 15, 151 OPT_m = 1 << 15,
152 OPT_d = 1 << 16, 152 OPT_l = 1 << 16,
153 OPT_d = 1 << 17,
153/* The rest has variable bit positions, need to be clever */ 154/* The rest has variable bit positions, need to be clever */
154 OPTBIT_d = 16, 155 OPTBIT_d = 17,
155 USE_FOR_MMU( OPTBIT_b,) 156 USE_FOR_MMU( OPTBIT_b,)
156 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) 157 ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
157 IF_FEATURE_UDHCP_PORT( OPTBIT_P,) 158 IF_FEATURE_UDHCP_PORT( OPTBIT_P,)
@@ -268,6 +269,23 @@ static void option_to_env(const uint8_t *option, const uint8_t *option_end)
268 //case D6_OPT_SERVERID: 269 //case D6_OPT_SERVERID:
269 case D6_OPT_IA_NA: 270 case D6_OPT_IA_NA:
270 case D6_OPT_IA_PD: 271 case D6_OPT_IA_PD:
272/* 0 1 2 3
273 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
274 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
275 * | OPTION_IA_PD | option-length |
276 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
277 * | IAID (4 octets) |
278 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
279 * | T1 |
280 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
281 * | T2 |
282 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
283 * . .
284 * . IA_PD-options .
285 * . .
286 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
287 */
288 /* recurse to handle "IA_PD-options" field */
271 option_to_env(option + 16, option + 4 + option[3]); 289 option_to_env(option + 16, option + 4 + option[3]);
272 break; 290 break;
273 //case D6_OPT_IA_TA: 291 //case D6_OPT_IA_TA:
@@ -604,6 +622,31 @@ static NOINLINE int send_d6_info_request(void)
604 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); 622 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
605} 623}
606 624
625/*
626 * RFC 3315 10. Identity Association
627 *
628 * An "identity-association" (IA) is a construct through which a server
629 * and a client can identify, group, and manage a set of related IPv6
630 * addresses. Each IA consists of an IAID and associated configuration
631 * information.
632 *
633 * A client must associate at least one distinct IA with each of its
634 * network interfaces for which it is to request the assignment of IPv6
635 * addresses from a DHCP server. The client uses the IAs assigned to an
636 * interface to obtain configuration information from a server for that
637 * interface. Each IA must be associated with exactly one interface.
638 *
639 * The IAID uniquely identifies the IA and must be chosen to be unique
640 * among the IAIDs on the client. The IAID is chosen by the client.
641 * For any given use of an IA by the client, the IAID for that IA MUST
642 * be consistent across restarts of the DHCP client...
643 */
644/* Generate IAID. We base it on our MAC address' last 4 bytes */
645static void generate_iaid(uint8_t *iaid)
646{
647 memcpy(iaid, &client_data.client_mac[2], 4);
648}
649
607/* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP. 650/* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP.
608 * 651 *
609 * RFC 3315 17.1.1. Creation of Solicit Messages 652 * RFC 3315 17.1.1. Creation of Solicit Messages
@@ -703,7 +746,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6)
703 client6_data.ia_na = xzalloc(len); 746 client6_data.ia_na = xzalloc(len);
704 client6_data.ia_na->code = D6_OPT_IA_NA; 747 client6_data.ia_na->code = D6_OPT_IA_NA;
705 client6_data.ia_na->len = len - 4; 748 client6_data.ia_na->len = len - 4;
706 *(bb__aliased_uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ 749 generate_iaid(client6_data.ia_na->data); /* IAID */
707 if (requested_ipv6) { 750 if (requested_ipv6) {
708 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); 751 struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4);
709 iaaddr->code = D6_OPT_IAADDR; 752 iaaddr->code = D6_OPT_IAADDR;
@@ -721,7 +764,7 @@ static NOINLINE int send_d6_discover(struct in6_addr *requested_ipv6)
721 client6_data.ia_pd = xzalloc(len); 764 client6_data.ia_pd = xzalloc(len);
722 client6_data.ia_pd->code = D6_OPT_IA_PD; 765 client6_data.ia_pd->code = D6_OPT_IA_PD;
723 client6_data.ia_pd->len = len - 4; 766 client6_data.ia_pd->len = len - 4;
724 *(bb__aliased_uint32_t*)client6_data.ia_pd->data = rand(); /* IAID */ 767 generate_iaid(client6_data.ia_pd->data); /* IAID */
725 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); 768 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len);
726 } 769 }
727 770
@@ -1131,12 +1174,11 @@ static void client_background(void)
1131//usage:#endif 1174//usage:#endif
1132//usage:#define udhcpc6_trivial_usage 1175//usage:#define udhcpc6_trivial_usage
1133//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n" 1176//usage: "[-fbq"IF_UDHCP_VERBOSE("v")"R] [-t N] [-T SEC] [-A SEC|-n] [-i IFACE] [-s PROG]\n"
1134//usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-ldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..." 1177//usage: " [-p PIDFILE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-mldo] [-r IPv6] [-x OPT:VAL]... [-O OPT]..."
1135//usage:#define udhcpc6_full_usage "\n" 1178//usage:#define udhcpc6_full_usage "\n"
1136//usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")" 1179//usage: "\n -i IFACE Interface to use (default "CONFIG_UDHCPC_DEFAULT_INTERFACE")"
1137//usage: "\n -p FILE Create pidfile" 1180//usage: "\n -p FILE Create pidfile"
1138//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")" 1181//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC6_DEFAULT_SCRIPT")"
1139//usage: "\n -B Request broadcast replies"
1140//usage: "\n -t N Send up to N discover packets" 1182//usage: "\n -t N Send up to N discover packets"
1141//usage: "\n -T SEC Pause between packets (default 3)" 1183//usage: "\n -T SEC Pause between packets (default 3)"
1142//usage: "\n -A SEC Wait if lease is not obtained (default 20)" 1184//usage: "\n -A SEC Wait if lease is not obtained (default 20)"
@@ -1154,6 +1196,7 @@ static void client_background(void)
1154////usage: IF_FEATURE_UDHCPC_ARPING( 1196////usage: IF_FEATURE_UDHCPC_ARPING(
1155////usage: "\n -a Use arping to validate offered address" 1197////usage: "\n -a Use arping to validate offered address"
1156////usage: ) 1198////usage: )
1199//usage: "\n -m Send multicast renew requests rather than unicast ones"
1157//usage: "\n -l Send 'information request' instead of 'solicit'" 1200//usage: "\n -l Send 'information request' instead of 'solicit'"
1158//usage: "\n (used for servers which do not assign IPv6 addresses)" 1201//usage: "\n (used for servers which do not assign IPv6 addresses)"
1159//usage: "\n -r IPv6 Request this address ('no' to not request any IP)" 1202//usage: "\n -r IPv6 Request this address ('no' to not request any IP)"
@@ -1211,7 +1254,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1211 /* Parse command line */ 1254 /* Parse command line */
1212 opt = getopt32long(argv, "^" 1255 opt = getopt32long(argv, "^"
1213 /* O,x: list; -T,-t,-A take numeric param */ 1256 /* O,x: list; -T,-t,-A take numeric param */
1214 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fld" 1257 "i:np:qRr:s:T:+t:+SA:+O:*ox:*fmld"
1215 USE_FOR_MMU("b") 1258 USE_FOR_MMU("b")
1216 ///IF_FEATURE_UDHCPC_ARPING("a") 1259 ///IF_FEATURE_UDHCPC_ARPING("a")
1217 IF_FEATURE_UDHCP_PORT("P:") 1260 IF_FEATURE_UDHCP_PORT("P:")
@@ -1464,7 +1507,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1464 if (opt & OPT_l) 1507 if (opt & OPT_l)
1465 send_d6_info_request(); 1508 send_d6_info_request();
1466 else 1509 else
1467 send_d6_renew(&srv6_buf, requested_ipv6); 1510 send_d6_renew(OPT_m ? NULL : &srv6_buf, requested_ipv6);
1468 timeout = discover_timeout; 1511 timeout = discover_timeout;
1469 packet_num++; 1512 packet_num++;
1470 continue; 1513 continue;
@@ -1606,62 +1649,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1606 case RENEW_REQUESTED: 1649 case RENEW_REQUESTED:
1607 case REBINDING: 1650 case REBINDING:
1608 if (packet.d6_msg_type == D6_MSG_REPLY) { 1651 if (packet.d6_msg_type == D6_MSG_REPLY) {
1609 unsigned start;
1610 uint32_t lease_seconds;
1611 struct d6_option *option;
1612 unsigned address_timeout;
1613 unsigned prefix_timeout;
1614 type_is_ok:
1615 change_listen_mode(LISTEN_NONE);
1616
1617 address_timeout = 0;
1618 prefix_timeout = 0;
1619 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1620 if (option && (option->data[0] | option->data[1]) != 0) {
1621///FIXME:
1622// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1623// | OPTION_STATUS_CODE | option-len |
1624// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1625// | status-code | |
1626// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1627// . status-message .
1628// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1629// so why do we think it's NAK if data[0] is zero but data[1] is not? That's wrong...
1630// we should also check that option->len is ok (i.e. not 0), right?
1631 /* return to init state */
1632 bb_info_msg("received DHCP NAK (%u)", option->data[4]);
1633 d6_run_script(packet.d6_options,
1634 packet_end, "nak");
1635 if (client_data.state != REQUESTING)
1636 d6_run_script_no_option("deconfig");
1637 sleep(3); /* avoid excessive network traffic */
1638 client_data.state = INIT_SELECTING;
1639 client_data.first_secs = 0; /* make secs field count from 0 */
1640 requested_ipv6 = NULL;
1641 timeout = 0;
1642 packet_num = 0;
1643 continue;
1644 }
1645 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1646 if (!option) {
1647 bb_simple_info_msg("no server ID, ignoring packet");
1648 continue;
1649 /* still selecting - this server looks bad */
1650 }
1651//Note: we do not bother comparing server IDs in Advertise and Reply msgs.
1652//server_id variable is used solely for creation of proper server_id option
1653//in outgoing packets. (why DHCPv6 even introduced it is a mystery).
1654 free(client6_data.server_id);
1655 client6_data.server_id = option;
1656 if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1657 /* enter requesting state */
1658 change_listen_mode(LISTEN_RAW);
1659 client_data.state = REQUESTING;
1660 timeout = 0;
1661 packet_num = 0;
1662 continue;
1663 }
1664 /* It's a D6_MSG_REPLY */
1665/* 1652/*
1666 * RFC 3315 18.1.8. Receipt of Reply Messages 1653 * RFC 3315 18.1.8. Receipt of Reply Messages
1667 * 1654 *
@@ -1747,6 +1734,67 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1747 * . . 1734 * . .
1748 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 1735 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1749 */ 1736 */
1737 unsigned start;
1738 uint32_t lease_seconds;
1739 struct d6_option *option;
1740 unsigned address_timeout;
1741 unsigned prefix_timeout;
1742 type_is_ok:
1743 change_listen_mode(LISTEN_NONE);
1744
1745 address_timeout = 0;
1746 prefix_timeout = 0;
1747 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1748 if (option) {
1749// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1750// | OPTION_STATUS_CODE | option-len |
1751// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1752// | status-code | |
1753// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
1754// . status-message .
1755// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1756 unsigned len, status;
1757 len = ((unsigned)option->len_hi << 8) + option->len;
1758 if (len < 2) {
1759 bb_simple_error_msg("invalid OPTION_STATUS_CODE, ignoring packet");
1760 continue;
1761 }
1762 status = ((unsigned)option->data[0] << 8) + option->data[1];
1763 if (status != 0) {
1764//TODO: handle status == 5 (UseMulticast)?
1765 /* return to init state */
1766 bb_info_msg("received DHCP NAK: %u '%.*s'", status, len - 2, option->data + 2);
1767 d6_run_script(packet.d6_options, packet_end, "nak");
1768 if (client_data.state != REQUESTING)
1769 d6_run_script_no_option("deconfig");
1770 sleep(3); /* avoid excessive network traffic */
1771 client_data.state = INIT_SELECTING;
1772 client_data.first_secs = 0; /* make secs field count from 0 */
1773 requested_ipv6 = NULL;
1774 timeout = 0;
1775 packet_num = 0;
1776 continue;
1777 }
1778 }
1779 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1780 if (!option) {
1781 bb_simple_info_msg("no server ID, ignoring packet");
1782 continue;
1783 /* still selecting - this server looks bad */
1784 }
1785//Note: we do not bother comparing server IDs in Advertise and Reply msgs.
1786//server_id variable is used solely for creation of proper server_id option
1787//in outgoing packets. (why DHCPv6 even introduced it is a mystery).
1788 free(client6_data.server_id);
1789 client6_data.server_id = option;
1790 if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1791 /* enter requesting state */
1792 change_listen_mode(LISTEN_RAW);
1793 client_data.state = REQUESTING;
1794 timeout = 0;
1795 packet_num = 0;
1796 continue;
1797 }
1750 if (option_mask32 & OPT_r) { 1798 if (option_mask32 & OPT_r) {
1751 struct d6_option *iaaddr; 1799 struct d6_option *iaaddr;
1752 1800
@@ -1790,6 +1838,21 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1790 1838
1791 free(client6_data.ia_pd); 1839 free(client6_data.ia_pd);
1792 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD); 1840 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
1841// 0 1 2 3
1842// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
1843// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1844// | OPTION_IA_PD | option-length |
1845// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1846// | IAID (4 octets) |
1847// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1848// | T1 |
1849// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1850// | T2 |
1851// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1852// . .
1853// . IA_PD-options .
1854// . .
1855// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
1793 if (!client6_data.ia_pd) { 1856 if (!client6_data.ia_pd) {
1794 bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet"); 1857 bb_info_msg("no %s option%s", "IA_PD", ", ignoring packet");
1795 continue; 1858 continue;
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c
index 142de9b43..1d7541948 100644
--- a/networking/udhcp/d6_packet.c
+++ b/networking/udhcp/d6_packet.c
@@ -153,13 +153,15 @@ int FAST_FUNC d6_send_kernel_packet_from_client_data_ifindex(
153 } 153 }
154 setsockopt_reuseaddr(fd); 154 setsockopt_reuseaddr(fd);
155 155
156 memset(&sa, 0, sizeof(sa)); 156 if (src_ipv6) {
157 sa.sin6_family = AF_INET6; 157 memset(&sa, 0, sizeof(sa));
158 sa.sin6_port = htons(source_port); 158 sa.sin6_family = AF_INET6;
159 sa.sin6_addr = *src_ipv6; /* struct copy */ 159 sa.sin6_port = htons(source_port);
160 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { 160 sa.sin6_addr = *src_ipv6; /* struct copy */
161 msg = "bind(%s)"; 161 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
162 goto ret_close; 162 msg = "bind(%s)";
163 goto ret_close;
164 }
163 } 165 }
164 166
165 memset(&sa, 0, sizeof(sa)); 167 memset(&sa, 0, sizeof(sa));
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 2904119e5..b9cbd6464 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -575,29 +575,51 @@ static void send_packet_to_client(struct dhcp_packet *dhcp_pkt, int force_broadc
575 const uint8_t *chaddr; 575 const uint8_t *chaddr;
576 uint32_t ciaddr; 576 uint32_t ciaddr;
577 577
578 // Was: 578 // Logic:
579 //if (force_broadcast) { /* broadcast */ } 579 //if (force_broadcast) { /* broadcast */ }
580 //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ } 580 //else if (dhcp_pkt->ciaddr) { /* unicast to dhcp_pkt->ciaddr */ }
581 // ^^^ dhcp_pkt->ciaddr comes from client's request packet.
582 // We expect such clients to have an UDP socket listening on that IP.
581 //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ } 583 //else if (dhcp_pkt->flags & htons(BROADCAST_FLAG)) { /* broadcast */ }
582 //else { /* unicast to dhcp_pkt->yiaddr */ } 584 //else { /* unicast to dhcp_pkt->yiaddr */ }
583 // But this is wrong: yiaddr is _our_ idea what client's IP is 585 // ^^^ The last case is confusing, but *should* work.
584 // (for example, from lease file). Client may not know that, 586 // It's a case where client have sent a DISCOVER
585 // and may not have UDP socket listening on that IP! 587 // and does not have a kernel UDP socket listening on the IP
586 // We should never unicast to dhcp_pkt->yiaddr! 588 // we are offering in yiaddr (it does not know the IP yet)!
587 // dhcp_pkt->ciaddr, OTOH, comes from client's request packet, 589 // This *should* work because client *should* listen on a raw socket
588 // and can be used. 590 // instead at this time (IOW: it should examine ALL IPv4 packets
589 591 // "by hand", not relying on kernel's UDP stack.)
590 if (force_broadcast 592
591 || (dhcp_pkt->flags & htons(BROADCAST_FLAG)) 593 chaddr = dhcp_pkt->chaddr;
592 || dhcp_pkt->ciaddr == 0 594
595 if (dhcp_pkt->ciaddr == 0
596 || force_broadcast /* sending DHCPNAK pkt? */
593 ) { 597 ) {
594 log1s("broadcasting packet to client"); 598 if (dhcp_pkt->flags & htons(BROADCAST_FLAG)
595 ciaddr = INADDR_BROADCAST; 599 || force_broadcast /* sending DHCPNAK pkt? */
596 chaddr = MAC_BCAST_ADDR; 600 ) {
601// RFC 2131:
602// If 'giaddr' is zero and 'ciaddr' is zero, and the broadcast bit is
603// set, then the server broadcasts DHCPOFFER and DHCPACK messages to
604// 0xffffffff. ...
605// In all cases, when 'giaddr' is zero, the server broadcasts any DHCPNAK
606// messages to 0xffffffff.
607 ciaddr = INADDR_BROADCAST;
608 chaddr = MAC_BCAST_ADDR;
609 log1s("broadcasting packet to client");
610 } else {
611// If the broadcast bit is not set and 'giaddr' is zero and
612// 'ciaddr' is zero, then the server unicasts DHCPOFFER and DHCPACK
613// messages to the client's hardware address and 'yiaddr' address.
614 ciaddr = dhcp_pkt->yiaddr;
615 log1("unicasting packet to client %ciaddr", 'y');
616 }
597 } else { 617 } else {
598 log1s("unicasting packet to client ciaddr"); 618// If the 'giaddr'
619// field is zero and the 'ciaddr' field is nonzero, then the server
620// unicasts DHCPOFFER and DHCPACK messages to the address in 'ciaddr'.
599 ciaddr = dhcp_pkt->ciaddr; 621 ciaddr = dhcp_pkt->ciaddr;
600 chaddr = dhcp_pkt->chaddr; 622 log1("unicasting packet to client %ciaddr", 'c');
601 } 623 }
602 624
603 udhcp_send_raw_packet(dhcp_pkt, 625 udhcp_send_raw_packet(dhcp_pkt,
@@ -624,6 +646,10 @@ static void send_packet_to_relay(struct dhcp_packet *dhcp_pkt)
624static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast) 646static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
625{ 647{
626 if (dhcp_pkt->gateway_nip) 648 if (dhcp_pkt->gateway_nip)
649// RFC 2131:
650// If the 'giaddr' field in a DHCP message from a client is non-zero,
651// the server sends any return messages to the 'DHCP server' port on the
652// BOOTP relay agent whose address appears in 'giaddr'.
627 send_packet_to_relay(dhcp_pkt); 653 send_packet_to_relay(dhcp_pkt);
628 else 654 else
629 send_packet_to_client(dhcp_pkt, force_broadcast); 655 send_packet_to_client(dhcp_pkt, force_broadcast);
diff --git a/runit/chpst.c b/runit/chpst.c
index 2be1a5775..3d04ee50d 100644
--- a/runit/chpst.c
+++ b/runit/chpst.c
@@ -38,7 +38,8 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38//config: bool "setuidgid (4.2 kb)" 38//config: bool "setuidgid (4.2 kb)"
39//config: default y 39//config: default y
40//config: help 40//config: help
41//config: Sets soft resource limits as specified by options 41//config: Sets UID and GID to those of the given account, and execs
42//config: specified program.
42//config: 43//config:
43//config:config ENVUIDGID 44//config:config ENVUIDGID
44//config: bool "envuidgid (4.1 kb)" 45//config: bool "envuidgid (4.1 kb)"
@@ -466,7 +467,8 @@ int chpst_main(int argc UNUSED_PARAM, char **argv)
466 /* nice should be done before xsetuid */ 467 /* nice should be done before xsetuid */
467 if (opt & OPT_n) { 468 if (opt & OPT_n) {
468 errno = 0; 469 errno = 0;
469 if (nice(xatoi(nicestr)) == -1) 470 nice(xatoi(nicestr));
471 if (errno)
470 bb_simple_perror_msg_and_die("nice"); 472 bb_simple_perror_msg_and_die("nice");
471 } 473 }
472 474
diff --git a/scripts/kconfig/libcurses/addch.c b/scripts/kconfig/libcurses/addch.c
index f3c25d389..3d1f9c04b 100644
--- a/scripts/kconfig/libcurses/addch.c
+++ b/scripts/kconfig/libcurses/addch.c
@@ -90,23 +90,25 @@ addch
90 All functions return OK on success and ERR on error. 90 All functions return OK on success and ERR on error.
91 91
92### Portability 92### Portability
93 X/Open ncurses NetBSD 93
94 addch Y Y Y 94 Function | X/Open | ncurses | NetBSD
95 waddch Y Y Y 95 :---------------------|:------:|:-------:|:------:
96 mvaddch Y Y Y 96 addch | Y | Y | Y
97 mvwaddch Y Y Y 97 waddch | Y | Y | Y
98 echochar Y Y Y 98 mvaddch | Y | Y | Y
99 wechochar Y Y Y 99 mvwaddch | Y | Y | Y
100 add_wch Y Y Y 100 echochar | Y | Y | Y
101 wadd_wch Y Y Y 101 wechochar | Y | Y | Y
102 mvadd_wch Y Y Y 102 add_wch | Y | Y | Y
103 mvwadd_wch Y Y Y 103 wadd_wch | Y | Y | Y
104 echo_wchar Y Y Y 104 mvadd_wch | Y | Y | Y
105 wecho_wchar Y Y Y 105 mvwadd_wch | Y | Y | Y
106 addrawch - - - 106 echo_wchar | Y | Y | Y
107 waddrawch - - - 107 wecho_wchar | Y | Y | Y
108 mvaddrawch - - - 108 addrawch | - | - | -
109 mvwaddrawch - - - 109 waddrawch | - | - | -
110 mvaddrawch | - | - | -
111 mvwaddrawch | - | - | -
110 112
111**man-end****************************************************************/ 113**man-end****************************************************************/
112 114
diff --git a/scripts/kconfig/libcurses/addstr.c b/scripts/kconfig/libcurses/addstr.c
index 47f8f4e10..bc286d4b5 100644
--- a/scripts/kconfig/libcurses/addstr.c
+++ b/scripts/kconfig/libcurses/addstr.c
@@ -43,23 +43,25 @@ addstr
43 All functions return OK or ERR. 43 All functions return OK or ERR.
44 44
45### Portability 45### Portability
46 X/Open ncurses NetBSD 46
47 addstr Y Y Y 47 Function | X/Open | ncurses | NetBSD
48 waddstr Y Y Y 48 :---------------------|:------:|:-------:|:------:
49 mvaddstr Y Y Y 49 addstr | Y | Y | Y
50 mvwaddstr Y Y Y 50 waddstr | Y | Y | Y
51 addnstr Y Y Y 51 mvaddstr | Y | Y | Y
52 waddnstr Y Y Y 52 mvwaddstr | Y | Y | Y
53 mvaddnstr Y Y Y 53 addnstr | Y | Y | Y
54 mvwaddnstr Y Y Y 54 waddnstr | Y | Y | Y
55 addwstr Y Y Y 55 mvaddnstr | Y | Y | Y
56 waddwstr Y Y Y 56 mvwaddnstr | Y | Y | Y
57 mvaddwstr Y Y Y 57 addwstr | Y | Y | Y
58 mvwaddwstr Y Y Y 58 waddwstr | Y | Y | Y
59 addnwstr Y Y Y 59 mvaddwstr | Y | Y | Y
60 waddnwstr Y Y Y 60 mvwaddwstr | Y | Y | Y
61 mvaddnwstr Y Y Y 61 addnwstr | Y | Y | Y
62 mvwaddnwstr Y Y Y 62 waddnwstr | Y | Y | Y
63 mvaddnwstr | Y | Y | Y
64 mvwaddnwstr | Y | Y | Y
63 65
64**man-end****************************************************************/ 66**man-end****************************************************************/
65 67
diff --git a/scripts/kconfig/libcurses/attr.c b/scripts/kconfig/libcurses/attr.c
index 3ab5a5637..d7bc36c73 100644
--- a/scripts/kconfig/libcurses/attr.c
+++ b/scripts/kconfig/libcurses/attr.c
@@ -96,36 +96,38 @@ attr
96 All functions return OK on success and ERR on error. 96 All functions return OK on success and ERR on error.
97 97
98### Portability 98### Portability
99 X/Open ncurses NetBSD 99
100 attroff Y Y Y 100 Function | X/Open | ncurses | NetBSD
101 wattroff Y Y Y 101 :---------------------|:------:|:-------:|:------:
102 attron Y Y Y 102 attroff | Y | Y | Y
103 wattron Y Y Y 103 wattroff | Y | Y | Y
104 attrset Y Y Y 104 attron | Y | Y | Y
105 wattrset Y Y Y 105 wattron | Y | Y | Y
106 standend Y Y Y 106 attrset | Y | Y | Y
107 wstandend Y Y Y 107 wattrset | Y | Y | Y
108 standout Y Y Y 108 standend | Y | Y | Y
109 wstandout Y Y Y 109 wstandend | Y | Y | Y
110 color_set Y Y Y 110 standout | Y | Y | Y
111 wcolor_set Y Y Y 111 wstandout | Y | Y | Y
112 attr_get Y Y Y 112 color_set | Y | Y | Y
113 wattr_get Y Y Y 113 wcolor_set | Y | Y | Y
114 attr_on Y Y Y 114 attr_get | Y | Y | Y
115 wattr_on Y Y Y 115 wattr_get | Y | Y | Y
116 attr_off Y Y Y 116 attr_on | Y | Y | Y
117 wattr_off Y Y Y 117 wattr_on | Y | Y | Y
118 attr_set Y Y Y 118 attr_off | Y | Y | Y
119 wattr_set Y Y Y 119 wattr_off | Y | Y | Y
120 chgat Y Y Y 120 attr_set | Y | Y | Y
121 wchgat Y Y Y 121 wattr_set | Y | Y | Y
122 mvchgat Y Y Y 122 chgat | Y | Y | Y
123 mvwchgat Y Y Y 123 wchgat | Y | Y | Y
124 getattrs - Y Y 124 mvchgat | Y | Y | Y
125 underend - - Y 125 mvwchgat | Y | Y | Y
126 wunderend - - Y 126 getattrs | - | Y | Y
127 underscore - - Y 127 underend | - | - | Y
128 wunderscore - - Y 128 wunderend | - | - | Y
129 underscore | - | - | Y
130 wunderscore | - | - | Y
129 131
130**man-end****************************************************************/ 132**man-end****************************************************************/
131 133
diff --git a/scripts/kconfig/libcurses/beep.c b/scripts/kconfig/libcurses/beep.c
index 0b97137fd..b679eed3c 100644
--- a/scripts/kconfig/libcurses/beep.c
+++ b/scripts/kconfig/libcurses/beep.c
@@ -26,9 +26,11 @@ beep
26 These functions return ERR if called before initscr(), otherwise OK. 26 These functions return ERR if called before initscr(), otherwise OK.
27 27
28### Portability 28### Portability
29 X/Open ncurses NetBSD 29
30 beep Y Y Y 30 Function | X/Open | ncurses | NetBSD
31 flash Y Y Y 31 :---------------------|:------:|:-------:|:------:
32 beep | Y | Y | Y
33 flash | Y | Y | Y
32 34
33**man-end****************************************************************/ 35**man-end****************************************************************/
34 36
diff --git a/scripts/kconfig/libcurses/bkgd.c b/scripts/kconfig/libcurses/bkgd.c
index af2d0e054..c92df28be 100644
--- a/scripts/kconfig/libcurses/bkgd.c
+++ b/scripts/kconfig/libcurses/bkgd.c
@@ -48,18 +48,20 @@ bkgd
48 case they return ERR. 48 case they return ERR.
49 49
50### Portability 50### Portability
51 X/Open ncurses NetBSD 51
52 bkgd Y Y Y 52 Function | X/Open | ncurses | NetBSD
53 bkgdset Y Y Y 53 :---------------------|:------:|:-------:|:------:
54 getbkgd Y Y Y 54 bkgd | Y | Y | Y
55 wbkgd Y Y Y 55 bkgdset | Y | Y | Y
56 wbkgdset Y Y Y 56 getbkgd | Y | Y | Y
57 bkgrnd Y Y Y 57 wbkgd | Y | Y | Y
58 bkgrndset Y Y Y 58 wbkgdset | Y | Y | Y
59 getbkgrnd Y Y Y 59 bkgrnd | Y | Y | Y
60 wbkgrnd Y Y Y 60 bkgrndset | Y | Y | Y
61 wbkgrndset Y Y Y 61 getbkgrnd | Y | Y | Y
62 wgetbkgrnd Y Y Y 62 wbkgrnd | Y | Y | Y
63 wbkgrndset | Y | Y | Y
64 wgetbkgrnd | Y | Y | Y
63 65
64**man-end****************************************************************/ 66**man-end****************************************************************/
65 67
diff --git a/scripts/kconfig/libcurses/border.c b/scripts/kconfig/libcurses/border.c
index 302c46ea2..409f2351a 100644
--- a/scripts/kconfig/libcurses/border.c
+++ b/scripts/kconfig/libcurses/border.c
@@ -46,14 +46,16 @@ border
46 border(), wborder(), and box() draw a border around the edge of the 46 border(), wborder(), and box() draw a border around the edge of the
47 window. If any argument is zero, an appropriate default is used: 47 window. If any argument is zero, an appropriate default is used:
48 48
49 ls left side of border ACS_VLINE 49 Name | Element | Default
50 rs right side of border ACS_VLINE 50 :----|:------------------------------|:------------
51 ts top side of border ACS_HLINE 51 ls | left side of border | ACS_VLINE
52 bs bottom side of border ACS_HLINE 52 rs | right side of border | ACS_VLINE
53 tl top left corner of border ACS_ULCORNER 53 ts | top side of border | ACS_HLINE
54 tr top right corner of border ACS_URCORNER 54 bs | bottom side of border | ACS_HLINE
55 bl bottom left corner of border ACS_LLCORNER 55 tl | top left corner of border | ACS_ULCORNER
56 br bottom right corner of border ACS_LRCORNER 56 tr | top right corner of border | ACS_URCORNER
57 bl | bottom left corner of border | ACS_LLCORNER
58 br | bottom right corner of border | ACS_LRCORNER
57 59
58 hline() and whline() draw a horizontal line, using ch, starting from 60 hline() and whline() draw a horizontal line, using ch, starting from
59 the current cursor position. The cursor position does not change. The 61 the current cursor position. The cursor position does not change. The
@@ -74,29 +76,31 @@ border
74 These functions return OK on success and ERR on error. 76 These functions return OK on success and ERR on error.
75 77
76### Portability 78### Portability
77 X/Open ncurses NetBSD 79
78 border Y Y Y 80 Function | X/Open | ncurses | NetBSD
79 wborder Y Y Y 81 :---------------------|:------:|:-------:|:------:
80 box Y Y Y 82 border | Y | Y | Y
81 hline Y Y Y 83 wborder | Y | Y | Y
82 vline Y Y Y 84 box | Y | Y | Y
83 whline Y Y Y 85 hline | Y | Y | Y
84 wvline Y Y Y 86 vline | Y | Y | Y
85 mvhline Y Y Y 87 whline | Y | Y | Y
86 mvvline Y Y Y 88 wvline | Y | Y | Y
87 mvwhline Y Y Y 89 mvhline | Y | Y | Y
88 mvwvline Y Y Y 90 mvvline | Y | Y | Y
89 border_set Y Y Y 91 mvwhline | Y | Y | Y
90 wborder_set Y Y Y 92 mvwvline | Y | Y | Y
91 box_set Y Y Y 93 border_set | Y | Y | Y
92 hline_set Y Y Y 94 wborder_set | Y | Y | Y
93 vline_set Y Y Y 95 box_set | Y | Y | Y
94 whline_set Y Y Y 96 hline_set | Y | Y | Y
95 wvline_set Y Y Y 97 vline_set | Y | Y | Y
96 mvhline_set Y Y Y 98 whline_set | Y | Y | Y
97 mvvline_set Y Y Y 99 wvline_set | Y | Y | Y
98 mvwhline_set Y Y Y 100 mvhline_set | Y | Y | Y
99 mvwvline_set Y Y Y 101 mvvline_set | Y | Y | Y
102 mvwhline_set | Y | Y | Y
103 mvwvline_set | Y | Y | Y
100 104
101**man-end****************************************************************/ 105**man-end****************************************************************/
102 106
diff --git a/scripts/kconfig/libcurses/clear.c b/scripts/kconfig/libcurses/clear.c
index acb8edf81..e10b321c3 100644
--- a/scripts/kconfig/libcurses/clear.c
+++ b/scripts/kconfig/libcurses/clear.c
@@ -38,15 +38,17 @@ clear
38 All functions return OK on success and ERR on error. 38 All functions return OK on success and ERR on error.
39 39
40### Portability 40### Portability
41 X/Open ncurses NetBSD 41
42 clear Y Y Y 42 Function | X/Open | ncurses | NetBSD
43 wclear Y Y Y 43 :---------------------|:------:|:-------:|:------:
44 erase Y Y Y 44 clear | Y | Y | Y
45 werase Y Y Y 45 wclear | Y | Y | Y
46 clrtobot Y Y Y 46 erase | Y | Y | Y
47 wclrtobot Y Y Y 47 werase | Y | Y | Y
48 clrtoeol Y Y Y 48 clrtobot | Y | Y | Y
49 wclrtoeol Y Y Y 49 wclrtobot | Y | Y | Y
50 clrtoeol | Y | Y | Y
51 wclrtoeol | Y | Y | Y
50 52
51**man-end****************************************************************/ 53**man-end****************************************************************/
52 54
diff --git a/scripts/kconfig/libcurses/color.c b/scripts/kconfig/libcurses/color.c
index 3335ae082..372dad948 100644
--- a/scripts/kconfig/libcurses/color.c
+++ b/scripts/kconfig/libcurses/color.c
@@ -92,20 +92,22 @@ color
92 find_pair() return a pair number, or -1 on error. 92 find_pair() return a pair number, or -1 on error.
93 93
94### Portability 94### Portability
95 X/Open ncurses NetBSD 95
96 has_colors Y Y Y 96 Function | X/Open | ncurses | NetBSD
97 start_color Y Y Y 97 :---------------------|:------:|:-------:|:------:
98 init_pair Y Y Y 98 has_colors | Y | Y | Y
99 pair_content Y Y Y 99 start_color | Y | Y | Y
100 can_change_color Y Y Y 100 init_pair | Y | Y | Y
101 init_color Y Y Y 101 pair_content | Y | Y | Y
102 color_content Y Y Y 102 can_change_color | Y | Y | Y
103 alloc_pair - Y - 103 init_color | Y | Y | Y
104 assume_default_colors - Y Y 104 color_content | Y | Y | Y
105 find_pair - Y - 105 alloc_pair | - | Y | -
106 free_pair - Y - 106 assume_default_colors | - | Y | Y
107 use_default_colors - Y Y 107 find_pair | - | Y | -
108 PDC_set_line_color - - - 108 free_pair | - | Y | -
109 use_default_colors | - | Y | Y
110 PDC_set_line_color | - | - | -
109 111
110**man-end****************************************************************/ 112**man-end****************************************************************/
111 113
diff --git a/scripts/kconfig/libcurses/curses.h b/scripts/kconfig/libcurses/curses.h
index e4ba3776a..f58fe66df 100644
--- a/scripts/kconfig/libcurses/curses.h
+++ b/scripts/kconfig/libcurses/curses.h
@@ -9,26 +9,28 @@
9 9
10Define before inclusion (only those needed): 10Define before inclusion (only those needed):
11 11
12 XCURSES if building / built for X11 12 Macro | Meaning / value
13 PDC_RGB if you want to use RGB color definitions 13 :-------------|-------------------------------------------------
14 (Red = 1, Green = 2, Blue = 4) instead of BGR 14 XCURSES | if building / built for X11
15 PDC_WIDE if building / built with wide-character support 15 PDC_RGB | RGB color (Red = 1, Green = 2, Blue = 4) vs. BGR
16 PDC_DLL_BUILD if building / built as a Windows DLL 16 PDC_WIDE | if building / built with wide-character support
17 PDC_NCMOUSE to use the ncurses mouse API instead 17 PDC_DLL_BUILD | if building / built as a Windows DLL
18 of PDCurses' traditional mouse API 18 PDC_NCMOUSE | use ncurses mouse API vs. traditional PDCurses
19 19
20Defined by this header: 20Defined by this header:
21 21
22 PDCURSES PDCurses-only features are available 22 Macro | Meaning / value
23 PDC_BUILD API build version 23 :-------------|-------------------------------------------------
24 PDC_VER_MAJOR major version number 24 PDCURSES | PDCurses-only features are available
25 PDC_VER_MINOR minor version number 25 PDC_BUILD | API build version
26 PDC_VERDOT version string 26 PDC_VER_MAJOR | major version number
27 PDC_VER_MINOR | minor version number
28 PDC_VERDOT | version string
27 29
28**man-end****************************************************************/ 30**man-end****************************************************************/
29 31
30#define PDCURSES 1 32#define PDCURSES 1
31#define PDC_BUILD 3907 33#define PDC_BUILD 3908
32#define PDC_VER_MAJOR 3 34#define PDC_VER_MAJOR 3
33#define PDC_VER_MINOR 9 35#define PDC_VER_MINOR 9
34#define PDC_VERDOT "3.9" 36#define PDC_VERDOT "3.9"
@@ -420,10 +422,9 @@ Text Attributes
420 422
421PDCurses uses a 32-bit integer for its chtype: 423PDCurses uses a 32-bit integer for its chtype:
422 424
423 +--------------------------------------------------------------------+ 425 color pair | modifiers | character eg 'a'
424 |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|..| 2| 1| 0| 426 -----------------------|-----------------------|--------------------
425 +--------------------------------------------------------------------+ 427 31 30 29 28 27 26 25 24|23 22 21 20 19 18 17 16|15 14 13 .. 2 1 0
426 color pair | modifiers | character eg 'a'
427 428
428There are 256 color pairs (8 bits), 8 bits for modifiers, and 16 bits 429There are 256 color pairs (8 bits), 8 bits for modifiers, and 16 bits
429for character data. The modifiers are bold, underline, right-line, 430for character data. The modifiers are bold, underline, right-line,
diff --git a/scripts/kconfig/libcurses/getch.c b/scripts/kconfig/libcurses/getch.c
index 8719ca39c..9d771ec0e 100644
--- a/scripts/kconfig/libcurses/getch.c
+++ b/scripts/kconfig/libcurses/getch.c
@@ -75,19 +75,21 @@ getch
75 character or function key token. 75 character or function key token.
76 76
77### Portability 77### Portability
78 X/Open ncurses NetBSD 78
79 getch Y Y Y 79 Function | X/Open | ncurses | NetBSD
80 wgetch Y Y Y 80 :---------------------|:------:|:-------:|:------:
81 mvgetch Y Y Y 81 getch | Y | Y | Y
82 mvwgetch Y Y Y 82 wgetch | Y | Y | Y
83 ungetch Y Y Y 83 mvgetch | Y | Y | Y
84 flushinp Y Y Y 84 mvwgetch | Y | Y | Y
85 get_wch Y Y Y 85 ungetch | Y | Y | Y
86 wget_wch Y Y Y 86 flushinp | Y | Y | Y
87 mvget_wch Y Y Y 87 get_wch | Y | Y | Y
88 mvwget_wch Y Y Y 88 wget_wch | Y | Y | Y
89 unget_wch Y Y Y 89 mvget_wch | Y | Y | Y
90 PDC_get_key_modifiers - - - 90 mvwget_wch | Y | Y | Y
91 unget_wch | Y | Y | Y
92 PDC_get_key_modifiers | - | - | -
91 93
92**man-end****************************************************************/ 94**man-end****************************************************************/
93 95
diff --git a/scripts/kconfig/libcurses/getyx.c b/scripts/kconfig/libcurses/getyx.c
index 5f104df99..6aa894ed0 100644
--- a/scripts/kconfig/libcurses/getyx.c
+++ b/scripts/kconfig/libcurses/getyx.c
@@ -54,21 +54,23 @@ getyx
54 values, or ERR in the case of a NULL window. 54 values, or ERR in the case of a NULL window.
55 55
56### Portability 56### Portability
57 X/Open ncurses NetBSD 57
58 getyx Y Y Y 58 Function | X/Open | ncurses | NetBSD
59 getparyx Y Y Y 59 :---------------------|:------:|:-------:|:------:
60 getbegyx Y Y Y 60 getyx | Y | Y | Y
61 getmaxyx Y Y Y 61 getparyx | Y | Y | Y
62 getsyx - Y Y 62 getbegyx | Y | Y | Y
63 setsyx - Y Y 63 getmaxyx | Y | Y | Y
64 getbegy - Y Y 64 getsyx | - | Y | Y
65 getbegx - Y Y 65 setsyx | - | Y | Y
66 getcury - Y Y 66 getbegy | - | Y | Y
67 getcurx - Y Y 67 getbegx | - | Y | Y
68 getpary - Y Y 68 getcury | - | Y | Y
69 getparx - Y Y 69 getcurx | - | Y | Y
70 getmaxy - Y Y 70 getpary | - | Y | Y
71 getmaxx - Y Y 71 getparx | - | Y | Y
72 getmaxy | - | Y | Y
73 getmaxx | - | Y | Y
72 74
73**man-end****************************************************************/ 75**man-end****************************************************************/
74 76
diff --git a/scripts/kconfig/libcurses/inch.c b/scripts/kconfig/libcurses/inch.c
index 2bd4430f6..28b57e222 100644
--- a/scripts/kconfig/libcurses/inch.c
+++ b/scripts/kconfig/libcurses/inch.c
@@ -31,15 +31,17 @@ inch
31 returned.) Note that in PDCurses, chtype and cchar_t are the same. 31 returned.) Note that in PDCurses, chtype and cchar_t are the same.
32 32
33### Portability 33### Portability
34 X/Open ncurses NetBSD 34
35 inch Y Y Y 35 Function | X/Open | ncurses | NetBSD
36 winch Y Y Y 36 :---------------------|:------:|:-------:|:------:
37 mvinch Y Y Y 37 inch | Y | Y | Y
38 mvwinch Y Y Y 38 winch | Y | Y | Y
39 in_wch Y Y Y 39 mvinch | Y | Y | Y
40 win_wch Y Y Y 40 mvwinch | Y | Y | Y
41 mvin_wch Y Y Y 41 in_wch | Y | Y | Y
42 mvwin_wch Y Y Y 42 win_wch | Y | Y | Y
43 mvin_wch | Y | Y | Y
44 mvwin_wch | Y | Y | Y
43 45
44**man-end****************************************************************/ 46**man-end****************************************************************/
45 47
diff --git a/scripts/kconfig/libcurses/initscr.c b/scripts/kconfig/libcurses/initscr.c
index 66940a3cf..a4208642a 100644
--- a/scripts/kconfig/libcurses/initscr.c
+++ b/scripts/kconfig/libcurses/initscr.c
@@ -83,17 +83,19 @@ initscr
83 returns OK, and resize_term(), which returns either OK or ERR. 83 returns OK, and resize_term(), which returns either OK or ERR.
84 84
85### Portability 85### Portability
86 X/Open ncurses NetBSD 86
87 initscr Y Y Y 87 Function | X/Open | ncurses | NetBSD
88 endwin Y Y Y 88 :---------------------|:------:|:-------:|:------:
89 isendwin Y Y Y 89 initscr | Y | Y | Y
90 newterm Y Y Y 90 endwin | Y | Y | Y
91 set_term Y Y Y 91 isendwin | Y | Y | Y
92 delscreen Y Y Y 92 newterm | Y | Y | Y
93 resize_term - Y Y 93 set_term | Y | Y | Y
94 set_tabsize - Y Y 94 delscreen | Y | Y | Y
95 curses_version - Y - 95 resize_term | - | Y | Y
96 is_termresized - - - 96 set_tabsize | - | Y | Y
97 curses_version | - | Y | -
98 is_termresized | - | - | -
97 99
98**man-end****************************************************************/ 100**man-end****************************************************************/
99 101
diff --git a/scripts/kconfig/libcurses/inopts.c b/scripts/kconfig/libcurses/inopts.c
index 30e18f611..a1c4b49f8 100644
--- a/scripts/kconfig/libcurses/inopts.c
+++ b/scripts/kconfig/libcurses/inopts.c
@@ -106,32 +106,34 @@ inopts
106 always returns FALSE. All others return OK on success and ERR on error. 106 always returns FALSE. All others return OK on success and ERR on error.
107 107
108### Portability 108### Portability
109 X/Open ncurses NetBSD 109
110 cbreak Y Y Y 110 Function | X/Open | ncurses | NetBSD
111 nocbreak Y Y Y 111 :---------------------|:------:|:-------:|:------:
112 echo Y Y Y 112 cbreak | Y | Y | Y
113 noecho Y Y Y 113 nocbreak | Y | Y | Y
114 halfdelay Y Y Y 114 echo | Y | Y | Y
115 intrflush Y Y Y 115 noecho | Y | Y | Y
116 keypad Y Y Y 116 halfdelay | Y | Y | Y
117 meta Y Y Y 117 intrflush | Y | Y | Y
118 nl Y Y Y 118 keypad | Y | Y | Y
119 nonl Y Y Y 119 meta | Y | Y | Y
120 nodelay Y Y Y 120 nl | Y | Y | Y
121 notimeout Y Y Y 121 nonl | Y | Y | Y
122 raw Y Y Y 122 nodelay | Y | Y | Y
123 noraw Y Y Y 123 notimeout | Y | Y | Y
124 noqiflush Y Y Y 124 raw | Y | Y | Y
125 qiflush Y Y Y 125 noraw | Y | Y | Y
126 timeout Y Y Y 126 noqiflush | Y | Y | Y
127 wtimeout Y Y Y 127 qiflush | Y | Y | Y
128 wgetdelay - Y - 128 timeout | Y | Y | Y
129 typeahead Y Y Y 129 wtimeout | Y | Y | Y
130 crmode Y Y Y 130 wgetdelay | - | Y | -
131 nocrmode Y Y Y 131 typeahead | Y | Y | Y
132 is_keypad - Y Y 132 crmode | Y | Y | Y
133 is_nodelay - Y - 133 nocrmode | Y | Y | Y
134 is_notimeout - Y - 134 is_keypad | - | Y | Y
135 is_nodelay | - | Y | -
136 is_notimeout | - | Y | -
135 137
136**man-end****************************************************************/ 138**man-end****************************************************************/
137 139
diff --git a/scripts/kconfig/libcurses/kernel.c b/scripts/kconfig/libcurses/kernel.c
index afb2d0661..0f5a73c21 100644
--- a/scripts/kconfig/libcurses/kernel.c
+++ b/scripts/kconfig/libcurses/kernel.c
@@ -71,20 +71,22 @@ kernel
71 curs_set(), which returns the previous visibility. 71 curs_set(), which returns the previous visibility.
72 72
73### Portability 73### Portability
74 X/Open ncurses NetBSD 74
75 def_prog_mode Y Y Y 75 Function | X/Open | ncurses | NetBSD
76 def_shell_mode Y Y Y 76 :---------------------|:------:|:-------:|:------:
77 reset_prog_mode Y Y Y 77 def_prog_mode | Y | Y | Y
78 reset_shell_mode Y Y Y 78 def_shell_mode | Y | Y | Y
79 resetty Y Y Y 79 reset_prog_mode | Y | Y | Y
80 savetty Y Y Y 80 reset_shell_mode | Y | Y | Y
81 ripoffline Y Y Y 81 resetty | Y | Y | Y
82 curs_set Y Y Y 82 savetty | Y | Y | Y
83 napms Y Y Y 83 ripoffline | Y | Y | Y
84 fixterm - Y - 84 curs_set | Y | Y | Y
85 resetterm - Y - 85 napms | Y | Y | Y
86 saveterm - Y - 86 fixterm | - | Y | -
87 draino - - - 87 resetterm | - | Y | -
88 saveterm | - | Y | -
89 draino | - | - | -
88 90
89**man-end****************************************************************/ 91**man-end****************************************************************/
90 92
diff --git a/scripts/kconfig/libcurses/move.c b/scripts/kconfig/libcurses/move.c
index 96496445e..38db1d19a 100644
--- a/scripts/kconfig/libcurses/move.c
+++ b/scripts/kconfig/libcurses/move.c
@@ -28,10 +28,12 @@ move
28 All functions return OK on success and ERR on error. 28 All functions return OK on success and ERR on error.
29 29
30### Portability 30### Portability
31 X/Open ncurses NetBSD 31
32 move Y Y Y 32 Function | X/Open | ncurses | NetBSD
33 mvcur Y Y Y 33 :---------------------|:------:|:-------:|:------:
34 wmove Y Y Y 34 move | Y | Y | Y
35 mvcur | Y | Y | Y
36 wmove | Y | Y | Y
35 37
36**man-end****************************************************************/ 38**man-end****************************************************************/
37 39
diff --git a/scripts/kconfig/libcurses/outopts.c b/scripts/kconfig/libcurses/outopts.c
index e0a55e437..4c8950959 100644
--- a/scripts/kconfig/libcurses/outopts.c
+++ b/scripts/kconfig/libcurses/outopts.c
@@ -75,23 +75,25 @@ outopts
75 return OK on success and ERR on error. 75 return OK on success and ERR on error.
76 76
77### Portability 77### Portability
78 X/Open ncurses NetBSD 78
79 clearok Y Y Y 79 Function | X/Open | ncurses | NetBSD
80 idlok Y Y Y 80 :---------------------|:------:|:-------:|:------:
81 idcok Y Y Y 81 clearok | Y | Y | Y
82 immedok Y Y Y 82 idlok | Y | Y | Y
83 leaveok Y Y Y 83 idcok | Y | Y | Y
84 setscrreg Y Y Y 84 immedok | Y | Y | Y
85 wsetscrreg Y Y Y 85 leaveok | Y | Y | Y
86 wgetscrreg - Y - 86 setscrreg | Y | Y | Y
87 scrollok Y Y Y 87 wsetscrreg | Y | Y | Y
88 is_cleared - Y - 88 wgetscrreg | - | Y | -
89 is_idlok - Y - 89 scrollok | Y | Y | Y
90 is_idcok - Y - 90 is_cleared | - | Y | -
91 is_immedok - Y - 91 is_idlok | - | Y | -
92 is_leaveok - Y Y 92 is_idcok | - | Y | -
93 is_scrollok - Y - 93 is_immedok | - | Y | -
94 raw_output - - - 94 is_leaveok | - | Y | Y
95 is_scrollok | - | Y | -
96 raw_output | - | - | -
95 97
96**man-end****************************************************************/ 98**man-end****************************************************************/
97 99
diff --git a/scripts/kconfig/libcurses/overlay.c b/scripts/kconfig/libcurses/overlay.c
index ae1903da8..75a93d83c 100644
--- a/scripts/kconfig/libcurses/overlay.c
+++ b/scripts/kconfig/libcurses/overlay.c
@@ -39,10 +39,12 @@ overlay
39 All functions return OK on success and ERR on error. 39 All functions return OK on success and ERR on error.
40 40
41### Portability 41### Portability
42 X/Open ncurses NetBSD 42
43 overlay Y Y Y 43 Function | X/Open | ncurses | NetBSD
44 overwrite Y Y Y 44 :---------------------|:------:|:-------:|:------:
45 copywin Y Y Y 45 overlay | Y | Y | Y
46 overwrite | Y | Y | Y
47 copywin | Y | Y | Y
46 48
47**man-end****************************************************************/ 49**man-end****************************************************************/
48 50
diff --git a/scripts/kconfig/libcurses/pad.c b/scripts/kconfig/libcurses/pad.c
index 3dfdfe5d6..8b44dabd4 100644
--- a/scripts/kconfig/libcurses/pad.c
+++ b/scripts/kconfig/libcurses/pad.c
@@ -62,14 +62,16 @@ pad
62 All functions except is_pad() return OK on success and ERR on error. 62 All functions except is_pad() return OK on success and ERR on error.
63 63
64### Portability 64### Portability
65 X/Open ncurses NetBSD 65
66 newpad Y Y Y 66 Function | X/Open | ncurses | NetBSD
67 subpad Y Y Y 67 :---------------------|:------:|:-------:|:------:
68 prefresh Y Y Y 68 newpad | Y | Y | Y
69 pnoutrefresh Y Y Y 69 subpad | Y | Y | Y
70 pechochar Y Y Y 70 prefresh | Y | Y | Y
71 pecho_wchar Y Y Y 71 pnoutrefresh | Y | Y | Y
72 is_pad - Y Y 72 pechochar | Y | Y | Y
73 pecho_wchar | Y | Y | Y
74 is_pad | - | Y | Y
73 75
74**man-end****************************************************************/ 76**man-end****************************************************************/
75 77
diff --git a/scripts/kconfig/libcurses/pdcclip.c b/scripts/kconfig/libcurses/pdcclip.c
index 740221280..6184ad2d9 100644
--- a/scripts/kconfig/libcurses/pdcclip.c
+++ b/scripts/kconfig/libcurses/pdcclip.c
@@ -24,26 +24,27 @@ clipboard
24 memory returned, via PDC_freeclipboard(). The length of the clipboard 24 memory returned, via PDC_freeclipboard(). The length of the clipboard
25 contents is returned in the length argument. 25 contents is returned in the length argument.
26 26
27 PDC_setclipboard copies the supplied text into the system's 27 PDC_setclipboard() copies the supplied text into the system's
28 clipboard, emptying the clipboard prior to the copy. 28 clipboard, emptying the clipboard prior to the copy.
29 29
30 PDC_clearclipboard() clears the internal clipboard. 30 PDC_clearclipboard() clears the internal clipboard.
31 31
32### Return Values 32### Return Values
33 33
34 indicator of success/failure of call. 34 PDC_CLIP_SUCCESS the call was successful
35 PDC_CLIP_SUCCESS the call was successful 35 PDC_CLIP_MEMORY_ERROR unable to allocate sufficient memory for
36 PDC_CLIP_MEMORY_ERROR unable to allocate sufficient memory for 36 the clipboard contents
37 the clipboard contents 37 PDC_CLIP_EMPTY the clipboard contains no text
38 PDC_CLIP_EMPTY the clipboard contains no text 38 PDC_CLIP_ACCESS_ERROR no clipboard support
39 PDC_CLIP_ACCESS_ERROR no clipboard support
40 39
41### Portability 40### Portability
42 X/Open ncurses NetBSD 41
43 PDC_getclipboard - - - 42 Function | X/Open | ncurses | NetBSD
44 PDC_setclipboard - - - 43 :---------------------|:------:|:-------:|:------:
45 PDC_freeclipboard - - - 44 PDC_getclipboard | - | - | -
46 PDC_clearclipboard - - - 45 PDC_setclipboard | - | - | -
46 PDC_freeclipboard | - | - | -
47 PDC_clearclipboard | - | - | -
47 48
48**man-end****************************************************************/ 49**man-end****************************************************************/
49 50
@@ -143,7 +144,12 @@ int PDC_clearclipboard(void)
143{ 144{
144 PDC_LOG(("PDC_clearclipboard() - called\n")); 145 PDC_LOG(("PDC_clearclipboard() - called\n"));
145 146
146 EmptyClipboard(); 147 if (OpenClipboard(NULL))
148 if (EmptyClipboard())
149 {
150 CloseClipboard();
151 return PDC_CLIP_SUCCESS;
152 }
147 153
148 return PDC_CLIP_SUCCESS; 154 return PDC_CLIP_ACCESS_ERROR;
149} 155}
diff --git a/scripts/kconfig/libcurses/pdcsetsc.c b/scripts/kconfig/libcurses/pdcsetsc.c
index a2d1b6dc3..1e9fc9b0d 100644
--- a/scripts/kconfig/libcurses/pdcsetsc.c
+++ b/scripts/kconfig/libcurses/pdcsetsc.c
@@ -31,9 +31,12 @@ pdcsetsc
31 platforms. 31 platforms.
32 32
33### Portability 33### Portability
34 X/Open ncurses NetBSD 34
35 PDC_set_blink - - - 35 Function | X/Open | ncurses | NetBSD
36 PDC_set_title - - - 36 :---------------------|:------:|:-------:|:------:
37 PDC_set_blink | - | - | -
38 PDC_set_bold | - | - | -
39 PDC_set_title | - | - | -
37 40
38**man-end****************************************************************/ 41**man-end****************************************************************/
39 42
diff --git a/scripts/kconfig/libcurses/printw.c b/scripts/kconfig/libcurses/printw.c
index 38e7fd112..a753638a5 100644
--- a/scripts/kconfig/libcurses/printw.c
+++ b/scripts/kconfig/libcurses/printw.c
@@ -32,13 +32,15 @@ printw
32 error. 32 error.
33 33
34### Portability 34### Portability
35 X/Open ncurses NetBSD 35
36 printw Y Y Y 36 Function | X/Open | ncurses | NetBSD
37 wprintw Y Y Y 37 :---------------------|:------:|:-------:|:------:
38 mvprintw Y Y Y 38 printw | Y | Y | Y
39 mvwprintw Y Y Y 39 wprintw | Y | Y | Y
40 vwprintw Y Y Y 40 mvprintw | Y | Y | Y
41 vw_printw Y Y Y 41 mvwprintw | Y | Y | Y
42 vwprintw | Y | Y | Y
43 vw_printw | Y | Y | Y
42 44
43**man-end****************************************************************/ 45**man-end****************************************************************/
44 46
diff --git a/scripts/kconfig/libcurses/refresh.c b/scripts/kconfig/libcurses/refresh.c
index 306f4efb3..1dce414e5 100644
--- a/scripts/kconfig/libcurses/refresh.c
+++ b/scripts/kconfig/libcurses/refresh.c
@@ -45,13 +45,15 @@ refresh
45 All functions return OK on success and ERR on error. 45 All functions return OK on success and ERR on error.
46 46
47### Portability 47### Portability
48 X/Open ncurses NetBSD 48
49 refresh Y Y Y 49 Function | X/Open | ncurses | NetBSD
50 wrefresh Y Y Y 50 :---------------------|:------:|:-------:|:------:
51 wnoutrefresh Y Y Y 51 refresh | Y | Y | Y
52 doupdate Y Y Y 52 wrefresh | Y | Y | Y
53 redrawwin Y Y Y 53 wnoutrefresh | Y | Y | Y
54 wredrawln Y Y Y 54 doupdate | Y | Y | Y
55 redrawwin | Y | Y | Y
56 wredrawln | Y | Y | Y
55 57
56**man-end****************************************************************/ 58**man-end****************************************************************/
57 59
diff --git a/scripts/kconfig/libcurses/scroll.c b/scripts/kconfig/libcurses/scroll.c
index d2f3d1704..a53d71bad 100644
--- a/scripts/kconfig/libcurses/scroll.c
+++ b/scripts/kconfig/libcurses/scroll.c
@@ -31,10 +31,12 @@ scroll
31 All functions return OK on success and ERR on error. 31 All functions return OK on success and ERR on error.
32 32
33### Portability 33### Portability
34 X/Open ncurses NetBSD 34
35 scroll Y Y Y 35 Function | X/Open | ncurses | NetBSD
36 scrl Y Y Y 36 :---------------------|:------:|:-------:|:------:
37 wscrl Y Y Y 37 scroll | Y | Y | Y
38 scrl | Y | Y | Y
39 wscrl | Y | Y | Y
38 40
39**man-end****************************************************************/ 41**man-end****************************************************************/
40 42
diff --git a/scripts/kconfig/libcurses/slk.c b/scripts/kconfig/libcurses/slk.c
index a9fca13d3..e8dde752c 100644
--- a/scripts/kconfig/libcurses/slk.c
+++ b/scripts/kconfig/libcurses/slk.c
@@ -46,12 +46,12 @@ slk
46 slk_init() requires a single parameter which describes the format of 46 slk_init() requires a single parameter which describes the format of
47 the SLKs as follows: 47 the SLKs as follows:
48 48
49 0 3-2-3 format 49 0 3-2-3 format
50 1 4-4 format 50 1 4-4 format
51 2 4-4-4 format (ncurses extension) 51 2 4-4-4 format (ncurses extension)
52 3 4-4-4 format with index line (ncurses extension) 52 3 4-4-4 format with index line (ncurses extension)
53 2 lines used 53 2 lines used
54 55 5-5 format (pdcurses format) 54 55 5-5 format (pdcurses format)
55 55
56 slk_refresh(), slk_noutrefresh() and slk_touch() are analogous to 56 slk_refresh(), slk_noutrefresh() and slk_touch() are analogous to
57 refresh(), noutrefresh() and touch(). 57 refresh(), noutrefresh() and touch().
@@ -61,26 +61,28 @@ slk
61 All functions return OK on success and ERR on error. 61 All functions return OK on success and ERR on error.
62 62
63### Portability 63### Portability
64 X/Open ncurses NetBSD 64
65 slk_init Y Y Y 65 Function | X/Open | ncurses | NetBSD
66 slk_set Y Y Y 66 :---------------------|:------:|:-------:|:------:
67 slk_refresh Y Y Y 67 slk_init | Y | Y | Y
68 slk_noutrefresh Y Y Y 68 slk_set | Y | Y | Y
69 slk_label Y Y Y 69 slk_refresh | Y | Y | Y
70 slk_clear Y Y Y 70 slk_noutrefresh | Y | Y | Y
71 slk_restore Y Y Y 71 slk_label | Y | Y | Y
72 slk_touch Y Y Y 72 slk_clear | Y | Y | Y
73 slk_attron Y Y Y 73 slk_restore | Y | Y | Y
74 slk_attrset Y Y Y 74 slk_touch | Y | Y | Y
75 slk_attroff Y Y Y 75 slk_attron | Y | Y | Y
76 slk_attr_on Y Y Y 76 slk_attrset | Y | Y | Y
77 slk_attr_set Y Y Y 77 slk_attroff | Y | Y | Y
78 slk_attr_off Y Y Y 78 slk_attr_on | Y | Y | Y
79 slk_wset Y Y Y 79 slk_attr_set | Y | Y | Y
80 PDC_mouse_in_slk - - - 80 slk_attr_off | Y | Y | Y
81 PDC_slk_free - - - 81 slk_wset | Y | Y | Y
82 PDC_slk_initialize - - - 82 PDC_mouse_in_slk | - | - | -
83 slk_wlabel - - - 83 PDC_slk_free | - | - | -
84 PDC_slk_initialize | - | - | -
85 slk_wlabel | - | - | -
84 86
85**man-end****************************************************************/ 87**man-end****************************************************************/
86 88
diff --git a/scripts/kconfig/libcurses/touch.c b/scripts/kconfig/libcurses/touch.c
index 2fd03cce5..7ea0b64b2 100644
--- a/scripts/kconfig/libcurses/touch.c
+++ b/scripts/kconfig/libcurses/touch.c
@@ -49,14 +49,16 @@ touch
49 is_wintouched() and is_linetouched(). 49 is_wintouched() and is_linetouched().
50 50
51### Portability 51### Portability
52 X/Open ncurses NetBSD 52
53 touchwin Y Y Y 53 Function | X/Open | ncurses | NetBSD
54 touchline Y Y Y 54 :---------------------|:------:|:-------:|:------:
55 untouchwin Y Y Y 55 touchwin | Y | Y | Y
56 wtouchln Y Y Y 56 touchline | Y | Y | Y
57 is_linetouched Y Y Y 57 untouchwin | Y | Y | Y
58 is_wintouched Y Y Y 58 wtouchln | Y | Y | Y
59 touchoverlap - - Y 59 is_linetouched | Y | Y | Y
60 is_wintouched | Y | Y | Y
61 touchoverlap | - | - | Y
60 62
61**man-end****************************************************************/ 63**man-end****************************************************************/
62 64
diff --git a/scripts/kconfig/libcurses/window.c b/scripts/kconfig/libcurses/window.c
index 4ae5b0861..891d0c05b 100644
--- a/scripts/kconfig/libcurses/window.c
+++ b/scripts/kconfig/libcurses/window.c
@@ -124,26 +124,28 @@ window
124 NOT cancelled for those windows. 124 NOT cancelled for those windows.
125 125
126### Portability 126### Portability
127 X/Open ncurses NetBSD 127
128 newwin Y Y Y 128 Function | X/Open | ncurses | NetBSD
129 delwin Y Y Y 129 :---------------------|:------:|:-------:|:------:
130 mvwin Y Y Y 130 newwin | Y | Y | Y
131 subwin Y Y Y 131 delwin | Y | Y | Y
132 derwin Y Y Y 132 mvwin | Y | Y | Y
133 mvderwin Y Y Y 133 subwin | Y | Y | Y
134 dupwin Y Y Y 134 derwin | Y | Y | Y
135 wgetparent - Y - 135 mvderwin | Y | Y | Y
136 wsyncup Y Y Y 136 dupwin | Y | Y | Y
137 syncok Y Y Y 137 wgetparent | - | Y | -
138 is_subwin - Y - 138 wsyncup | Y | Y | Y
139 is_syncok - Y - 139 syncok | Y | Y | Y
140 wcursyncup Y Y Y 140 is_subwin | - | Y | -
141 wsyncdown Y Y Y 141 is_syncok | - | Y | -
142 wresize - Y Y 142 wcursyncup | Y | Y | Y
143 resize_window - - - 143 wsyncdown | Y | Y | Y
144 PDC_makelines - - - 144 wresize | - | Y | Y
145 PDC_makenew - - - 145 resize_window | - | - | -
146 PDC_sync - - - 146 PDC_makelines | - | - | -
147 PDC_makenew | - | - | -
148 PDC_sync | - | - | -
147 149
148**man-end****************************************************************/ 150**man-end****************************************************************/
149 151
diff --git a/scripts/kconfig/lxdialog/check-lxdialog.sh b/scripts/kconfig/lxdialog/check-lxdialog.sh
index a608d4c5e..885586865 100755
--- a/scripts/kconfig/lxdialog/check-lxdialog.sh
+++ b/scripts/kconfig/lxdialog/check-lxdialog.sh
@@ -53,7 +53,7 @@ trap "rm -f $tmp" 0 1 2 3 15
53check() { 53check() {
54 $cc -x c - -o $tmp 2>/dev/null <<'EOF' 54 $cc -x c - -o $tmp 2>/dev/null <<'EOF'
55#include CURSES_LOC 55#include CURSES_LOC
56int main() {} 56int main() { return 0; }
57EOF 57EOF
58 if [ $? != 0 ]; then 58 if [ $? != 0 ]; then
59 echo " *** Unable to find the ncurses libraries or the" 1>&2 59 echo " *** Unable to find the ncurses libraries or the" 1>&2
diff --git a/scripts/mk_mingw64u_defconfig b/scripts/mk_mingw64u_defconfig
index 19124d735..5561a0900 100755
--- a/scripts/mk_mingw64u_defconfig
+++ b/scripts/mk_mingw64u_defconfig
@@ -32,6 +32,7 @@ set_build_opts \
32 CONFIG_LAST_SUPPORTED_WCHAR=1114111 \ 32 CONFIG_LAST_SUPPORTED_WCHAR=1114111 \
33 CONFIG_UNICODE_COMBINING_WCHARS=y \ 33 CONFIG_UNICODE_COMBINING_WCHARS=y \
34 CONFIG_UNICODE_WIDE_WCHARS=y \ 34 CONFIG_UNICODE_WIDE_WCHARS=y \
35 CONFIG_FEATURE_USE_CNG_API=y \
35 < "$configs"/mingw64_defconfig \ 36 < "$configs"/mingw64_defconfig \
36 > "$configs"/mingw64u_defconfig 37 > "$configs"/mingw64u_defconfig
37 38
diff --git a/shell/Config.src b/shell/Config.src
index 5efbf9995..5b3fe08f3 100644
--- a/shell/Config.src
+++ b/shell/Config.src
@@ -166,9 +166,10 @@ config FEATURE_SH_HISTFILESIZE
166 default y 166 default y
167 depends on SHELL_ASH || SHELL_HUSH 167 depends on SHELL_ASH || SHELL_HUSH
168 help 168 help
169 This option makes busybox shells to use $HISTFILESIZE variable 169 This option makes busybox shells to use $HISTSIZE and
170 to set shell history size. Note that its max value is capped 170 $HISTFILESIZE variables to set shell history size.
171 by "History size" setting in library tuning section. 171 Note that its max value is capped by "History size" setting
172 in library tuning section.
172 173
173config FEATURE_SH_EMBEDDED_SCRIPTS 174config FEATURE_SH_EMBEDDED_SCRIPTS
174 bool "Embed scripts in the binary" 175 bool "Embed scripts in the binary"
diff --git a/shell/ash.c b/shell/ash.c
index 3919118f0..0038aa1e9 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -929,6 +929,7 @@ raise_interrupt(void)
929 raise(SIGINT); 929 raise(SIGINT);
930#else 930#else
931 fflush_all(); 931 fflush_all();
932 kill(-getpid(), SIGINT);
932 _exit(SIGINT << 24); 933 _exit(SIGINT << 24);
933#endif 934#endif
934 } 935 }
@@ -4274,7 +4275,7 @@ signal_handler(int signo)
4274 return; 4275 return;
4275 } 4276 }
4276#if ENABLE_FEATURE_EDITING 4277#if ENABLE_FEATURE_EDITING
4277 bb_got_signal = signo; /* for read_line_input: "we got a signal" */ 4278 bb_got_signal = signo; /* for read_line_input / read builtin: "we got a signal" */
4278#endif 4279#endif
4279 gotsig[signo - 1] = 1; 4280 gotsig[signo - 1] = 1;
4280 pending_sig = signo; 4281 pending_sig = signo;
@@ -15812,6 +15813,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
15812 r = shell_builtin_read(&params); 15813 r = shell_builtin_read(&params);
15813 INT_ON; 15814 INT_ON;
15814 15815
15816#if !ENABLE_PLATFORM_MINGW32
15815 if ((uintptr_t)r == 1 && errno == EINTR) { 15817 if ((uintptr_t)r == 1 && errno == EINTR) {
15816 /* To get SIGCHLD: sleep 1 & read x; echo $x 15818 /* To get SIGCHLD: sleep 1 & read x; echo $x
15817 * Correct behavior is to not exit "read" 15819 * Correct behavior is to not exit "read"
@@ -15820,8 +15822,15 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
15820 goto again; 15822 goto again;
15821 } 15823 }
15822 15824
15823#if ENABLE_PLATFORM_MINGW32 15825 if ((uintptr_t)r == 2) /* -t SEC timeout? */
15826 /* bash: "The exit status is greater than 128 if the timeout is exceeded." */
15827 /* The actual value observed with bash 5.2.15: */
15828 return 128 + SIGALRM;
15829#else /* ENABLE_PLATFORM_MINGW32 */
15824 if ((uintptr_t)r == 2) { 15830 if ((uintptr_t)r == 2) {
15831 /* Timeout, return 128 + SIGALRM */
15832 return 142;
15833 } else if ((uintptr_t)r == 3) {
15825 /* ^C pressed, propagate event */ 15834 /* ^C pressed, propagate event */
15826 if (trap[SIGINT]) { 15835 if (trap[SIGINT]) {
15827 write(STDOUT_FILENO, "^C", 2); 15836 write(STDOUT_FILENO, "^C", 2);
@@ -15969,8 +15978,25 @@ exitshell(void)
15969 char *p; 15978 char *p;
15970 15979
15971#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 15980#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
15972 save_history(line_input_state); /* may be NULL */ 15981 if (line_input_state) {
15982 const char *hp;
15983# if ENABLE_FEATURE_SH_HISTFILESIZE
15984// in bash:
15985// HISTFILESIZE controls the on-disk history file size (in lines, 0=no history):
15986// "When this variable is assigned a value, the history file is truncated, if necessary"
15987// but we do it only at exit, not on assignment:
15988 /* Use HISTFILESIZE to limit file size */
15989 hp = lookupvar("HISTFILESIZE");
15990 if (hp)
15991 line_input_state->max_history = size_from_HISTFILESIZE(hp);
15992# endif
15993 /* HISTFILE: "If unset, the command history is not saved when a shell exits." */
15994 hp = lookupvar("HISTFILE");
15995 line_input_state->hist_file = hp;
15996 save_history(line_input_state); /* no-op if hist_file is NULL or "" */
15997 }
15973#endif 15998#endif
15999
15974 savestatus = exitstatus; 16000 savestatus = exitstatus;
15975 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus)); 16001 TRACE(("pid %d, exitshell(%d)\n", getpid(), savestatus));
15976 if (setjmp(loc.loc)) 16002 if (setjmp(loc.loc))
@@ -16474,7 +16500,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv)
16474 if (hp) 16500 if (hp)
16475 line_input_state->hist_file = xstrdup(hp); 16501 line_input_state->hist_file = xstrdup(hp);
16476# if ENABLE_FEATURE_SH_HISTFILESIZE 16502# if ENABLE_FEATURE_SH_HISTFILESIZE
16477 hp = lookupvar("HISTFILESIZE"); 16503 hp = lookupvar("HISTSIZE");
16504 /* Using HISTFILESIZE above to limit max_history would be WRONG:
16505 * users may set HISTFILESIZE=0 in their profile scripts
16506 * to prevent _saving_ of history files, but still want to have
16507 * non-zero history limit for in-memory list.
16508 */
16478 line_input_state->max_history = size_from_HISTFILESIZE(hp); 16509 line_input_state->max_history = size_from_HISTFILESIZE(hp);
16479# endif 16510# endif
16480 } 16511 }
diff --git a/shell/ash_test/ash-read/read_ifs2.right b/shell/ash_test/ash-read/read_ifs2.right
new file mode 100644
index 000000000..797137dae
--- /dev/null
+++ b/shell/ash_test/ash-read/read_ifs2.right
@@ -0,0 +1,9 @@
1|X|Y:Z:|
2|X|Y:Z|
3|X|Y|
4|X|Y|
5|X||
6|X||
7|||
8Whitespace should be trimmed too:
9|X|Y|
diff --git a/shell/ash_test/ash-read/read_ifs2.tests b/shell/ash_test/ash-read/read_ifs2.tests
new file mode 100755
index 000000000..f01a68978
--- /dev/null
+++ b/shell/ash_test/ash-read/read_ifs2.tests
@@ -0,0 +1,9 @@
1echo "X:Y:Z:" | (IFS=": " read x y; echo "|$x|$y|")
2echo "X:Y:Z" | (IFS=": " read x y; echo "|$x|$y|")
3echo "X:Y:" | (IFS=": " read x y; echo "|$x|$y|")
4echo "X:Y" | (IFS=": " read x y; echo "|$x|$y|")
5echo "X:" | (IFS=": " read x y; echo "|$x|$y|")
6echo "X" | (IFS=": " read x y; echo "|$x|$y|")
7echo "" | (IFS=": " read x y; echo "|$x|$y|")
8echo Whitespace should be trimmed too:
9echo "X:Y : " | (IFS=": " read x y; echo "|$x|$y|")
diff --git a/shell/ash_test/ash-read/read_t.right b/shell/ash_test/ash-read/read_t.right
index 04126cbe6..3eedae275 100644
--- a/shell/ash_test/ash-read/read_t.right
+++ b/shell/ash_test/ash-read/read_t.right
@@ -1,4 +1,4 @@
1>< 1>te:142<
2>< 2>:142<
3>test< 3>test:0<
4>test< 4>test:0<
diff --git a/shell/ash_test/ash-read/read_t.tests b/shell/ash_test/ash-read/read_t.tests
index d65f1aeaa..9fbeec517 100755
--- a/shell/ash_test/ash-read/read_t.tests
+++ b/shell/ash_test/ash-read/read_t.tests
@@ -1,10 +1,10 @@
1# bash 3.2 outputs: 1# bash 5.2 outputs:
2 2
3# >< 3# >te:142<
4{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply<") 4{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply:$?<")
5# >< 5# >:142<
6{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply<") 6{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply:$?<")
7# >test< 7# >test:0<
8{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply<") 8{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply:$?<")
9# >test< 9# >test:0<
10{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply<") 10{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply:$?<")
diff --git a/shell/ash_test/printenv.c b/shell/ash_test/printenv.c
index c86308d3b..f0f41984d 100644
--- a/shell/ash_test/printenv.c
+++ b/shell/ash_test/printenv.c
@@ -31,9 +31,7 @@
31extern char **environ; 31extern char **environ;
32 32
33int 33int
34main (argc, argv) 34main (int argc, char **argv)
35 int argc;
36 char **argv;
37{ 35{
38 register char **envp, *eval; 36 register char **envp, *eval;
39 int len; 37 int len;
diff --git a/shell/ash_test/recho.c b/shell/ash_test/recho.c
index 42a5feafd..7e96b14cc 100644
--- a/shell/ash_test/recho.c
+++ b/shell/ash_test/recho.c
@@ -27,7 +27,7 @@
27#include <stdio.h> 27#include <stdio.h>
28#include <stdlib.h> 28#include <stdlib.h>
29 29
30void strprint(); 30void strprint(char *);
31 31
32int main(int argc, char **argv) 32int main(int argc, char **argv)
33{ 33{
diff --git a/shell/hush.c b/shell/hush.c
index 04dda0734..d1f687f9d 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -1973,7 +1973,7 @@ static void record_pending_signo(int sig)
1973 || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0]) 1973 || (G_traps && G_traps[SIGCHLD] && G_traps[SIGCHLD][0])
1974 /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */ 1974 /* ^^^ if SIGCHLD, interrupt line reading only if it has a trap */
1975 ) { 1975 ) {
1976 bb_got_signal = sig; /* for read_line_input: "we got a signal" */ 1976 bb_got_signal = sig; /* for read_line_input / read builtin: "we got a signal" */
1977 } 1977 }
1978#endif 1978#endif
1979#if ENABLE_HUSH_FAST 1979#if ENABLE_HUSH_FAST
@@ -2099,11 +2099,29 @@ static sighandler_t pick_sighandler(unsigned sig)
2099 return handler; 2099 return handler;
2100} 2100}
2101 2101
2102static const char* FAST_FUNC get_local_var_value(const char *name);
2103
2102/* Restores tty foreground process group, and exits. */ 2104/* Restores tty foreground process group, and exits. */
2103static void hush_exit(int exitcode) 2105static void hush_exit(int exitcode)
2104{ 2106{
2105#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 2107#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
2106 save_history(G.line_input_state); /* may be NULL */ 2108 if (G.line_input_state) {
2109 const char *hp;
2110# if ENABLE_FEATURE_SH_HISTFILESIZE
2111// in bash:
2112// HISTFILESIZE controls the on-disk history file size (in lines, 0=no history):
2113// "When this variable is assigned a value, the history file is truncated, if necessary"
2114// but we do it only at exit, not on every assignment:
2115 /* Use HISTFILESIZE to limit file size */
2116 hp = get_local_var_value("HISTFILESIZE");
2117 if (hp)
2118 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
2119# endif
2120 /* HISTFILE: "If unset, the command history is not saved when a shell exits." */
2121 hp = get_local_var_value("HISTFILE");
2122 G.line_input_state->hist_file = hp;
2123 save_history(G.line_input_state); /* no-op if hist_file is NULL or "" */
2124 }
2107#endif 2125#endif
2108 2126
2109 fflush_all(); 2127 fflush_all();
@@ -4607,6 +4625,11 @@ static int fetch_heredocs(o_string *as_string, struct pipe *pi, int heredoc_cnt,
4607 4625
4608 redir->rd_type = REDIRECT_HEREDOC2; 4626 redir->rd_type = REDIRECT_HEREDOC2;
4609 /* redir->rd_dup is (ab)used to indicate <<- */ 4627 /* redir->rd_dup is (ab)used to indicate <<- */
4628 if (!redir->rd_filename) {
4629 /* examples: "echo <<", "echo <<<", "echo <<>" */
4630 syntax_error("missing here document terminator");
4631 return -1;
4632 }
4610 p = fetch_till_str(as_string, input, 4633 p = fetch_till_str(as_string, input,
4611 redir->rd_filename, redir->rd_dup); 4634 redir->rd_filename, redir->rd_dup);
4612 if (!p) { 4635 if (!p) {
@@ -10361,6 +10384,9 @@ int hush_main(int argc, char **argv)
10361 _exit(0); 10384 _exit(0);
10362 } 10385 }
10363 G.argv0_for_re_execing = argv[0]; 10386 G.argv0_for_re_execing = argv[0];
10387 if (G.argv0_for_re_execing[0] == '-')
10388 /* reexeced hush should never be a login shell */
10389 G.argv0_for_re_execing++;
10364#endif 10390#endif
10365#if ENABLE_HUSH_TRAP 10391#if ENABLE_HUSH_TRAP
10366# if ENABLE_HUSH_FUNCTIONS 10392# if ENABLE_HUSH_FUNCTIONS
@@ -10424,7 +10450,7 @@ int hush_main(int argc, char **argv)
10424 if (!get_local_var_value("PATH")) 10450 if (!get_local_var_value("PATH"))
10425 set_local_var_from_halves("PATH", bb_default_root_path); 10451 set_local_var_from_halves("PATH", bb_default_root_path);
10426 10452
10427 /* PS1/PS2 are set later, if we determine that we are interactive */ 10453 /* PS1/PS2/HISTFILE are set later, if we determine that we are interactive */
10428 10454
10429 /* bash also exports SHLVL and _, 10455 /* bash also exports SHLVL and _,
10430 * and sets (but doesn't export) the following variables: 10456 * and sets (but doesn't export) the following variables:
@@ -10446,7 +10472,6 @@ int hush_main(int argc, char **argv)
10446 * BASH_SOURCE=() 10472 * BASH_SOURCE=()
10447 * DIRSTACK=() 10473 * DIRSTACK=()
10448 * PIPESTATUS=([0]="0") 10474 * PIPESTATUS=([0]="0")
10449 * HISTFILE=/<xxx>/.bash_history
10450 * HISTFILESIZE=500 10475 * HISTFILESIZE=500
10451 * HISTSIZE=500 10476 * HISTSIZE=500
10452 * MAILCHECK=60 10477 * MAILCHECK=60
@@ -10806,18 +10831,30 @@ int hush_main(int argc, char **argv)
10806 const char *hp = get_local_var_value("HISTFILE"); 10831 const char *hp = get_local_var_value("HISTFILE");
10807 if (!hp) { 10832 if (!hp) {
10808 hp = get_local_var_value("HOME"); 10833 hp = get_local_var_value("HOME");
10809 if (hp) 10834 if (hp) {
10810 hp = concat_path_file(hp, ".hush_history"); 10835 hp = concat_path_file(hp, ".hush_history");
10836 /* Make HISTFILE set on exit (else history won't be saved) */
10837 set_local_var_from_halves("HISTFILE", hp);
10838 }
10811 } else { 10839 } else {
10812 hp = xstrdup(hp); 10840 hp = xstrdup(hp);
10813 } 10841 }
10814 if (hp) { 10842 if (hp) {
10815 G.line_input_state->hist_file = hp; 10843 G.line_input_state->hist_file = hp;
10816 //set_local_var(xasprintf("HISTFILE=%s", ...));
10817 } 10844 }
10818# if ENABLE_FEATURE_SH_HISTFILESIZE 10845# if ENABLE_FEATURE_SH_HISTFILESIZE
10819 hp = get_local_var_value("HISTFILESIZE"); 10846 hp = get_local_var_value("HISTSIZE");
10847 /* Using HISTFILESIZE above to limit max_history would be WRONG:
10848 * users may set HISTFILESIZE=0 in their profile scripts
10849 * to prevent _saving_ of history files, but still want to have
10850 * non-zero history limit for in-memory list.
10851 */
10852// in bash, runtime history size is controlled by HISTSIZE (0=no history),
10853// HISTFILESIZE controls on-disk history file size (in lines, 0=no history):
10820 G.line_input_state->max_history = size_from_HISTFILESIZE(hp); 10854 G.line_input_state->max_history = size_from_HISTFILESIZE(hp);
10855// HISTFILESIZE: "The shell sets the default value to the value of HISTSIZE after reading any startup files."
10856// HISTSIZE: "The shell sets the default value to 500 after reading any startup files."
10857// (meaning: if the value wasn't set after startup files, the default value is set as described above)
10821# endif 10858# endif
10822 } 10859 }
10823# endif 10860# endif
@@ -11172,6 +11209,11 @@ static int FAST_FUNC builtin_read(char **argv)
11172 goto again; 11209 goto again;
11173 } 11210 }
11174 11211
11212 if ((uintptr_t)r == 2) /* -t SEC timeout? */
11213 /* bash: "The exit status is greater than 128 if the timeout is exceeded." */
11214 /* The actual value observed with bash 5.2.15: */
11215 return 128 + SIGALRM;
11216
11175 if ((uintptr_t)r > 1) { 11217 if ((uintptr_t)r > 1) {
11176 bb_simple_error_msg(r); 11218 bb_simple_error_msg(r);
11177 r = (char*)(uintptr_t)1; 11219 r = (char*)(uintptr_t)1;
diff --git a/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.right b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.right
new file mode 100644
index 000000000..7af73557a
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.right
@@ -0,0 +1 @@
hush: syntax error: missing here document terminator
diff --git a/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.tests b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.tests
new file mode 100755
index 000000000..33ccde26b
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF1.tests
@@ -0,0 +1,2 @@
1echo <<
2echo Done:
diff --git a/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.right b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.right
new file mode 100644
index 000000000..7af73557a
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.right
@@ -0,0 +1 @@
hush: syntax error: missing here document terminator
diff --git a/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.tests b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.tests
new file mode 100755
index 000000000..fcda11045
--- /dev/null
+++ b/shell/hush_test/hush-heredoc/heredoc_syntax_err_no_EOF2.tests
@@ -0,0 +1,2 @@
1echo << >
2echo Done:
diff --git a/shell/hush_test/hush-read/read_t.right b/shell/hush_test/hush-read/read_t.right
index 04126cbe6..3eedae275 100644
--- a/shell/hush_test/hush-read/read_t.right
+++ b/shell/hush_test/hush-read/read_t.right
@@ -1,4 +1,4 @@
1>< 1>te:142<
2>< 2>:142<
3>test< 3>test:0<
4>test< 4>test:0<
diff --git a/shell/hush_test/hush-read/read_t.tests b/shell/hush_test/hush-read/read_t.tests
index d65f1aeaa..9fbeec517 100755
--- a/shell/hush_test/hush-read/read_t.tests
+++ b/shell/hush_test/hush-read/read_t.tests
@@ -1,10 +1,10 @@
1# bash 3.2 outputs: 1# bash 5.2 outputs:
2 2
3# >< 3# >te:142<
4{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply<") 4{ echo -n 'te'; sleep 2; echo 'st'; } | (read -t 1 reply; echo ">$reply:$?<")
5# >< 5# >:142<
6{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply<") 6{ sleep 2; echo 'test'; } | (read -t 1 reply; echo ">$reply:$?<")
7# >test< 7# >test:0<
8{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply<") 8{ echo -n 'te'; sleep 1; echo 'st'; } | (read -t 2 reply; echo ">$reply:$?<")
9# >test< 9# >test:0<
10{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply<") 10{ sleep 1; echo 'test'; } | (read -t 2 reply; echo ">$reply:$?<")
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 7fb5f8c58..657f0df8f 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -55,7 +55,7 @@ const char* FAST_FUNC
55shell_builtin_read(struct builtin_read_params *params) 55shell_builtin_read(struct builtin_read_params *params)
56{ 56{
57 struct pollfd pfd[1]; 57 struct pollfd pfd[1];
58#define fd (pfd[0].fd) /* -u FD */ 58#define fd (pfd->fd) /* -u FD */
59 unsigned err; 59 unsigned err;
60 unsigned end_ms; /* -t TIMEOUT */ 60 unsigned end_ms; /* -t TIMEOUT */
61 int nchars; /* -n NUM */ 61 int nchars; /* -n NUM */
@@ -144,7 +144,7 @@ shell_builtin_read(struct builtin_read_params *params)
144 * bash seems to ignore -p PROMPT for this use case. 144 * bash seems to ignore -p PROMPT for this use case.
145 */ 145 */
146 int r; 146 int r;
147 pfd[0].events = POLLIN; 147 pfd->events = POLLIN;
148 r = poll(pfd, 1, /*timeout:*/ 0); 148 r = poll(pfd, 1, /*timeout:*/ 0);
149 /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */ 149 /* Return 0 only if poll returns 1 ("one fd ready"), else return 1: */
150 return (const char *)(uintptr_t)(r <= 0); 150 return (const char *)(uintptr_t)(r <= 0);
@@ -209,8 +209,8 @@ shell_builtin_read(struct builtin_read_params *params)
209 * 32-bit unix time wrapped (year 2038+). 209 * 32-bit unix time wrapped (year 2038+).
210 */ 210 */
211 if (timeout <= 0) { /* already late? */ 211 if (timeout <= 0) { /* already late? */
212 retval = (const char *)(uintptr_t)1; 212 retval = (const char *)(uintptr_t)2;
213 goto ret; 213 break;
214 } 214 }
215 } 215 }
216 216
@@ -219,15 +219,23 @@ shell_builtin_read(struct builtin_read_params *params)
219 * regardless of SA_RESTART-ness of that signal! 219 * regardless of SA_RESTART-ness of that signal!
220 */ 220 */
221 errno = 0; 221 errno = 0;
222 pfd[0].events = POLLIN; 222 pfd->events = POLLIN;
223//TODO race with a signal arriving just before the poll! 223
224#if ENABLE_PLATFORM_MINGW32 224#if ENABLE_PLATFORM_MINGW32
225 /* Don't poll if timeout is -1, it hurts performance. */ 225 /* Don't poll if timeout is -1, it hurts performance. The
226 * caution above about interrupts isn't relevant on Windows
227 * where Ctrl-C causes an event, not a signal.
228 */
226 if (timeout >= 0) 229 if (timeout >= 0)
227#endif 230#endif
228 if (poll(pfd, 1, timeout) <= 0) { 231 /* test bb_got_signal, then poll(), atomically wrt signals */
229 /* timed out, or EINTR */ 232 if (check_got_signal_and_poll(pfd, timeout) <= 0) {
233 /* timed out, or some error */
230 err = errno; 234 err = errno;
235 if (!err) { /* timed out */
236 retval = (const char *)(uintptr_t)2;
237 break;
238 }
231 retval = (const char *)(uintptr_t)1; 239 retval = (const char *)(uintptr_t)1;
232 goto ret; 240 goto ret;
233 } 241 }
@@ -238,15 +246,18 @@ shell_builtin_read(struct builtin_read_params *params)
238 key = windows_read_key(fd, NULL, timeout); 246 key = windows_read_key(fd, NULL, timeout);
239 if (key == 0x03) { 247 if (key == 0x03) {
240 /* ^C pressed */ 248 /* ^C pressed */
241 retval = (const char *)(uintptr_t)2; 249 retval = (const char *)(uintptr_t)3;
242 goto ret; 250 goto ret;
243 } 251 }
244 else if (key == -1 || (key == 0x1a && bufpos == 0)) { 252 else if (key == -1) {
245 /* timeout or ^Z at start of buffer */ 253 /* timeout */
254 retval = (const char *)(uintptr_t)2;
255 break;
256 } else if (key == 0x1a && bufpos == 0) {
257 /* ^Z at start of buffer */
246 retval = (const char *)(uintptr_t)1; 258 retval = (const char *)(uintptr_t)1;
247 goto ret; 259 break;
248 } 260 } else if (key == '\b') {
249 else if (key == '\b') {
250 if (bufpos > 0) { 261 if (bufpos > 0) {
251 --bufpos; 262 --bufpos;
252 ++nchars; 263 ++nchars;
@@ -278,7 +289,7 @@ shell_builtin_read(struct builtin_read_params *params)
278 * and exit BS context. 289 * and exit BS context.
279 * - CR LF not in BS context: replace CR with LF */ 290 * - CR LF not in BS context: replace CR with LF */
280 buffer[--bufpos] = c; 291 buffer[--bufpos] = c;
281 ++nchars; 292 nchars += 1 + (backslash == 2);
282 } 293 }
283 } else if (backslash == 2) { 294 } else if (backslash == 2) {
284 /* We saw BS CR ??, keep escaped CR, exit BS context, 295 /* We saw BS CR ??, keep escaped CR, exit BS context,
@@ -298,6 +309,9 @@ shell_builtin_read(struct builtin_read_params *params)
298 backslash = 0; 309 backslash = 0;
299 if (c != '\n') 310 if (c != '\n')
300 goto put; 311 goto put;
312#if ENABLE_PLATFORM_MINGW32
313 ++nchars;
314#endif
301 continue; 315 continue;
302 } 316 }
303 if (c == '\\') { 317 if (c == '\\') {
@@ -338,7 +352,7 @@ shell_builtin_read(struct builtin_read_params *params)
338 } 352 }
339 put: 353 put:
340 bufpos++; 354 bufpos++;
341 } while (--nchars); 355 } while (IF_PLATFORM_MINGW32(backslash ||) --nchars);
342 356
343 if (argv[0]) { 357 if (argv[0]) {
344 /* Remove trailing space $IFS chars */ 358 /* Remove trailing space $IFS chars */
diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c
index 7558051f0..2cbb22b6d 100644
--- a/sysklogd/syslogd.c
+++ b/sysklogd/syslogd.c
@@ -1045,7 +1045,7 @@ static int NOINLINE syslogd_init(char **argv)
1045#endif 1045#endif
1046 /* If they have not specified remote logging, then log locally */ 1046 /* If they have not specified remote logging, then log locally */
1047 if (ENABLE_FEATURE_REMOTE_LOG && !(opts & OPT_remotelog)) // -R 1047 if (ENABLE_FEATURE_REMOTE_LOG && !(opts & OPT_remotelog)) // -R
1048 option_mask32 |= OPT_locallog; 1048 option_mask32 = (opts |= OPT_locallog);
1049#if ENABLE_FEATURE_SYSLOGD_CFG 1049#if ENABLE_FEATURE_SYSLOGD_CFG
1050 parse_syslogdcfg(opt_f); 1050 parse_syslogdcfg(opt_f);
1051#endif 1051#endif
diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests
index 85e746589..a4462c53e 100755
--- a/testsuite/cpio.tests
+++ b/testsuite/cpio.tests
@@ -154,6 +154,29 @@ testing "cpio -R with extract" \
154" "" "" 154" "" ""
155SKIP= 155SKIP=
156 156
157# Create an archive containing a file with "../dont_write" filename.
158# See that it will not be allowed to unpack.
159# NB: GNU cpio 2.15 DOES NOT do such checks.
160optional FEATURE_PATH_TRAVERSAL_PROTECTION
161rm -rf cpio.testdir
162mkdir -p cpio.testdir/prepare/inner
163echo "file outside of destination was written" > cpio.testdir/prepare/dont_write
164echo "data" > cpio.testdir/prepare/inner/to_extract
165mkdir -p cpio.testdir/extract
166testing "cpio extract file outside of destination" "\
167(cd cpio.testdir/prepare/inner && echo -e '../dont_write\nto_extract' | cpio -o -H newc) | (cd cpio.testdir/extract && cpio -vi 2>&1)
168echo \$?
169ls cpio.testdir/dont_write 2>&1" \
170"\
171cpio: removing leading '../' from member names
172../dont_write
173to_extract
1741 blocks
1750
176ls: cpio.testdir/dont_write: No such file or directory
177" "" ""
178SKIP=
179
157# Clean up 180# Clean up
158rm -rf cpio.testdir cpio.testdir2 2>/dev/null 181rm -rf cpio.testdir cpio.testdir2 2>/dev/null
159 182
diff --git a/testsuite/cryptpw.tests b/testsuite/cryptpw.tests
index 0dd91fe15..83bfde521 100755
--- a/testsuite/cryptpw.tests
+++ b/testsuite/cryptpw.tests
@@ -22,21 +22,93 @@ testing "cryptpw des zz" \
22#SKIP= 22#SKIP=
23 23
24optional USE_BB_CRYPT_SHA 24optional USE_BB_CRYPT_SHA
25testing "cryptpw sha256" \ 25# Note: mkpasswd-5.6.2 won't accept "-m sha256", wants "-m sha256crypt"
26 "cryptpw -m sha256 QWErty '123456789012345678901234567890'" \ 26testing 'cryptpw sha256' \
27 '$5$1234567890123456$5DxfOCmU4vRhtzfsbdK.6wSGMwwVbac7ZkWwusb8Si7\n' "" "" 27 'cryptpw -m sha256 QWErty 1234567890123456' \
28 '$5$1234567890123456$5DxfOCmU4vRhtzfsbdK.6wSGMwwVbac7ZkWwusb8Si7\n' \
29 '' ''
30# mkpasswd-5.6.2 does not allow overlong salts, we truncate (at 16 chars for sha256)
31testing 'cryptpw sha256 overlong' \
32 'cryptpw -m sha256 QWErty 123456789012345678901234567890' \
33 '$5$1234567890123456$5DxfOCmU4vRhtzfsbdK.6wSGMwwVbac7ZkWwusb8Si7\n' \
34 '' ''
35testing 'cryptpw sha256 implicit' \
36 'cryptpw QWErty \$5\$1234567890123456' \
37 '$5$1234567890123456$5DxfOCmU4vRhtzfsbdK.6wSGMwwVbac7ZkWwusb8Si7\n' \
38 '' ''
39testing 'cryptpw sha256 rounds=99999' \
40 'cryptpw -m sha256 QWErty rounds=99999\$123456789012345678901234567890' \
41 '$5$rounds=99999$1234567890123456$aYellycJGZM6AKyVzaQsSrDBdTixubtMnM6J.MN0xM8\n' \
42 '' ''
43testing 'cryptpw sha256 rounds=99999 implicit' \
44 'cryptpw QWErty \$5\$rounds=99999\$123456789012345678901234567890' \
45 '$5$rounds=99999$1234567890123456$aYellycJGZM6AKyVzaQsSrDBdTixubtMnM6J.MN0xM8\n' \
46 '' ''
28 47
29testing "cryptpw sha256 rounds=99999" \ 48testing 'cryptpw sha512' \
30 "cryptpw -m sha256 QWErty 'rounds=99999\$123456789012345678901234567890'" \ 49 'cryptpw -m sha512 QWErty 123456789012345678901234567890' \
31 '$5$rounds=99999$1234567890123456$aYellycJGZM6AKyVzaQsSrDBdTixubtMnM6J.MN0xM8\n' "" "" 50 '$6$1234567890123456$KB7QqxFyqmJSWyQYcCuGeFukgz1bPQoipWZf7.9L7z3k8UNTXa6UikbKcUGDc2ANn7DOGmDaroxDgpK16w/RE0\n' \
32 51 '' ''
33testing "cryptpw sha512" \ 52testing 'cryptpw sha512crypt' \
34 "cryptpw -m sha512 QWErty '123456789012345678901234567890'" \ 53 'cryptpw -m sha512crypt QWErty 123456789012345678901234567890' \
35 '$6$1234567890123456$KB7QqxFyqmJSWyQYcCuGeFukgz1bPQoipWZf7.9L7z3k8UNTXa6UikbKcUGDc2ANn7DOGmDaroxDgpK16w/RE0\n' "" "" 54 '$6$1234567890123456$KB7QqxFyqmJSWyQYcCuGeFukgz1bPQoipWZf7.9L7z3k8UNTXa6UikbKcUGDc2ANn7DOGmDaroxDgpK16w/RE0\n' \
55 '' ''
56testing 'cryptpw sha512 rounds=99999' \
57 'cryptpw -m sha512 QWErty rounds=99999\$123456789012345678901234567890' \
58 '$6$rounds=99999$1234567890123456$BfF6gD6ZjUmwawH5QaAglYAxtU./yvsz0fcQ464l49aMI2DZW3j5ri28CrxK7riPWNpLuUpfaIdY751SBYKUH.\n' \
59 '' ''
60SKIP=
36 61
37testing "cryptpw sha512 rounds=99999" \ 62optional USE_BB_CRYPT_YES
38 "cryptpw -m sha512 QWErty 'rounds=99999\$123456789012345678901234567890'" \ 63testing 'cryptpw yescrypt' \
39 '$6$rounds=99999$1234567890123456$BfF6gD6ZjUmwawH5QaAglYAxtU./yvsz0fcQ464l49aMI2DZW3j5ri28CrxK7riPWNpLuUpfaIdY751SBYKUH.\n' "" "" 64 'cryptpw -m yescrypt qweRTY123@-+ j9T\$123456789012345678901234' \
65 '$y$j9T$123456789012345678901234$AKxw5OX/T4jD.v./IW.5tE/j7izNjw06fg3OvH1LsN9\n' \
66 '' ''
67testing 'cryptpw yescrypt with non-standard N=2048 instead of 4096 (j8T instead of j9T)' \
68 'cryptpw -m yescrypt qweRTY123@-+ j8T\$123456789012345678901234' \
69 '$y$j8T$123456789012345678901234$JQUUfopCxlfZNE8f.THJwbOkhy.XtB3GIjo9HUVioWB\n' \
70 '' ''
71# mkpasswd-5.6.2 allows short salts for yescrypt
72# ...but there is a catch. Not all of them.
73# The "partial" (not fitting in whole bytes) ascii64-encoded salt
74# is a special case. For example, "$zzz" would not even work in upstream.
75testing 'cryptpw yescrypt with empty salt' \
76 'cryptpw -m yescrypt qweRTY123@-+ j9T\$' \
77 '$y$j9T$$hpeksL94GXNRwnA00L3c8WFy0khFAUbCpBSak.N3Bp.\n' \
78 '' ''
79testing 'cryptpw yescrypt with 3-char salt' \
80 'cryptpw -m yescrypt qweRTY123@-+ j9T\$123' \
81 '$y$j9T$123$A34DMIGUbUIo3bjx66Wtk2IFoREMIw6d49it25KQh2D\n' \
82 '' ''
83# "." is not allowed in mkpasswd-5.6.2
84# ....................................
85# ".." is decoded into one zero byte (not two)
86testing 'cryptpw yescrypt with 2-char salt ".."' \
87 'cryptpw -m yescrypt qweRTY123@-+ j9T\$..' \
88 '$y$j9T$..$yVHeOayxOGg6cHL3.dg10u7T.qSgySfLN3uhSVSLNn/\n' \
89 '' ''
90# "..." is decoded into two zero bytes (not three, not one)
91testing 'cryptpw yescrypt with 3-char salt "..."' \
92 'cryptpw -m yescrypt qweRTY123@-+ j9T\$...' \
93 '$y$j9T$...$xHvJ5USZ7hFyXYbOijtEOMfZRS23cWIxu2eIBXRymA5\n' \
94 '' ''
95# "...." is decoded into three zero bytes (no surprises here)
96testing 'cryptpw yescrypt with 4-char salt "...."' \
97 'cryptpw -m yescrypt qweRTY123@-+ j9T\$....' \
98 '$y$j9T$....$wOnauYL2/NEtr6YQi9pi8AtV7L57sEbVOAnWJIcP9q2\n' \
99 '' ''
100# 84 chars = 21 4-char blocks which decode into 21*3 = 63 bytes.
101# The last byte of the maximum allowed salt size has to come from an incomplete
102# char block. E.g. "z/" encodes byte 0x7f. "z1" is 0xff.
103# Anything larger (e.g. "z2") is an error (it encodes 0x13f).
104testing 'cryptpw yescrypt with 86-char salt (max size)' \
105 'cryptpw -m yescrypt qweRTY123@-+ j9T\$123456789012345678901234567890123456789012345678901234567890123456789012345678901234z/' \
106 '$y$j9T$123456789012345678901234567890123456789012345678901234567890123456789012345678901234z/$Exxe8IoPXiddFsqj7iqCanRf8FyquAoB0/uceLmLjG.\n' \
107 '' ''
108testing 'cryptpw yescrypt implicit' \
109 'cryptpw qweRTY123@-+ \$y\$j9T\$123456789012345678901234' \
110 '$y$j9T$123456789012345678901234$AKxw5OX/T4jD.v./IW.5tE/j7izNjw06fg3OvH1LsN9\n' \
111 '' ''
40SKIP= 112SKIP=
41 113
42exit $FAILCOUNT 114exit $FAILCOUNT
diff --git a/testsuite/cut.tests b/testsuite/cut.tests
index a31f41f7f..21cfea809 100755
--- a/testsuite/cut.tests
+++ b/testsuite/cut.tests
@@ -23,14 +23,30 @@ the quick brown fox jumps over the lazy dog
23 23
24testing "cut -b a,a,a" "cut -b 3,3,3 input" "e\np\ne\n" "$abc" "" 24testing "cut -b a,a,a" "cut -b 3,3,3 input" "e\np\ne\n" "$abc" ""
25 25
26testing "cut -b overlaps" "cut -b 1-3,2-5,7-9,9-10 input" \ 26testing "cut -b overlaps" \
27 "one:to:th\nalphabeta\nthe qick \n" "$abc" "" 27 "cut -b 1-3,2-5,7-9,9-10 input" \
28testing "-b encapsulated" "cut -b 3-8,4-6 input" "e:two:\npha:be\ne quic\n" \ 28 "\
29 "$abc" "" 29one:to:th
30# --output-delimiter not implemnted (yet?) 30alphabeta
31#testing "cut -bO overlaps" \ 31the qick \n" \
32# "cut --output-delimiter ' ' -b 1-3,2-5,7-9,9-10 input" \ 32 "$abc" ""
33# "one:t o:th\nalpha beta\nthe q ick \n" "$abc" "" 33testing "-b encapsulated" \
34 "cut -b 3-8,4-6 input" \
35 "\
36e:two:
37pha:be
38e quic\n" \
39 "$abc" ""
40optional LONG_OPTS
41testing "cut -b --output-delimiter overlaps" \
42 "cut --output-delimiter='^' -b 1-3,2-5,7-9,9-10 input" \
43 "\
44one:t^o:th
45alpha^beta
46the q^ick \n" \
47 "$abc" ""
48SKIP=
49
34testing "cut high-low error" "cut -b 8-3 input 2>/dev/null || echo err" "err\n" \ 50testing "cut high-low error" "cut -b 8-3 input 2>/dev/null || echo err" "err\n" \
35 "$abc" "" 51 "$abc" ""
36 52
@@ -68,10 +84,27 @@ testing "cut with -d -f( ) -s" "cut -d' ' -f3 -s input && echo yes" "yes\n" "$in
68testing "cut with -d -f(a) -s" "cut -da -f3 -s input" "n\nsium:Jim\n\ncion:Ed\n" "$input" "" 84testing "cut with -d -f(a) -s" "cut -da -f3 -s input" "n\nsium:Jim\n\ncion:Ed\n" "$input" ""
69testing "cut with -d -f(a) -s -n" "cut -da -f3 -s -n input" "n\nsium:Jim\n\ncion:Ed\n" "$input" "" 85testing "cut with -d -f(a) -s -n" "cut -da -f3 -s -n input" "n\nsium:Jim\n\ncion:Ed\n" "$input" ""
70 86
87input="\
88
89foo bar baz
90
91bing bong boop
92
93"
94testing "cut with -d -s omits blank lines" "cut -d' ' -f2 -s input" "bar\nbong\n" "$input" ""
95
71# substitute for awk 96# substitute for awk
72optional FEATURE_CUT_REGEX 97optional FEATURE_CUT_REGEX
73testing "cut -DF" "cut -DF 2,7,5" \ 98testing "cut -DF unordered" "cut -DF 2,7,5" \
74 "said and your\nare\nis demand. supply\nforecast :\nyou you better,\n\nEm: Took hate\n" "" \ 99 "\
100said and your
101are
102is demand. supply
103forecast :
104you you better,
105
106Em: Took hate
107" "" \
75"Bother, said Pooh. It's your husband, and he has a gun. 108"Bother, said Pooh. It's your husband, and he has a gun.
76Cheerios are donut seeds. 109Cheerios are donut seeds.
77Talk is cheap because supply exceeds demand. 110Talk is cheap because supply exceeds demand.
@@ -79,9 +112,92 @@ Weather forecast for tonight : dark.
79Apple: you can buy better, but you can't pay more. 112Apple: you can buy better, but you can't pay more.
80Subcalifragilisticexpialidocious. 113Subcalifragilisticexpialidocious.
81Auntie Em: Hate you, hate Kansas. Took the dog. Dorothy." 114Auntie Em: Hate you, hate Kansas. Took the dog. Dorothy."
115
116# No delimiter found: print entire line regardless of -F RANGES
117testing "cut -F1" "cut -d: -F1" \
118 "the_only_field\n" "" \
119 "the_only_field\n"
120testing "cut -F2" "cut -d: -F2" \
121 "the_only_field\n" "" \
122 "the_only_field\n"
123# No delimiter found and -s: skip entire line
124testing "cut -sF1" "cut -d: -sF1" \
125 "" "" \
126 "the_only_field\n"
127#^^^ the above is probably mishandled by toybox, it prints the line
128testing "cut -sF2" "cut -d: -sF2" \
129 "" "" \
130 "the_only_field\n"
131# -D disables special handling of lines with no delimiters, the line is treated as the 1st field
132testing "cut -DF1" "cut -d: -DF1" \
133 "the_only_field\n" "" \
134 "the_only_field\n"
135testing "cut -DF2" "cut -d: -DF2" \
136 "\n" "" \
137 "the_only_field\n"
138
139optional FEATURE_CUT_REGEX LONG_OPTS
140testing "cut -F preserves intermediate delimiters" \
141 "cut --output-delimiter=: -F2,4-6,7" \
142 "2:4 5 6:7\n" \
143 "" "1 2 3 4\t\t5 6 7 8\n"
144SKIP=
145
146optional LONG_OPTS
147testing "cut -f does not preserve intermediate delimiters" \
148 "cut --output-delimiter=: -d' ' -f2,4-6,7" \
149 "2:4:5:6:7\n" \
150 "" "1 2 3 4 5 6 7 8\n"
151SKIP=
152
153testing "cut empty field" "cut -d ':' -f 1-3" \
154 "a::b\n" \
155 "" "a::b\n"
156testing "cut empty field 2" "cut -d ':' -f 3-5" \
157 "b::c\n" \
158 "" "a::b::c:d\n"
159testing "cut non-existing field" "cut -d ':' -f1,3" \
160 "1\n" \
161 "" "1:\n"
162
163# cut -d$'\n' has a special meaning: "select input lines".
164# I didn't find any documentation for this feature.
165testing "cut -dNEWLINE" \
166 "cut -d'
167' -f4,2,6-8" \
168 "2\n4\n6\n7\n" \
169 "" "1\n2\n3\n4\n5\n6\n7"
170
171optional LONG_OPTS
172testing "cut -dNEWLINE --output-delimiter" \
173 "cut -d'
174' --output-delimiter=@@ -f4,2,6-8" \
175 "2@@4@@6@@7\n" \
176 "" "1\n2\n3\n4\n5\n6\n7"
177
178testing "cut -dNEWLINE --output-delimiter 2" \
179 "cut -d'
180' --output-delimiter=@@ -f4,2,6-8" \
181 "2@@4@@6@@7\n" \
182 "" "1\n2\n3\n4\n5\n6\n7\n"
183
184testing "cut -dNEWLINE --output-delimiter EMPTY_INPUT" \
185 "cut -d'
186' --output-delimiter=@@ -f4,2,6-8" \
187 "" \
188 "" ""
82SKIP= 189SKIP=
83 190
84testing "cut empty field" "cut -d ':' -f 1-3" "a::b\n" "" "a::b\n" 191# This seems to work as if delimiter is never found.
85testing "cut empty field 2" "cut -d ':' -f 3-5" "b::c\n" "" "a::b::c:d\n" 192# We test here that -d '' does *not* operate as if there was no -d
193# and delimiter has defaulted to TAB:
194testing "cut -d EMPTY" \
195 "cut -d '' -f2-" \
196 "1 2\t3 4 5\n" \
197 "" "1 2\t3 4 5\n"
198testing "cut -d EMPTY -s" \
199 "cut -d '' -f2- -s" \
200 "" \
201 "" "1 2\t3 4 5\n"
86 202
87exit $FAILCOUNT 203exit $FAILCOUNT
diff --git a/testsuite/hexdump.tests b/testsuite/hexdump.tests
index be0379cfc..b2f6a2201 100755
--- a/testsuite/hexdump.tests
+++ b/testsuite/hexdump.tests
@@ -5,6 +5,17 @@
5 5
6. ./testing.sh 6. ./testing.sh
7 7
8input=\
9"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\
10"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\
11"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\
12"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\
13"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
14
15little_endian=false
16{ printf '\0\1' | hexdump -d | grep -q 256; } && little_endian=true
17readonly little_endian
18
8# testing "description" "command" "result" "infile" "stdin" 19# testing "description" "command" "result" "infile" "stdin"
9testing 'hexdump -C with four NULs' \ 20testing 'hexdump -C with four NULs' \
10 'hexdump -C' \ 21 'hexdump -C' \
@@ -43,12 +54,7 @@ testing "hexdump -e %3_u" \
43 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f 54 80 81 82 83 84 85 86 87 88 89 8a 8b 8c 8d 8e 8f
44 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff 55 f0 f1 f2 f3 f4 f5 f6 f7 f8 f9 fa fb fc fd fe ff
45" \ 56" \
46 "" \ 57 "" "$input"
47"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\
48"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\
49"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\
50"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\
51"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\
52 58
53testing "hexdump -e /1 %d" \ 59testing "hexdump -e /1 %d" \
54 "hexdump -e '16/1 \" %4d\" \"\n\"'" \ 60 "hexdump -e '16/1 \" %4d\" \"\n\"'" \
@@ -59,27 +65,74 @@ testing "hexdump -e /1 %d" \
59 -128 -127 -126 -125 -124 -123 -122 -121 -120 -119 -118 -117 -116 -115 -114 -113 65 -128 -127 -126 -125 -124 -123 -122 -121 -120 -119 -118 -117 -116 -115 -114 -113
60 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 66 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
61" \ 67" \
62 "" \ 68 "" "$input"
63"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\
64"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\
65"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\
66"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\
67"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\
68 69
69testing "hexdump -e /2 %d" \ 70$little_endian || SKIP=1
70 "hexdump -e '8/2 \" %6d\" \"\n\"'" \ 71testing "hexdump -e /2 %d (little endian)" \
71 "\ 72 "hexdump -e '8/2 \" %6d\" \"\n\"'" \
73 "\
72 256 770 1284 1798 2312 2826 3340 3854 74 256 770 1284 1798 2312 2826 3340 3854
73 4368 4882 5396 5910 6424 6938 7452 7966 75 4368 4882 5396 5910 6424 6938 7452 7966
74 29040 29554 30068 30582 31096 31610 32124 32638 76 29040 29554 30068 30582 31096 31610 32124 32638
75 -32384 -31870 -31356 -30842 -30328 -29814 -29300 -28786 77 -32384 -31870 -31356 -30842 -30328 -29814 -29300 -28786
76 -3600 -3086 -2572 -2058 -1544 -1030 -516 -2 78 -3600 -3086 -2572 -2058 -1544 -1030 -516 -2
77" \ 79" \
80 "" "$input"
81SKIP=
82
83$little_endian && SKIP=1
84testing "hexdump -e /2 %d (big endian)" \
85 "hexdump -e '8/2 \" %6d\" \"\n\"'" \
86 "\
87 1 515 1029 1543 2057 2571 3085 3599
88 4113 4627 5141 5655 6169 6683 7197 7711
89 28785 29299 29813 30327 30841 31355 31869 32383
90 -32639 -32125 -31611 -31097 -30583 -30069 -29555 -29041
91 -3855 -3341 -2827 -2313 -1799 -1285 -771 -257
92" \
93 "" "$input"
94SKIP=
95
96$little_endian || SKIP=1
97testing "hexdump -e /2 %x (little endian)" \
98 "hexdump -e '8/2 \" %6x\" \"\n\"'" \
99 "\
100 100 302 504 706 908 b0a d0c f0e
101 1110 1312 1514 1716 1918 1b1a 1d1c 1f1e
102 7170 7372 7574 7776 7978 7b7a 7d7c 7f7e
103 8180 8382 8584 8786 8988 8b8a 8d8c 8f8e
104 f1f0 f3f2 f5f4 f7f6 f9f8 fbfa fdfc fffe
105" \
106 "" "$input"
107SKIP=
108
109$little_endian && SKIP=1
110testing "hexdump -e /2 %x (big endian)" \
111 "hexdump -e '8/2 \" %6x\" \"\n\"'" \
112 "\
113 1 203 405 607 809 a0b c0d e0f
114 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f
115 7071 7273 7475 7677 7879 7a7b 7c7d 7e7f
116 8081 8283 8485 8687 8889 8a8b 8c8d 8e8f
117 f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff
118" \
119 "" "$input"
120SKIP=
121
122$little_endian || SKIP=1
123testing "hexdump -n4 -e '\"%u\"' (little endian)" \
124 "hexdump -n4 -e '\"%u\"'" \
125 "12345678" \
78 "" \ 126 "" \
79"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"\ 127 "\x4e\x61\xbc\x00AAAA"
80"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"\ 128SKIP=
81"\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"\ 129
82"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"\ 130$little_endian && SKIP=1
83"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"\ 131testing "hexdump -n4 -e '\"%u\"' (big endian)" \
132 "hexdump -n4 -e '\"%u\"'" \
133 "1315027968" \
134 "" \
135 "\x4e\x61\xbc\x00AAAA"
136SKIP=
84 137
85exit $FAILCOUNT 138exit $FAILCOUNT
diff --git a/testsuite/make.tests b/testsuite/make.tests
index 376bdcc15..fabdbe45c 100755
--- a/testsuite/make.tests
+++ b/testsuite/make.tests
@@ -86,6 +86,16 @@ test.k:
86' 86'
87cd .. || exit 1; rm -rf make.tempdir 2>/dev/null 87cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
88 88
89# Check that single-suffix inference rules work.
90mkdir make.tempdir && cd make.tempdir || exit 1
91touch test.sh
92testing "make single-suffix inference rule works" \
93 "make -f - -s; echo $?" \
94 "0\n" "" '
95test:
96'
97cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
98
89# There was a bug where the failure of a build command didn't result 99# There was a bug where the failure of a build command didn't result
90# in make returning a non-zero exit status. 100# in make returning a non-zero exit status.
91testing "make return error if command fails" \ 101testing "make return error if command fails" \
@@ -541,6 +551,36 @@ testing "make chained inference rules" \
541' 551'
542cd .. || exit 1; rm -rf make.tempdir 2>/dev/null 552cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
543 553
554# Suffixes with multiple periods are supported
555mkdir make.tempdir && cd make.tempdir || exit 1
556touch x.c.c
557testing "make support multi-period suffixes" \
558 "make -f -" "cat x.c.c >x.o.o\nx\n" "" '
559.SUFFIXES: .c.c .o.o
560x.o.o:
561.c.c.o.o:
562 cat $< >$@
563 @echo $*
564'
565cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
566
567# Suffixes with no periods are supported
568mkdir make.tempdir && cd make.tempdir || exit 1
569touch filex
570testing "make support suffixes without any periods" \
571 "make -f -" "cp filex fileh\nfile\ncp filex filez\nfile\n" "" '
572.SUFFIXES: x h z
573all: fileh filez
574fileh:
575filez: filex
576 cp filex filez
577 @echo $*
578xh:
579 cp $< $@
580 @echo $*
581'
582cd .. || exit 1; rm -rf make.tempdir 2>/dev/null
583
544# make supports *, ? and [] wildcards in targets and prerequisites 584# make supports *, ? and [] wildcards in targets and prerequisites
545mkdir make.tempdir && cd make.tempdir || exit 1 585mkdir make.tempdir && cd make.tempdir || exit 1
546touch -t 202206171201 t1a t2aa t3b 586touch -t 202206171201 t1a t2aa t3b
diff --git a/testsuite/od.tests b/testsuite/od.tests
index 4f245a7e8..c863bf2e8 100755
--- a/testsuite/od.tests
+++ b/testsuite/od.tests
@@ -61,7 +61,8 @@ testing "od -a (DESKTOP)" \
61"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff" 61"\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff"
62SKIP= 62SKIP=
63 63
64testing "od -B" \ 64$little_endian || SKIP=1
65testing "od -B (little-endian)" \
65 "od -B" \ 66 "od -B" \
66"\ 67"\
670000000 001001 005003 041101 177103 680000000 001001 005003 041101 177103
@@ -70,6 +71,16 @@ testing "od -B" \
70 "" "$input" 71 "" "$input"
71SKIP= 72SKIP=
72 73
74$little_endian && SKIP=1
75testing "od -B (big-endian)" \
76 "od -B" \
77"\
780000000 000402 001412 040502 041776
790000010
80" \
81 "" "$input"
82SKIP=
83
73$little_endian || SKIP=1 84$little_endian || SKIP=1
74testing "od -o (little-endian)" \ 85testing "od -o (little-endian)" \
75 "od -o" \ 86 "od -o" \
diff --git a/testsuite/wget/wget-handles-https b/testsuite/wget/wget-handles-https
new file mode 100644
index 000000000..11915f42f
--- /dev/null
+++ b/testsuite/wget/wget-handles-https
@@ -0,0 +1,4 @@
1test x"$SKIP_INTERNET_TESTS" != x"" && exit
2
3busybox wget -q -O foo https://www.google.com/
4test -s foo
diff --git a/win32/dirent.c b/win32/dirent.c
index 795fc779c..f0e8deae2 100644
--- a/win32/dirent.c
+++ b/win32/dirent.c
@@ -3,7 +3,9 @@
3struct DIR { 3struct DIR {
4 struct dirent dd_dir; 4 struct dirent dd_dir;
5 HANDLE dd_handle; /* FindFirstFile handle */ 5 HANDLE dd_handle; /* FindFirstFile handle */
6 int dd_stat; /* 0-based index */ 6 int not_first;
7 int got_dot;
8 int got_dotdot;
7}; 9};
8 10
9static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata) 11static inline void finddata2dirent(struct dirent *ent, WIN32_FIND_DATAA *fdata)
@@ -59,9 +61,11 @@ DIR *opendir(const char *name)
59 } 61 }
60 62
61 /* initialize DIR structure and copy first dir entry */ 63 /* initialize DIR structure and copy first dir entry */
62 dir = xmalloc(sizeof(DIR)); 64 dir = xzalloc(sizeof(DIR));
63 dir->dd_handle = h; 65 dir->dd_handle = h;
64 dir->dd_stat = 0; 66 /* dir->not_first = 0; */
67 /* dir->got_dot = 0; */
68 /* dir->got_dotdot = 0; */
65 finddata2dirent(&dir->dd_dir, &fdata); 69 finddata2dirent(&dir->dd_dir, &fdata);
66 return dir; 70 return dir;
67} 71}
@@ -74,11 +78,17 @@ struct dirent *readdir(DIR *dir)
74 } 78 }
75 79
76 /* if first entry, dirent has already been set up by opendir */ 80 /* if first entry, dirent has already been set up by opendir */
77 if (dir->dd_stat) { 81 if (dir->not_first) {
78 /* get next entry and convert from WIN32_FIND_DATA to dirent */ 82 /* get next entry and convert from WIN32_FIND_DATA to dirent */
79 WIN32_FIND_DATAA fdata; 83 WIN32_FIND_DATAA fdata;
80 if (FindNextFileA(dir->dd_handle, &fdata)) { 84 if (FindNextFileA(dir->dd_handle, &fdata)) {
81 finddata2dirent(&dir->dd_dir, &fdata); 85 finddata2dirent(&dir->dd_dir, &fdata);
86 } else if (!dir->got_dot) {
87 strcpy(dir->dd_dir.d_name, ".");
88 dir->dd_dir.d_type = DT_DIR;
89 } else if (!dir->got_dotdot) {
90 strcpy(dir->dd_dir.d_name, "..");
91 dir->dd_dir.d_type = DT_DIR;
82 } else { 92 } else {
83 DWORD lasterr = GetLastError(); 93 DWORD lasterr = GetLastError();
84 /* POSIX says you shouldn't set errno when readdir can't 94 /* POSIX says you shouldn't set errno when readdir can't
@@ -89,7 +99,15 @@ struct dirent *readdir(DIR *dir)
89 } 99 }
90 } 100 }
91 101
92 ++dir->dd_stat; 102 /* Have we seen '.' or '..'? */
103 if (dir->dd_dir.d_name[0] == '.') {
104 if (dir->dd_dir.d_name[1] == '\0')
105 dir->got_dot = TRUE;
106 else if (dir->dd_dir.d_name[1] == '.' && dir->dd_dir.d_name[2] == '\0')
107 dir->got_dotdot = TRUE;
108 }
109
110 dir->not_first = TRUE;
93 return &dir->dd_dir; 111 return &dir->dd_dir;
94} 112}
95 113
diff --git a/win32/glob.c b/win32/glob.c
index 1cc6483e7..35a1e9a65 100644
--- a/win32/glob.c
+++ b/win32/glob.c
@@ -298,7 +298,7 @@ int glob(const char *restrict pat, int flags, int (*errfunc)(const char *path, i
298 if (append(&tail, pat, strlen(pat), 0)) 298 if (append(&tail, pat, strlen(pat), 0))
299 return GLOB_NOSPACE; 299 return GLOB_NOSPACE;
300 cnt++; 300 cnt++;
301 } else 301 } else if (!error)
302 return GLOB_NOMATCH; 302 return GLOB_NOMATCH;
303 } 303 }
304 304
diff --git a/win32/inet_pton.c b/win32/inet_pton.c
index f229a9355..eec8bd2fe 100644
--- a/win32/inet_pton.c
+++ b/win32/inet_pton.c
@@ -78,6 +78,7 @@ int inet_pton(int af, const char *restrict s, void *restrict a0)
78 if (s[j]!='.' || (i<6 && brk<0)) return 0; 78 if (s[j]!='.' || (i<6 && brk<0)) return 0;
79 need_v4=1; 79 need_v4=1;
80 i++; 80 i++;
81 ip[i&7]=0;
81 break; 82 break;
82 } 83 }
83 s += j+1; 84 s += j+1;
diff --git a/win32/ioctl.c b/win32/ioctl.c
index 93f9f504d..d0ed68d61 100644
--- a/win32/ioctl.c
+++ b/win32/ioctl.c
@@ -1,5 +1,7 @@
1#include "libbb.h" 1#include "libbb.h"
2#include "lazyload.h"
2 3
4#if ENABLE_STTY || ENABLE_TTYSIZE
3static int mingw_get_terminal_width_height(struct winsize *win) 5static int mingw_get_terminal_width_height(struct winsize *win)
4{ 6{
5 int fd; 7 int fd;
@@ -21,6 +23,45 @@ static int mingw_get_terminal_width_height(struct winsize *win)
21 23
22 return -1; 24 return -1;
23} 25}
26#endif
27
28#if ENABLE_STTY
29static int mingw_set_terminal_width_height(struct winsize *win)
30{
31 BOOL ret;
32 DECLARE_PROC_ADDR(BOOL, GetConsoleScreenBufferInfoEx, HANDLE,
33 PCONSOLE_SCREEN_BUFFER_INFOEX);
34 DECLARE_PROC_ADDR(BOOL, SetConsoleScreenBufferInfoEx, HANDLE,
35 PCONSOLE_SCREEN_BUFFER_INFOEX);
36
37 if (!INIT_PROC_ADDR(kernel32.dll, GetConsoleScreenBufferInfoEx))
38 return -1;
39 if (!INIT_PROC_ADDR(kernel32.dll, SetConsoleScreenBufferInfoEx))
40 return -1;
41
42 for (int fd = STDOUT_FILENO; fd <= STDERR_FILENO; ++fd) {
43 CONSOLE_SCREEN_BUFFER_INFOEX sbi;
44 HANDLE handle = (HANDLE)_get_osfhandle(fd);
45
46 sbi.cbSize = sizeof(sbi);
47 if (handle != INVALID_HANDLE_VALUE &&
48 (ret=GetConsoleScreenBufferInfoEx(handle, &sbi)) != 0) {
49 if (sbi.dwSize.X != win->ws_col) {
50 sbi.dwSize.X = win->ws_col;
51 }
52 if (sbi.dwSize.Y < win->ws_row) {
53 sbi.dwSize.Y = win->ws_row;
54 }
55 sbi.srWindow.Bottom = sbi.srWindow.Top + win->ws_row;
56 sbi.srWindow.Right = sbi.srWindow.Left + win->ws_col;
57 ret = SetConsoleScreenBufferInfoEx(handle, &sbi);
58 break;
59 }
60 }
61
62 return ret ? 0 : -1;
63}
64#endif
24 65
25int ioctl(int fd UNUSED_PARAM, int code, ...) 66int ioctl(int fd UNUSED_PARAM, int code, ...)
26{ 67{
@@ -31,10 +72,18 @@ int ioctl(int fd UNUSED_PARAM, int code, ...)
31 va_start(ap, code); 72 va_start(ap, code);
32 73
33 switch (code) { 74 switch (code) {
75#if ENABLE_STTY || ENABLE_TTYSIZE
34 case TIOCGWINSZ: 76 case TIOCGWINSZ:
35 arg = va_arg(ap, void *); 77 arg = va_arg(ap, void *);
36 ret = mingw_get_terminal_width_height((struct winsize *)arg); 78 ret = mingw_get_terminal_width_height((struct winsize *)arg);
37 break; 79 break;
80#endif
81#if ENABLE_STTY
82 case TIOCSWINSZ:
83 arg = va_arg(ap, void *);
84 ret = mingw_set_terminal_width_height((struct winsize *)arg);
85 break;
86#endif
38 default: 87 default:
39 ret = -1; 88 ret = -1;
40 errno = EINVAL; 89 errno = EINVAL;
diff --git a/win32/mingw.c b/win32/mingw.c
index 7a5198ccf..061e7bac6 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -2538,3 +2538,34 @@ char * FAST_FUNC exe_relative_path(const char *tail)
2538 free(exepath); 2538 free(exepath);
2539 return relpath; 2539 return relpath;
2540} 2540}
2541
2542int mingw_shell_execute(SHELLEXECUTEINFO *info)
2543{
2544 DECLARE_PROC_ADDR(BOOL, ShellExecuteExA, SHELLEXECUTEINFOA *);
2545 char *lpath;
2546 int ret;
2547
2548 if (!INIT_PROC_ADDR(shell32.dll, ShellExecuteExA)) {
2549 errno = ENOSYS;
2550 return FALSE;
2551 }
2552
2553 // ShellExecuteEx() needs backslash as separator in UNC paths.
2554 lpath = xstrdup(info->lpFile);
2555 slash_to_bs(lpath);
2556 info->lpFile = lpath;
2557
2558 ret = ShellExecuteExA(info);
2559
2560 free(lpath);
2561 return ret;
2562}
2563
2564#if ENABLE_FEATURE_USE_CNG_API
2565void mingw_die_if_error(NTSTATUS status, const char *function_name) {
2566 if (!NT_SUCCESS(status)) {
2567 bb_error_msg_and_die("call to %s failed: 0x%08lX",
2568 function_name, (unsigned long)status);
2569 }
2570}
2571#endif
diff --git a/win32/process.c b/win32/process.c
index e7c9ca187..33f45ee42 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -331,7 +331,9 @@ mingw_spawn_interpreter(int mode, const char *prog, char *const *argv,
331 } else { 331 } else {
332 errno = ENOENT; 332 errno = ENOENT;
333 } 333 }
334#if ENABLE_FEATURE_PREFER_APPLETS && NUM_APPLETS > 1
334 done: 335 done:
336#endif
335 free(path); 337 free(path);
336 free(new_argv); 338 free(new_argv);
337 return ret; 339 return ret;
@@ -499,6 +501,38 @@ static NORETURN void wait_for_child(HANDLE child, const char *cmd)
499 exit((int)code); 501 exit((int)code);
500} 502}
501 503
504static intptr_t
505shell_execute(const char *path, char *const *argv)
506{
507 SHELLEXECUTEINFO info;
508 char *args;
509
510 memset(&info, 0, sizeof(SHELLEXECUTEINFO));
511 info.cbSize = sizeof(SHELLEXECUTEINFO);
512 info.fMask = SEE_MASK_NOCLOSEPROCESS;
513 /* info.hwnd = NULL; */
514 info.lpVerb = "runas";
515 info.lpFile = path;
516
517 args = NULL;
518 if (*argv++) {
519 while (*argv) {
520 char *q = quote_arg(*argv++);
521 args = xappendword(args, q);
522 free(q);
523 }
524 }
525
526 info.lpParameters = args;
527 /* info.lpDirectory = NULL; */
528 info.nShow = SW_SHOWNORMAL;
529
530 mingw_shell_execute(&info);
531
532 free(args);
533 return info.hProcess ? (intptr_t)info.hProcess : -1;
534}
535
502int 536int
503mingw_execvp(const char *cmd, char *const *argv) 537mingw_execvp(const char *cmd, char *const *argv)
504{ 538{
@@ -512,6 +546,16 @@ int
512mingw_execve(const char *cmd, char *const *argv, char *const *envp) 546mingw_execve(const char *cmd, char *const *argv, char *const *envp)
513{ 547{
514 intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0); 548 intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0);
549
550 if (ret == -1 && GetLastError() == ERROR_ELEVATION_REQUIRED) {
551 // Command exists but failed because it wants elevated privileges.
552 // Try again using ShellExecuteEx().
553 SetLastError(0);
554 ret = shell_execute(cmd, argv);
555 if (GetLastError())
556 exit(1);
557 }
558
515 if (ret != -1) 559 if (ret != -1)
516 wait_for_child((HANDLE)ret, cmd); 560 wait_for_child((HANDLE)ret, cmd);
517 return ret; 561 return ret;
diff --git a/win32/select.c b/win32/select.c
index 2be221ac8..46a051cfc 100644
--- a/win32/select.c
+++ b/win32/select.c
@@ -273,8 +273,11 @@ mingw_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
273 int i, fd, rc; 273 int i, fd, rc;
274 clock_t tend = 0; 274 clock_t tend = 0;
275 275
276 if (nfds > FD_SETSIZE) 276 if (nfds < 0 || nfds > FD_SETSIZE)
277 nfds = FD_SETSIZE; 277 {
278 errno = EINVAL;
279 return -1;
280 }
278 281
279 if (!timeout) 282 if (!timeout)
280 wait_timeout = INFINITE; 283 wait_timeout = INFINITE;
diff --git a/win32/strptime.c b/win32/strptime.c
index 3205b95a2..c12e96202 100644
--- a/win32/strptime.c
+++ b/win32/strptime.c
@@ -1,23 +1,23 @@
1/* Copyright (C) 2002, 2004-2005, 2007, 2009-2020 Free Software Foundation, 1/* Copyright (C) 2002, 2004-2005, 2007, 2009-2024 Free Software Foundation,
2 Inc. 2 Inc.
3 This file is part of the GNU C Library. 3 This file is part of the GNU C Library.
4 4
5 This program is free software; you can redistribute it and/or modify 5 This file is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU Lesser General Public License as
7 the Free Software Foundation; either version 2, or (at your option) 7 published by the Free Software Foundation; either version 2.1 of the
8 any later version. 8 License, or (at your option) any later version.
9 9
10 This program is distributed in the hope that it will be useful, 10 This file is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details. 13 GNU Lesser General Public License for more details.
14 14
15 You should have received a copy of the GNU General Public License along 15 You should have received a copy of the GNU Lesser General Public License
16 with this program; if not, see <https://www.gnu.org/licenses/>. */ 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 17
18/* 18/*
19 * File from gnulib (https://www.gnu.org/software/gnulib/), processed with 19 * File from gnulib (https://www.gnu.org/software/gnulib/), processed with
20 * coan source -U_LIBC -U_NL_CURRENT -UHAVE_TM_GMTOFF strptime.c 20 * coan source -U_LIBC -U_NL_CURRENT -UHAVE_STRUCT_TM_TM_GMTOFF strptime.c
21 * and lightly edited. 21 * and lightly edited.
22 * 22 *
23 * A form of support for tm_gmtoff was later restored. 23 * A form of support for tm_gmtoff was later restored.
@@ -30,7 +30,7 @@
30#include <ctype.h> 30#include <ctype.h>
31#include <limits.h> 31#include <limits.h>
32#include <string.h> 32#include <string.h>
33#include <stdbool.h> 33#include <strings.h>
34 34
35 35
36enum ptime_locale_status { not, loc, raw }; 36enum ptime_locale_status { not, loc, raw };
@@ -543,23 +543,23 @@ __strptime_internal (const char *rp, const char *fmt, struct tm *tm,
543 543
544 if ((have_uweek || have_wweek) && have_wday) 544 if ((have_uweek || have_wweek) && have_wday)
545 { 545 {
546 int save_wday = tm->tm_wday; 546 int saved_wday = tm->tm_wday;
547 int save_mday = tm->tm_mday; 547 int saved_mday = tm->tm_mday;
548 int save_mon = tm->tm_mon; 548 int saved_mon = tm->tm_mon;
549 int w_offset = have_uweek ? 0 : 1; 549 int w_offset = have_uweek ? 0 : 1;
550 550
551 tm->tm_mday = 1; 551 tm->tm_mday = 1;
552 tm->tm_mon = 0; 552 tm->tm_mon = 0;
553 day_of_the_week (tm); 553 day_of_the_week (tm);
554 if (have_mday) 554 if (have_mday)
555 tm->tm_mday = save_mday; 555 tm->tm_mday = saved_mday;
556 if (have_mon) 556 if (have_mon)
557 tm->tm_mon = save_mon; 557 tm->tm_mon = saved_mon;
558 558
559 if (!have_yday) 559 if (!have_yday)
560 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7 560 tm->tm_yday = ((7 - (tm->tm_wday - w_offset)) % 7
561 + (week_no - 1) *7 561 + (week_no - 1) *7
562 + save_wday - w_offset); 562 + saved_wday - w_offset);
563 563
564 if (!have_mday || !have_mon) 564 if (!have_mday || !have_mon)
565 { 565 {
@@ -575,7 +575,7 @@ __strptime_internal (const char *rp, const char *fmt, struct tm *tm,
575 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); 575 - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1);
576 } 576 }
577 577
578 tm->tm_wday = save_wday; 578 tm->tm_wday = saved_wday;
579 } 579 }
580 580
581 return (char *) rp; 581 return (char *) rp;
diff --git a/win32/termios.c b/win32/termios.c
index f18ff7c3b..b94f68f59 100644
--- a/win32/termios.c
+++ b/win32/termios.c
@@ -2,12 +2,10 @@
2 2
3int tcsetattr(int fd, int mode UNUSED_PARAM, const struct termios *t) 3int tcsetattr(int fd, int mode UNUSED_PARAM, const struct termios *t)
4{ 4{
5 if (terminal_mode(FALSE) & VT_INPUT) { 5 HANDLE h = (HANDLE)_get_osfhandle(fd);
6 HANDLE h = (HANDLE)_get_osfhandle(fd); 6 if (!SetConsoleMode(h, t->w_mode)) {
7 if (!SetConsoleMode(h, t->imode)) { 7 errno = err_win_to_posix();
8 errno = err_win_to_posix(); 8 return -1;
9 return -1;
10 }
11 } 9 }
12 10
13 return 0; 11 return 0;
@@ -15,16 +13,20 @@ int tcsetattr(int fd, int mode UNUSED_PARAM, const struct termios *t)
15 13
16int tcgetattr(int fd, struct termios *t) 14int tcgetattr(int fd, struct termios *t)
17{ 15{
18 if (terminal_mode(FALSE) & VT_INPUT) { 16 HANDLE h = (HANDLE)_get_osfhandle(fd);
19 HANDLE h = (HANDLE)_get_osfhandle(fd); 17 if (!GetConsoleMode(h, &t->w_mode)) {
20 if (!GetConsoleMode(h, &t->imode)) { 18 errno = err_win_to_posix();
21 errno = err_win_to_posix(); 19 return -1;
22 return -1;
23 }
24 } 20 }
21
25 t->c_cc[VINTR] = 3; // ctrl-c 22 t->c_cc[VINTR] = 3; // ctrl-c
26 t->c_cc[VEOF] = 4; // ctrl-d 23 t->c_cc[VEOF] = 4; // ctrl-d
27 24
25 if (t->w_mode & ENABLE_ECHO_INPUT)
26 t->c_lflag |= ECHO;
27 else
28 t->c_lflag &= ~ECHO;
29
28 return 0; 30 return 0;
29} 31}
30 32
diff --git a/win32/termios.h b/win32/termios.h
index 8408aa3e3..60c51119b 100644
--- a/win32/termios.h
+++ b/win32/termios.h
@@ -1,23 +1,32 @@
1#ifndef TERMIOS_H 1#ifndef TERMIOS_H
2#define TERMIOS_H 2#define TERMIOS_H
3 3
4#define VINTR 0 4#define ECHO 0x0004
5#define VEOF 1
6 5
7#define TCIFLUSH 0 6#define VINTR 0
8#define TCSAFLUSH 1 7#define VEOF 1
9#define TCSANOW 2 8
10#define TCSADRAIN 3 9#define TCIFLUSH 0
11#define TCSADFLUSH 4 10#define TCSAFLUSH 1
11#define TCSANOW 2
12#define TCSADRAIN 3
13#define TCSADFLUSH 4
14
15#define CSIZE 0
12 16
13typedef unsigned char cc_t; 17typedef unsigned char cc_t;
18typedef unsigned int tcflag_t;
14typedef unsigned int speed_t; 19typedef unsigned int speed_t;
15 20
16#define NCCS 2 21#define NCCS 18
17struct termios { 22struct termios {
23 tcflag_t c_iflag;
24 tcflag_t c_oflag;
25 tcflag_t c_cflag;
26 tcflag_t c_lflag;
27 char c_line;
18 cc_t c_cc[NCCS]; 28 cc_t c_cc[NCCS];
19 unsigned long imode; 29 unsigned long w_mode;
20 unsigned long omode;
21}; 30};
22 31
23struct winsize { 32struct winsize {
diff --git a/win32/winansi.c b/win32/winansi.c
index c7529c453..9736f0568 100644
--- a/win32/winansi.c
+++ b/win32/winansi.c
@@ -160,7 +160,7 @@ int FAST_FUNC terminal_mode(int reset)
160 mode |= VT_INPUT; 160 mode |= VT_INPUT;
161 } 161 }
162 162
163 if (newmode != oldmode) { 163 if (reset && newmode != oldmode) {
164 if (!SetConsoleMode(h, newmode)) { 164 if (!SetConsoleMode(h, newmode)) {
165 if (mode >= 4) 165 if (mode >= 4)
166 mode &= ~VT_INPUT; 166 mode &= ~VT_INPUT;