From d32fc647d7da1923a91750ae937bf9b517195c8f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 1 Jul 2014 13:20:22 +0200 Subject: libbb: fix bb_ask() to flush input before prompt, not after. Closes 7190 Signed-off-by: Denys Vlasenko --- libbb/bb_askpass.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'libbb') diff --git a/libbb/bb_askpass.c b/libbb/bb_askpass.c index 77c1bcd95..1927ba9e9 100644 --- a/libbb/bb_askpass.c +++ b/libbb/bb_askpass.c @@ -30,9 +30,12 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt) struct sigaction sa, oldsa; struct termios tio, oldtio; + tcflush(fd, TCIFLUSH); + /* Was buggy: was printing prompt *before* flushing input, + * which was upsetting "expect" based scripts of some users. + */ fputs(prompt, stdout); fflush_all(); - tcflush(fd, TCIFLUSH); tcgetattr(fd, &oldtio); tio = oldtio; -- cgit v1.2.3-55-g6feb From 2a563ea49a16589f47ed6afe7b22eebef4e3a6d1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Jul 2014 17:24:13 +0200 Subject: sha3: add 32-bit optimized bit-sliced implementation It is an interesting trick, but so far I only managed to make it work correctly, not to make it faster and/or smaller. The code is ifdefed out for now. Signed-off-by: Denys Vlasenko --- libbb/hash_md5_sha.c | 256 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 242 insertions(+), 14 deletions(-) (limited to 'libbb') diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 3f743ac75..dff583ad1 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -926,10 +926,81 @@ void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) # define SHA3_SMALL CONFIG_SHA3_SMALL #endif +#define OPTIMIZE_SHA3_FOR_32 0 +/* + * SHA3 can be optimized for 32-bit CPUs with bit-slicing: + * every 64-bit word of state[] can be split into two 32-bit words + * by even/odd bits. In this form, all rotations of sha3 round + * are 32-bit - and there are lots of them. + * However, it requires either splitting/combining state words + * before/after sha3 round (code does this now) + * or shuffling bits before xor'ing them into state and in sha3_end. + * Without shuffling, bit-slicing results in -130 bytes of code + * and marginal speedup (but of course it gives wrong result). + * With shuffling it works, but +260 code bytes, and slower. + * Disabled for now: + */ +#if 0 /* LONG_MAX == 0x7fffffff */ +# undef OPTIMIZE_SHA3_FOR_32 +# define OPTIMIZE_SHA3_FOR_32 1 +#endif + enum { SHA3_IBLK_BYTES = 72, /* 576 bits / 8 */ }; +#if OPTIMIZE_SHA3_FOR_32 +/* This splits every 64-bit word into a pair of 32-bit words, + * even bits go into first word, odd bits go to second one. + * The conversion is done in-place. + */ +static void split_halves(uint64_t *state) +{ + /* Credit: Henry S. Warren, Hacker's Delight, Addison-Wesley, 2002 */ + uint32_t *s32 = (uint32_t*)state; + uint32_t t, x0, x1; + int i; + for (i = 24; i >= 0; --i) { + x0 = s32[0]; + t = (x0 ^ (x0 >> 1)) & 0x22222222; x0 = x0 ^ t ^ (t << 1); + t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0C; x0 = x0 ^ t ^ (t << 2); + t = (x0 ^ (x0 >> 4)) & 0x00F000F0; x0 = x0 ^ t ^ (t << 4); + t = (x0 ^ (x0 >> 8)) & 0x0000FF00; x0 = x0 ^ t ^ (t << 8); + x1 = s32[1]; + t = (x1 ^ (x1 >> 1)) & 0x22222222; x1 = x1 ^ t ^ (t << 1); + t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0C; x1 = x1 ^ t ^ (t << 2); + t = (x1 ^ (x1 >> 4)) & 0x00F000F0; x1 = x1 ^ t ^ (t << 4); + t = (x1 ^ (x1 >> 8)) & 0x0000FF00; x1 = x1 ^ t ^ (t << 8); + *s32++ = (x0 & 0x0000FFFF) | (x1 << 16); + *s32++ = (x0 >> 16) | (x1 & 0xFFFF0000); + } +} +/* The reverse operation */ +static void combine_halves(uint64_t *state) +{ + uint32_t *s32 = (uint32_t*)state; + uint32_t t, x0, x1; + int i; + for (i = 24; i >= 0; --i) { + x0 = s32[0]; + x1 = s32[1]; + t = (x0 & 0x0000FFFF) | (x1 << 16); + x1 = (x0 >> 16) | (x1 & 0xFFFF0000); + x0 = t; + t = (x0 ^ (x0 >> 8)) & 0x0000FF00; x0 = x0 ^ t ^ (t << 8); + t = (x0 ^ (x0 >> 4)) & 0x00F000F0; x0 = x0 ^ t ^ (t << 4); + t = (x0 ^ (x0 >> 2)) & 0x0C0C0C0C; x0 = x0 ^ t ^ (t << 2); + t = (x0 ^ (x0 >> 1)) & 0x22222222; x0 = x0 ^ t ^ (t << 1); + *s32++ = x0; + t = (x1 ^ (x1 >> 8)) & 0x0000FF00; x1 = x1 ^ t ^ (t << 8); + t = (x1 ^ (x1 >> 4)) & 0x00F000F0; x1 = x1 ^ t ^ (t << 4); + t = (x1 ^ (x1 >> 2)) & 0x0C0C0C0C; x1 = x1 ^ t ^ (t << 2); + t = (x1 ^ (x1 >> 1)) & 0x22222222; x1 = x1 ^ t ^ (t << 1); + *s32++ = x1; + } +} +#endif + /* * In the crypto literature this function is usually called Keccak-f(). */ @@ -937,6 +1008,164 @@ static void sha3_process_block72(uint64_t *state) { enum { NROUNDS = 24 }; +#if OPTIMIZE_SHA3_FOR_32 + /* + static const uint32_t IOTA_CONST_0[NROUNDS] = { + 0x00000001UL, + 0x00000000UL, + 0x00000000UL, + 0x00000000UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000000UL, + 0x00000000UL, + 0x00000001UL, + 0x00000000UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000001UL, + 0x00000000UL, + 0x00000000UL, + 0x00000000UL, + 0x00000000UL, + 0x00000001UL, + 0x00000000UL, + 0x00000001UL, + 0x00000000UL, + }; + ** bits are in lsb: 0101 0000 1111 0100 1111 0001 + */ + uint32_t IOTA_CONST_0bits = (uint32_t)(0x0050f4f1); + static const uint32_t IOTA_CONST_1[NROUNDS] = { + 0x00000000UL, + 0x00000089UL, + 0x8000008bUL, + 0x80008080UL, + 0x0000008bUL, + 0x00008000UL, + 0x80008088UL, + 0x80000082UL, + 0x0000000bUL, + 0x0000000aUL, + 0x00008082UL, + 0x00008003UL, + 0x0000808bUL, + 0x8000000bUL, + 0x8000008aUL, + 0x80000081UL, + 0x80000081UL, + 0x80000008UL, + 0x00000083UL, + 0x80008003UL, + 0x80008088UL, + 0x80000088UL, + 0x00008000UL, + 0x80008082UL, + }; + + uint32_t *const s32 = (uint32_t*)state; + unsigned round; + + split_halves(state); + + for (round = 0; round < NROUNDS; round++) { + unsigned x; + + /* Theta */ + { + uint32_t BC[20]; + for (x = 0; x < 10; ++x) { + BC[x+10] = BC[x] = s32[x]^s32[x+10]^s32[x+20]^s32[x+30]^s32[x+40]; + } + for (x = 0; x < 10; x += 2) { + uint32_t ta, tb; + ta = BC[x+8] ^ rotl32(BC[x+3], 1); + tb = BC[x+9] ^ BC[x+2]; + s32[x+0] ^= ta; + s32[x+1] ^= tb; + s32[x+10] ^= ta; + s32[x+11] ^= tb; + s32[x+20] ^= ta; + s32[x+21] ^= tb; + s32[x+30] ^= ta; + s32[x+31] ^= tb; + s32[x+40] ^= ta; + s32[x+41] ^= tb; + } + } + /* RhoPi */ + { + uint32_t t0a,t0b, t1a,t1b; + t1a = s32[1*2+0]; + t1b = s32[1*2+1]; + +#define RhoPi(PI_LANE, ROT_CONST) \ + t0a = s32[PI_LANE*2+0];\ + t0b = s32[PI_LANE*2+1];\ + if (ROT_CONST & 1) {\ + s32[PI_LANE*2+0] = rotl32(t1b, ROT_CONST/2+1);\ + s32[PI_LANE*2+1] = ROT_CONST == 1 ? t1a : rotl32(t1a, ROT_CONST/2+0);\ + } else {\ + s32[PI_LANE*2+0] = rotl32(t1a, ROT_CONST/2);\ + s32[PI_LANE*2+1] = rotl32(t1b, ROT_CONST/2);\ + }\ + t1a = t0a; t1b = t0b; + + RhoPi(10, 1) + RhoPi( 7, 3) + RhoPi(11, 6) + RhoPi(17,10) + RhoPi(18,15) + RhoPi( 3,21) + RhoPi( 5,28) + RhoPi(16,36) + RhoPi( 8,45) + RhoPi(21,55) + RhoPi(24, 2) + RhoPi( 4,14) + RhoPi(15,27) + RhoPi(23,41) + RhoPi(19,56) + RhoPi(13, 8) + RhoPi(12,25) + RhoPi( 2,43) + RhoPi(20,62) + RhoPi(14,18) + RhoPi(22,39) + RhoPi( 9,61) + RhoPi( 6,20) + RhoPi( 1,44) +#undef RhoPi + } + /* Chi */ + for (x = 0; x <= 20; x += 5) { + /* + * Can write this in terms of uint32 too, + * but why? compiler does it automatically. + */ + uint64_t BC0, BC1, BC2, BC3, BC4; + BC0 = state[x + 0]; + BC1 = state[x + 1]; + BC2 = state[x + 2]; + state[x + 0] = BC0 ^ ((~BC1) & BC2); + BC3 = state[x + 3]; + state[x + 1] = BC1 ^ ((~BC2) & BC3); + BC4 = state[x + 4]; + state[x + 2] = BC2 ^ ((~BC3) & BC4); + state[x + 3] = BC3 ^ ((~BC4) & BC0); + state[x + 4] = BC4 ^ ((~BC0) & BC1); + } + /* Iota */ + s32[0] ^= IOTA_CONST_0bits & 1; + IOTA_CONST_0bits >>= 1; + s32[1] ^= IOTA_CONST_1[round]; + } + + combine_halves(state); +#else /* Elements should be 64-bit, but top half is always zero or 0x80000000. * We encode 63rd bits in a separate word below. * Same is true for 31th bits, which lets us use 16-bit table instead of 64-bit. @@ -983,7 +1212,7 @@ static void sha3_process_block72(uint64_t *state) }; /*static const uint8_t MOD5[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, };*/ - unsigned x, y; + unsigned x; unsigned round; if (BB_BIG_ENDIAN) { @@ -1045,22 +1274,20 @@ static void sha3_process_block72(uint64_t *state) RhoPi_twice(20); RhoPi_twice(22); #undef RhoPi_twice } - /* Chi */ - for (y = 0; y <= 20; y += 5) { + for (x = 0; x <= 20; x += 5) { uint64_t BC0, BC1, BC2, BC3, BC4; - BC0 = state[y + 0]; - BC1 = state[y + 1]; - BC2 = state[y + 2]; - state[y + 0] = BC0 ^ ((~BC1) & BC2); - BC3 = state[y + 3]; - state[y + 1] = BC1 ^ ((~BC2) & BC3); - BC4 = state[y + 4]; - state[y + 2] = BC2 ^ ((~BC3) & BC4); - state[y + 3] = BC3 ^ ((~BC4) & BC0); - state[y + 4] = BC4 ^ ((~BC0) & BC1); + BC0 = state[x + 0]; + BC1 = state[x + 1]; + BC2 = state[x + 2]; + state[x + 0] = BC0 ^ ((~BC1) & BC2); + BC3 = state[x + 3]; + state[x + 1] = BC1 ^ ((~BC2) & BC3); + BC4 = state[x + 4]; + state[x + 2] = BC2 ^ ((~BC3) & BC4); + state[x + 3] = BC3 ^ ((~BC4) & BC0); + state[x + 4] = BC4 ^ ((~BC0) & BC1); } - /* Iota */ state[0] ^= IOTA_CONST[round] | (uint32_t)((IOTA_CONST_bit31 << round) & 0x80000000) @@ -1072,6 +1299,7 @@ static void sha3_process_block72(uint64_t *state) state[x] = SWAP_LE64(state[x]); } } +#endif } void FAST_FUNC sha3_begin(sha3_ctx_t *ctx) -- cgit v1.2.3-55-g6feb From 4ff933c0e7895bd1ac1fe9793117f4d69de35514 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 30 Jul 2014 14:18:57 +0200 Subject: sha3: code shrink (and speedup for SHA3_SMALL=0) function old new delta sha3_process_block72 1454 1359 -95 Signed-off-by: Denys Vlasenko --- libbb/hash_md5_sha.c | 82 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 66 insertions(+), 16 deletions(-) (limited to 'libbb') diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index dff583ad1..4cef2aba1 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -1141,22 +1141,30 @@ static void sha3_process_block72(uint64_t *state) #undef RhoPi } /* Chi */ - for (x = 0; x <= 20; x += 5) { - /* - * Can write this in terms of uint32 too, - * but why? compiler does it automatically. - */ - uint64_t BC0, BC1, BC2, BC3, BC4; - BC0 = state[x + 0]; - BC1 = state[x + 1]; - BC2 = state[x + 2]; - state[x + 0] = BC0 ^ ((~BC1) & BC2); - BC3 = state[x + 3]; - state[x + 1] = BC1 ^ ((~BC2) & BC3); - BC4 = state[x + 4]; - state[x + 2] = BC2 ^ ((~BC3) & BC4); - state[x + 3] = BC3 ^ ((~BC4) & BC0); - state[x + 4] = BC4 ^ ((~BC0) & BC1); + for (x = 0; x <= 40;) { + uint32_t BC0, BC1, BC2, BC3, BC4; + BC0 = s32[x + 0*2]; + BC1 = s32[x + 1*2]; + BC2 = s32[x + 2*2]; + s32[x + 0*2] = BC0 ^ ((~BC1) & BC2); + BC3 = s32[x + 3*2]; + s32[x + 1*2] = BC1 ^ ((~BC2) & BC3); + BC4 = s32[x + 4*2]; + s32[x + 2*2] = BC2 ^ ((~BC3) & BC4); + s32[x + 3*2] = BC3 ^ ((~BC4) & BC0); + s32[x + 4*2] = BC4 ^ ((~BC0) & BC1); + x++; + BC0 = s32[x + 0*2]; + BC1 = s32[x + 1*2]; + BC2 = s32[x + 2*2]; + s32[x + 0*2] = BC0 ^ ((~BC1) & BC2); + BC3 = s32[x + 3*2]; + s32[x + 1*2] = BC1 ^ ((~BC2) & BC3); + BC4 = s32[x + 4*2]; + s32[x + 2*2] = BC2 ^ ((~BC3) & BC4); + s32[x + 3*2] = BC3 ^ ((~BC4) & BC0); + s32[x + 4*2] = BC4 ^ ((~BC0) & BC1); + x += 9; } /* Iota */ s32[0] ^= IOTA_CONST_0bits & 1; @@ -1275,6 +1283,7 @@ static void sha3_process_block72(uint64_t *state) #undef RhoPi_twice } /* Chi */ +#if LONG_MAX > 0x7fffffff for (x = 0; x <= 20; x += 5) { uint64_t BC0, BC1, BC2, BC3, BC4; BC0 = state[x + 0]; @@ -1288,6 +1297,47 @@ static void sha3_process_block72(uint64_t *state) state[x + 3] = BC3 ^ ((~BC4) & BC0); state[x + 4] = BC4 ^ ((~BC0) & BC1); } +#else + /* Reduced register pressure version + * for register-starved 32-bit arches + * (i386: -95 bytes, and it is _faster_) + */ + for (x = 0; x <= 40;) { + uint32_t BC0, BC1, BC2, BC3, BC4; + uint32_t *const s32 = (uint32_t*)state; +# if SHA3_SMALL + do_half: +#endif + BC0 = s32[x + 0*2]; + BC1 = s32[x + 1*2]; + BC2 = s32[x + 2*2]; + s32[x + 0*2] = BC0 ^ ((~BC1) & BC2); + BC3 = s32[x + 3*2]; + s32[x + 1*2] = BC1 ^ ((~BC2) & BC3); + BC4 = s32[x + 4*2]; + s32[x + 2*2] = BC2 ^ ((~BC3) & BC4); + s32[x + 3*2] = BC3 ^ ((~BC4) & BC0); + s32[x + 4*2] = BC4 ^ ((~BC0) & BC1); + x++; +# if SHA3_SMALL + if (x & 1) + goto do_half; + x += 8; +# else + BC0 = s32[x + 0*2]; + BC1 = s32[x + 1*2]; + BC2 = s32[x + 2*2]; + s32[x + 0*2] = BC0 ^ ((~BC1) & BC2); + BC3 = s32[x + 3*2]; + s32[x + 1*2] = BC1 ^ ((~BC2) & BC3); + BC4 = s32[x + 4*2]; + s32[x + 2*2] = BC2 ^ ((~BC3) & BC4); + s32[x + 3*2] = BC3 ^ ((~BC4) & BC0); + s32[x + 4*2] = BC4 ^ ((~BC0) & BC1); + x += 9; +# endif + } +#endif /* Iota */ state[0] ^= IOTA_CONST[round] | (uint32_t)((IOTA_CONST_bit31 << round) & 0x80000000) -- cgit v1.2.3-55-g6feb From 09a0e2223f68a266749043bf33c84faeb5cee8a0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 30 Jul 2014 16:26:09 +0200 Subject: sha3: tweak comments and indentation Signed-off-by: Denys Vlasenko --- libbb/hash_md5_sha.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'libbb') diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 4cef2aba1..1f63ccdee 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -1174,12 +1174,13 @@ static void sha3_process_block72(uint64_t *state) combine_halves(state); #else - /* Elements should be 64-bit, but top half is always zero or 0x80000000. - * We encode 63rd bits in a separate word below. - * Same is true for 31th bits, which lets us use 16-bit table instead of 64-bit. - * The speed penalty is lost in the noise. - */ + /* Native 64-bit algorithm */ static const uint16_t IOTA_CONST[NROUNDS] = { + /* Elements should be 64-bit, but top half is always zero + * or 0x80000000. We encode 63rd bits in a separate word below. + * Same is true for 31th bits, which lets us use 16-bit table + * instead of 64-bit. The speed penalty is lost in the noise. + */ 0x0001, 0x8082, 0x808a, @@ -1283,7 +1284,7 @@ static void sha3_process_block72(uint64_t *state) #undef RhoPi_twice } /* Chi */ -#if LONG_MAX > 0x7fffffff +# if LONG_MAX > 0x7fffffff for (x = 0; x <= 20; x += 5) { uint64_t BC0, BC1, BC2, BC3, BC4; BC0 = state[x + 0]; @@ -1297,7 +1298,7 @@ static void sha3_process_block72(uint64_t *state) state[x + 3] = BC3 ^ ((~BC4) & BC0); state[x + 4] = BC4 ^ ((~BC0) & BC1); } -#else +# else /* Reduced register pressure version * for register-starved 32-bit arches * (i386: -95 bytes, and it is _faster_) @@ -1305,9 +1306,9 @@ static void sha3_process_block72(uint64_t *state) for (x = 0; x <= 40;) { uint32_t BC0, BC1, BC2, BC3, BC4; uint32_t *const s32 = (uint32_t*)state; -# if SHA3_SMALL +# if SHA3_SMALL do_half: -#endif +# endif BC0 = s32[x + 0*2]; BC1 = s32[x + 1*2]; BC2 = s32[x + 2*2]; @@ -1319,11 +1320,11 @@ static void sha3_process_block72(uint64_t *state) s32[x + 3*2] = BC3 ^ ((~BC4) & BC0); s32[x + 4*2] = BC4 ^ ((~BC0) & BC1); x++; -# if SHA3_SMALL +# if SHA3_SMALL if (x & 1) goto do_half; x += 8; -# else +# else BC0 = s32[x + 0*2]; BC1 = s32[x + 1*2]; BC2 = s32[x + 2*2]; @@ -1335,9 +1336,9 @@ static void sha3_process_block72(uint64_t *state) s32[x + 3*2] = BC3 ^ ((~BC4) & BC0); s32[x + 4*2] = BC4 ^ ((~BC0) & BC1); x += 9; -# endif +# endif } -#endif +# endif /* long is 32-bit */ /* Iota */ state[0] ^= IOTA_CONST[round] | (uint32_t)((IOTA_CONST_bit31 << round) & 0x80000000) -- cgit v1.2.3-55-g6feb From feac9b607dc68ea63992a46b3b8361f00f663cdc Mon Sep 17 00:00:00 2001 From: Morten Kvistgaard Date: Tue, 5 Aug 2014 21:57:18 +0200 Subject: ftpd: add optional support for authentication function old new delta cmdio_get_cmd_and_arg - 237 +237 get_passwd - 97 +97 check_password - 82 +82 ftpd_main 2297 2178 -119 ask_and_check_password_extended 206 84 -122 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 0/2 up/down: 416/-241) Total: 175 bytes Signed-off-by: Morten Kvistgaard Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 + libbb/Kbuild.src | 1 + libbb/correct_password.c | 96 +++++++++++++++++++++++++++++++++--------------- networking/Config.src | 7 ++++ networking/ftpd.c | 47 ++++++++++++------------ 5 files changed, 100 insertions(+), 52 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index 858084bc5..ff223dd0f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1316,6 +1316,7 @@ int sd_listen_fds(void); #define SETUP_ENV_NO_CHDIR (1 << 4) void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; void nuke_str(char *str) FAST_FUNC; +int check_password(const struct passwd *pw, const char *plaintext) FAST_FUNC; int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC; int ask_and_check_password(const struct passwd *pw) FAST_FUNC; /* Returns a malloced string */ diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 62680bd52..0a9e803d7 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -150,6 +150,7 @@ lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o lib-$(CONFIG_FEATURE_HTTPD_AUTH_MD5) += pw_encrypt.o +lib-$(CONFIG_FEATURE_FTP_AUTHENTICATION) += pw_encrypt.o lib-$(CONFIG_DF) += find_mount_point.o lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o diff --git a/libbb/correct_password.c b/libbb/correct_password.c index acadf3914..513c93028 100644 --- a/libbb/correct_password.c +++ b/libbb/correct_password.c @@ -30,6 +30,63 @@ #include "libbb.h" +#define SHADOW_BUFSIZE 256 + +/* Retrieve encrypted password string for pw. + * If pw == NULL, return a string which fails password check against any + * password. + */ +#if !ENABLE_FEATURE_SHADOWPASSWDS +#define get_passwd(pw, buffer) get_passwd(pw) +#endif +static const char *get_passwd(const struct passwd *pw, char buffer[SHADOW_BUFSIZE]) +{ + const char *pass; + + if (!pw) + return "aa"; /* "aa" will never match */ + + pass = pw->pw_passwd; +#if ENABLE_FEATURE_SHADOWPASSWDS + /* Using _r function to avoid pulling in static buffers */ + if ((pass[0] == 'x' || pass[0] == '*') && !pass[1]) { + struct spwd spw; + int r; + /* getspnam_r may return 0 yet set result to NULL. + * At least glibc 2.4 does this. Be extra paranoid here. */ + struct spwd *result = NULL; + r = getspnam_r(pw->pw_name, &spw, buffer, SHADOW_BUFSIZE, &result); + pass = (r || !result) ? "aa" : result->sp_pwdp; + } +#endif + return pass; +} + +/* + * Return 1 if PW has an empty password. + * Return 1 if the user gives the correct password for entry PW, + * 0 if not. + * NULL pw means "just fake it for login with bad username" + */ +int FAST_FUNC check_password(const struct passwd *pw, const char *plaintext) +{ + IF_FEATURE_SHADOWPASSWDS(char buffer[SHADOW_BUFSIZE];) + char *encrypted; + const char *pw_pass; + int r; + + pw_pass = get_passwd(pw, buffer); + if (!pw_pass[0]) { /* empty password field? */ + return 1; + } + + encrypted = pw_encrypt(plaintext, /*salt:*/ pw_pass, 1); + r = (strcmp(encrypted, pw_pass) == 0); + free(encrypted); + return r; +} + + /* Ask the user for a password. * Return 1 without asking if PW has an empty password. * Return -1 on EOF, error while reading input, or timeout. @@ -41,42 +98,23 @@ int FAST_FUNC ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) { - char *unencrypted, *encrypted; - const char *correct; + IF_FEATURE_SHADOWPASSWDS(char buffer[SHADOW_BUFSIZE];) + char *plaintext; + const char *pw_pass; int r; - /* fake salt. crypt() can choke otherwise. */ - correct = "aa"; - if (!pw) { - /* "aa" will never match */ - goto fake_it; - } - correct = pw->pw_passwd; -#if ENABLE_FEATURE_SHADOWPASSWDS - /* Using _r function to avoid pulling in static buffers */ - if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) { - struct spwd spw; - char buffer[256]; - /* getspnam_r may return 0 yet set result to NULL. - * At least glibc 2.4 does this. Be extra paranoid here. */ - struct spwd *result = NULL; - r = getspnam_r(pw->pw_name, &spw, buffer, sizeof(buffer), &result); - correct = (r || !result) ? "aa" : result->sp_pwdp; - } -#endif - if (!correct[0]) /* empty password field? */ + pw_pass = get_passwd(pw, buffer); + if (!pw_pass[0]) /* empty password field? */ return 1; - fake_it: - unencrypted = bb_ask(STDIN_FILENO, timeout, prompt); - if (!unencrypted) { + plaintext = bb_ask(STDIN_FILENO, timeout, prompt); + if (!plaintext) { /* EOF (such as ^D) or error (such as ^C) or timeout */ return -1; } - encrypted = pw_encrypt(unencrypted, correct, 1); - r = (strcmp(encrypted, correct) == 0); - free(encrypted); - nuke_str(unencrypted); + + r = check_password(pw, plaintext); + nuke_str(plaintext); return r; } diff --git a/networking/Config.src b/networking/Config.src index fbad7ecb2..e56646917 100644 --- a/networking/Config.src +++ b/networking/Config.src @@ -134,6 +134,13 @@ config FEATURE_FTPD_ACCEPT_BROKEN_LIST it increases the code size by ~40 bytes. Most other ftp servers seem to behave similar to this. +config FEATURE_FTP_AUTHENTICATION + bool "Enable authentication" + default y + depends on FTPD + help + Enable basic system login as seen in telnet etc. + config FTPGET bool "ftpget" default y diff --git a/networking/ftpd.c b/networking/ftpd.c index 2d2a3a44c..9fcc3e963 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -1172,18 +1172,6 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) if (logmode) applet_name = xasprintf("%s[%u]", applet_name, (int)getpid()); -#if !BB_MMU - G.root_fd = -1; -#endif - argv += optind; - if (argv[0]) { -#if !BB_MMU - G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY); - close_on_exec_on(G.root_fd); -#endif - xchroot(argv[0]); - } - //umask(077); - admin can set umask before starting us /* Signals. We'll always take -EPIPE rather than a rude signal, thanks */ @@ -1199,23 +1187,22 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) WRITE_OK(FTP_GREET); signal(SIGALRM, timeout_handler); -#ifdef IF_WE_WANT_TO_REQUIRE_LOGIN +#if ENABLE_FEATURE_FTP_AUTHENTICATION { - smallint user_was_specified = 0; + struct passwd *pw = NULL; + while (1) { uint32_t cmdval = cmdio_get_cmd_and_arg(); if (cmdval == const_USER) { - if (G.ftp_arg == NULL || strcasecmp(G.ftp_arg, "anonymous") != 0) - cmdio_write_raw(STR(FTP_LOGINERR)" Server is anonymous only\r\n"); - else { - user_was_specified = 1; - cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify the password\r\n"); - } + pw = getpwnam(G.ftp_arg); + cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify password\r\n"); } else if (cmdval == const_PASS) { - if (user_was_specified) - break; - cmdio_write_raw(STR(FTP_NEEDUSER)" Login with USER\r\n"); + if (check_password(pw, G.ftp_arg) > 0) { + break; /* login success */ + } + cmdio_write_raw(STR(FTP_LOGINERR)" Login failed\r\n"); + pw = NULL; } else if (cmdval == const_QUIT) { WRITE_OK(FTP_GOODBYE); return 0; @@ -1223,10 +1210,24 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n"); } } + change_identity(pw); } WRITE_OK(FTP_LOGINOK); #endif + /* Do this after auth, else /etc/passwd is not accessible */ +#if !BB_MMU + G.root_fd = -1; +#endif + argv += optind; + if (argv[0]) { +#if !BB_MMU + G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY); + close_on_exec_on(G.root_fd); +#endif + xchroot(argv[0]); + } + /* RFC-959 Section 5.1 * The following commands and options MUST be supported by every * server-FTP and user-FTP, except in cases where the underlying -- cgit v1.2.3-55-g6feb From 45b4ecc8689d1291b01793efab3ac25125e14e48 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 Aug 2014 20:33:18 +0200 Subject: init: if libc-based Unicode support is on, run setlocale(LC_ALL, "") at startup It is not clear why we were excluding init from this. The "getpid() != 1" clause was there from the beginning (2001) but not explained. Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'libbb') diff --git a/libbb/appletlib.c b/libbb/appletlib.c index f7c416ece..a0150854a 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -184,8 +184,7 @@ void lbb_prepare(const char *applet #endif applet_name = applet; - /* Set locale for everybody except 'init' */ - if (ENABLE_LOCALE_SUPPORT && getpid() != 1) + if (ENABLE_LOCALE_SUPPORT) setlocale(LC_ALL, ""); #if ENABLE_FEATURE_INDIVIDUAL -- cgit v1.2.3-55-g6feb From cd7a38a87d54f5421b379870ff866676f31923b2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 18 Sep 2014 00:47:05 +0200 Subject: false: make "false --help" exit with 1 function old new delta run_applet_no_and_exit 447 445 -2 Signed-off-by: Denys Vlasenko --- applets/applet_tables.c | 17 +++++++++++++++++ libbb/appletlib.c | 26 ++++++++++++++++++-------- 2 files changed, 35 insertions(+), 8 deletions(-) (limited to 'libbb') diff --git a/applets/applet_tables.c b/applets/applet_tables.c index 94b974e09..92bf1e447 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c @@ -14,6 +14,7 @@ #include #include #include +#include #undef ARRAY_SIZE #define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) @@ -49,6 +50,16 @@ static int cmp_name(const void *a, const void *b) return strcmp(aa->name, bb->name); } +static int str_isalnum_(const char *s) +{ + while (*s) { + if (!isalnum(*s) && *s != '_') + return 0; + s++; + } + return 1; +} + int main(int argc, char **argv) { int i; @@ -94,6 +105,12 @@ int main(int argc, char **argv) } printf(";\n\n"); + for (i = 0; i < NUM_APPLETS; i++) { + if (str_isalnum_(applets[i].name)) + printf("#define APPLET_NO_%s %d\n", applets[i].name, i); + } + printf("\n"); + printf("#ifndef SKIP_applet_main\n"); printf("int (*const applet_main[])(int argc, char **argv) = {\n"); for (i = 0; i < NUM_APPLETS; i++) { diff --git a/libbb/appletlib.c b/libbb/appletlib.c index a0150854a..cb16e310f 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -745,15 +745,25 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) /* Reinit some shared global data */ xfunc_error_retval = EXIT_FAILURE; - applet_name = APPLET_NAME(applet_no); - if (argc == 2 && strcmp(argv[1], "--help") == 0) { - /* Special case. POSIX says "test --help" - * should be no different from e.g. "test --foo". */ -//TODO: just compare applet_no with APPLET_NO_test - if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) { - /* If you want "foo --help" to return 0: */ - xfunc_error_retval = 0; + +#if defined APPLET_NO_test + /* Special case. POSIX says "test --help" + * should be no different from e.g. "test --foo". + * Thus for "test", we skip --help check. + */ + if (applet_no != APPLET_NO_test) +#endif + { + if (argc == 2 && strcmp(argv[1], "--help") == 0) { +#if defined APPLET_NO_false + /* Someone insisted that "false --help" must exit 1. Sigh */ + if (applet_no != APPLET_NO_false) +#endif + { + /* Make "foo --help" exit with 0: */ + xfunc_error_retval = 0; + } bb_show_usage(); } } -- cgit v1.2.3-55-g6feb From d6e7672545c717497490c0b0f54f64594f374f9d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 22 Sep 2014 21:14:02 +0200 Subject: less: move "retry-on-EAGAIN" logic closer to read ops This makes "G" (goto end of input) command work as well as /search_for_nonexistent_string: both will read to EOF now even from somewhat slow input (such as kernel's "git log"). function old new delta ndelay_on 35 43 +8 ndelay_off 35 43 +8 read_lines 695 691 -4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 16/-4) Total: 12 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 4 ++-- libbb/xfuncs.c | 10 ++++++---- miscutils/less.c | 47 +++++++++++++++++++++-------------------------- 3 files changed, 29 insertions(+), 32 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index ff223dd0f..d57f00e0e 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -390,8 +390,8 @@ const char *bb_basename(const char *name) FAST_FUNC; char *last_char_is(const char *s, int c) FAST_FUNC; const char* endofname(const char *name) FAST_FUNC; -void ndelay_on(int fd) FAST_FUNC; -void ndelay_off(int fd) FAST_FUNC; +int ndelay_on(int fd) FAST_FUNC; +int ndelay_off(int fd) FAST_FUNC; void close_on_exec_on(int fd) FAST_FUNC; void xdup2(int, int) FAST_FUNC; void xmove_fd(int, int) FAST_FUNC; diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 23f27516f..f25ce9446 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -25,20 +25,22 @@ #include "libbb.h" /* Turn on nonblocking I/O on a fd */ -void FAST_FUNC ndelay_on(int fd) +int FAST_FUNC ndelay_on(int fd) { int flags = fcntl(fd, F_GETFL); if (flags & O_NONBLOCK) - return; + return flags; fcntl(fd, F_SETFL, flags | O_NONBLOCK); + return flags; } -void FAST_FUNC ndelay_off(int fd) +int FAST_FUNC ndelay_off(int fd) { int flags = fcntl(fd, F_GETFL); if (!(flags & O_NONBLOCK)) - return; + return flags; fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + return flags; } void FAST_FUNC close_on_exec_on(int fd) diff --git a/miscutils/less.c b/miscutils/less.c index 719af5a0d..3016c5b47 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -414,10 +414,10 @@ static void read_lines(void) char *current_line, *p; int w = width; char last_terminated = terminated; + time_t last_time = 0; + int retry_EAGAIN = 2; #if ENABLE_FEATURE_LESS_REGEXP unsigned old_max_fline = max_fline; - time_t last_time = 0; - int had_progress = 2; #endif /* (careful: max_fline can be -1) */ @@ -427,8 +427,6 @@ static void read_lines(void) if (option_mask32 & FLAG_N) w -= 8; - IF_FEATURE_LESS_REGEXP(again0:) - p = current_line = ((char*)xmalloc(w + 4)) + 4; max_fline += last_terminated; if (!last_terminated) { @@ -448,15 +446,29 @@ static void read_lines(void) char c; /* if no unprocessed chars left, eat more */ if (readpos >= readeof) { - errno = 0; - ndelay_on(0); - eof_error = safe_read(STDIN_FILENO, readbuf, sizeof(readbuf)); - ndelay_off(0); + int flags = ndelay_on(0); + + while (1) { + time_t t; + + errno = 0; + eof_error = safe_read(STDIN_FILENO, readbuf, sizeof(readbuf)); + if (errno != EAGAIN) + break; + t = time(NULL); + if (t != last_time) { + last_time = t; + if (--retry_EAGAIN < 0) + break; + } + sched_yield(); + } + fcntl(0, F_SETFL, flags); /* ndelay_off(0) */ readpos = 0; readeof = eof_error; if (eof_error <= 0) goto reached_eof; - IF_FEATURE_LESS_REGEXP(had_progress = 1;) + retry_EAGAIN = 1; } c = readbuf[readpos]; /* backspace? [needed for manpages] */ @@ -534,24 +546,7 @@ static void read_lines(void) #endif } if (eof_error <= 0) { -#if !ENABLE_FEATURE_LESS_REGEXP break; -#else - if (wanted_match < num_matches) { - break; - } /* else: goto_match() called us */ - if (errno == EAGAIN) { - time_t t = time(NULL); - if (t != last_time) { - last_time = t; - if (--had_progress < 0) - break; - } - sched_yield(); - goto again0; - } - break; -#endif } max_fline++; current_line = ((char*)xmalloc(w + 4)) + 4; -- cgit v1.2.3-55-g6feb