From patchwork Mon May 21 17:38:50 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zack Weinberg X-Patchwork-Id: 917765 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-92638-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=panix.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="bpvUWvUD"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40qQyG3nVdz9s1w for ; Tue, 22 May 2018 03:39:34 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; q=dns; s= default; b=U+IVrQpcOUhw9e+kGjv2TPIp5JGDwBxpGd31KLFKeKVeCX5k/nhhY 2ti9xgj9fgejoz51VzhZX7QtvTx0MLcy2A64vjqPPt2V3gvVjDUgFBgBdWhK7G5A CDhABoyDGyiIurJI4ip6RNSCa0pCjt0CTQ5gTD57cFwPGS9wvyNpoM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; s=default; bh=FdvvId7HHCG00ROM2g9TokYNZEI=; b=bpvUWvUDG0wV/YxJLMzJjEoYzVnC Ehou4dc69dj/pEClP3WgN9Y0N+cLNT9nzI0j7SsU2y72ckHytWur2mqg0Ztl3Z0v GFbstH1yg/JiFqsFPalq53JSYlMNFR3+Y7VN+pWgNLYBhViya+DDOfHc3qkgecyy mCzquBuneLK1yXc= Received: (qmail 111005 invoked by alias); 21 May 2018 17:39:05 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 110467 invoked by uid 89); 21 May 2018 17:39:01 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_PASS autolearn=ham version=3.3.2 spammy=secure, knowledge, Numbers, comply X-HELO: mailbackend.panix.com From: Zack Weinberg To: libc-alpha@sourceware.org Cc: carlos@redhat.com, fweimer@redhat.com, rj@2c3t.io, kukuk@suse.de Subject: [PATCH 1/4] Disallow use of DES encryption functions in new programs. Date: Mon, 21 May 2018 13:38:50 -0400 Message-Id: <20180521173853.5172-2-zackw@panix.com> In-Reply-To: <20180521173853.5172-1-zackw@panix.com> References: <20180521173853.5172-1-zackw@panix.com> MIME-Version: 1.0 The functions encrypt, setkey, encrypt_r, setkey_r, cbc_crypt, ecb_crypt, and des_setparity should not be used in new programs, because they use the DES block cipher, which is unacceptably weak by modern standards. Demote all of them to compatibility symbols, and remove their prototypes from installed headers. cbc_crypt, ecb_crypt, and des_setparity were already compat symbols when glibc was configured with --disable-obsolete-rpc. This is running a little ahead of POSIX, where encrypt and setkey are still part of the current standard, but I doubt anyone will mind. See for the progress of their removal from POSIX. The entire "DES Encryption" section is dropped from the manual, as is the mention of AUTH_DES and FIPS 140-2 in the introduction to crypt.texi. The documentation of 'memfrob' cross-referenced the DES Encryption section, which is replaced by a hyperlink to libgcrypt, and while I was in there I spruced up the actual documentation of 'memfrob' and 'strfry' a little. It's still fairly jokey, because those functions _are_ jokes, but they do also have real use cases, so people trying to use them for real should have all the information they need. DES-based authentication for Sun RPC is also insecure and should be deprecated or even removed, but maybe that can be left as TI-RPC's problem. * posix/unistd.h: Do not declare encrypt. * stdlib/stdlib.h: Do not declare setkey. * crypt/crypt.h: Do not declare encrypt, setkey, encrypt_r, setkey_r. * sunrpc/Makefile: Do not install des_crypt.h nor rpc_des.h. * crypt/Versions: Add an empty stanza for GLIBC_2.28. * crypt/crypt-entry.c: Make fcrypt a compat symbol. * crypt/crypt_util.c: Make encrypt, encrypt_r, setkey, setkey_r into compat symbols. Don't define initial_perm if it's not going to be used. * crypt/cert.c: Link explicitly with the expected versions for setkey and encrypt. If they are not available at all, mark the test as unsupported. * sunrpc/des_crypt.c: Unconditionally block linkage with cbc_crypt and ecb_crypt for new binaries. * sunrpc/des_soft.c: Unconditionally block linkage with des_setparity for new binaries. * manual/crypt.texi: Remove the entire "DES Encryption" section. Also remove the paragraph talking about FIPS 140-2 from the introduction. * manual/string.texi (strfry, memfrob): Revise. Recommend use of libgcrypt for "real" encryption, not DES. * conform/data/stdlib.h-data: Do not expect setkey. * conform/data/unistd.h-data: Do not expect encrypt. --- NEWS | 12 +++ conform/data/stdlib.h-data | 3 - conform/data/unistd.h-data | 3 - crypt/Versions | 3 + crypt/cert.c | 29 ++++++ crypt/crypt-entry.c | 15 +-- crypt/crypt.h | 18 +--- crypt/crypt_util.c | 9 ++ manual/crypt.texi | 201 ------------------------------------- manual/string.texi | 82 +++++++-------- posix/unistd.h | 9 -- stdlib/stdlib.h | 6 -- sunrpc/Makefile | 2 +- sunrpc/des_crypt.c | 7 +- sunrpc/des_soft.c | 2 +- 15 files changed, 105 insertions(+), 296 deletions(-) diff --git a/NEWS b/NEWS index bade9e4765..0bd21948f6 100644 --- a/NEWS +++ b/NEWS @@ -74,6 +74,18 @@ Deprecated and removed features, and other changes affecting compatibility: and could not usefully be used with the GNU C Library on systems with version 3.1 or later of the Linux kernel. +* The obsolete functions 'encrypt', 'encrypt_r', 'setkey', 'setkey_r', + 'cbc_crypt', 'ecb_crypt', and 'des_setparity' are no longer available to + newly linked binaries, and the headers and + are no longer installed. These functions encrypted and + decrypted data with the DES block cipher, which is no longer considered + secure. Software that still uses these functions should switch to a + modern cryptography library, such as libgcrypt. + +* The obsolete function 'fcrypt' is no longer available to newly linked + binaries. It was just another name for the standard function 'crypt', + and it has not appeared in any header file in many years. + Changes to build and runtime requirements: [Add changes to build and runtime requirements here] diff --git a/conform/data/stdlib.h-data b/conform/data/stdlib.h-data index d8fcccc2fb..6913828196 100644 --- a/conform/data/stdlib.h-data +++ b/conform/data/stdlib.h-data @@ -149,9 +149,6 @@ function {unsigned short int*} seed48 (unsigned short int[3]) #if !defined ISO && !defined ISO99 && !defined ISO11 && !defined POSIX && !defined XPG4 && !defined XPG42 && !defined UNIX98 function int setenv (const char*, const char*, int) #endif -#if !defined ISO && !defined ISO99 && !defined ISO11 && !defined POSIX && !defined POSIX2008 -function void setkey (const char*) -#endif #if !defined ISO && !defined ISO99 && !defined ISO11 && !defined XPG4 && !defined POSIX && !defined POSIX2008 function {char*} setstate (char*) #endif diff --git a/conform/data/unistd.h-data b/conform/data/unistd.h-data index ddf4f25132..68a7cd973e 100644 --- a/conform/data/unistd.h-data +++ b/conform/data/unistd.h-data @@ -449,9 +449,6 @@ allow cuserid #endif function int dup (int) function int dup2 (int, int) -#if !defined POSIX && !defined POSIX2008 -function void encrypt (char[64], int) -#endif function int execl (const char*, const char*, ...) function int execle (const char*, const char*, ...) function int execlp (const char*, const char*, ...) diff --git a/crypt/Versions b/crypt/Versions index 389e7d544a..d3e9d30174 100644 --- a/crypt/Versions +++ b/crypt/Versions @@ -2,4 +2,7 @@ libcrypt { GLIBC_2.0 { crypt; crypt_r; encrypt; encrypt_r; fcrypt; setkey; setkey_r; } + GLIBC_2.28 { + # used in SHLIB_COMPAT directives + } } diff --git a/crypt/cert.c b/crypt/cert.c index 80029e9078..3bab49b1ea 100644 --- a/crypt/cert.c +++ b/crypt/cert.c @@ -10,6 +10,26 @@ #include #include "crypt.h" +/* This file tests the deprecated setkey/encrypt interface. */ +#undef MODULE_NAME +#define MODULE_NAME libcrypt +#define SHARED +#include + +#if SHLIB_COMPAT (libcrypt, GLIBC_2_0, GLIBC_2_28) + +#define libcrypt_version_reference(symbol, version) \ + _libcrypt_version_reference (symbol, VERSION_libcrypt_##version) +#define _libcrypt_version_reference(symbol, version) \ + __libcrypt_version_reference (symbol, version) +#define __libcrypt_version_reference(symbol, version) \ + __asm__ (".symver " #symbol ", " #symbol "@" #version) + +extern void setkey (const char *); +extern void encrypt (const char *, int); +libcrypt_version_reference (setkey, GLIBC_2_0); +libcrypt_version_reference (encrypt, GLIBC_2_0); + int totfails = 0; int main (int argc, char *argv[]); @@ -104,3 +124,12 @@ put8 (char *cp) printf("%02x", t); } } + +#else /* encrypt and setkey are not available. */ + +int main(void) +{ + return 77; /* UNSUPPORTED */ +} + +#endif diff --git a/crypt/crypt-entry.c b/crypt/crypt-entry.c index 58691fb384..4e95f74878 100644 --- a/crypt/crypt-entry.c +++ b/crypt/crypt-entry.c @@ -35,6 +35,7 @@ #endif #include "crypt-private.h" +#include /* Prototypes for local functions. */ #ifndef __GNU_LIBRARY__ @@ -176,17 +177,7 @@ crypt (const char *key, const char *salt) return __crypt_r (key, salt, &_ufc_foobar); } - -/* - * To make fcrypt users happy. - * They don't need to call init_des. - */ -#ifdef _LIBC +#if SHLIB_COMPAT (libcrypt, GLIBC_2_0, GLIBC_2_28) weak_alias (crypt, fcrypt) -#else -char * -__fcrypt (const char *key, const char *salt) -{ - return crypt (key, salt); -} +compat_symbol (libcrypt, fcrypt, fcrypt, GLIBC_2_0); #endif diff --git a/crypt/crypt.h b/crypt/crypt.h index 5da098b715..3cb18de14d 100644 --- a/crypt/crypt.h +++ b/crypt/crypt.h @@ -32,16 +32,8 @@ __BEGIN_DECLS extern char *crypt (const char *__key, const char *__salt) __THROW __nonnull ((1, 2)); -/* Setup DES tables according KEY. */ -extern void setkey (const char *__key) __THROW __nonnull ((1)); - -/* Encrypt data in BLOCK in place if EDFLAG is zero; otherwise decrypt - block in place. */ -extern void encrypt (char *__glibc_block, int __edflag) - __THROW __nonnull ((1)); - #ifdef __USE_GNU -/* Reentrant versions of the functions above. The additional argument +/* Reentrant version of 'crypt'. The additional argument points to a structure where the results are placed in. */ struct crypt_data { @@ -60,14 +52,6 @@ struct crypt_data extern char *crypt_r (const char *__key, const char *__salt, struct crypt_data * __restrict __data) __THROW __nonnull ((1, 2, 3)); - -extern void setkey_r (const char *__key, - struct crypt_data * __restrict __data) - __THROW __nonnull ((1, 2)); - -extern void encrypt_r (char *__glibc_block, int __edflag, - struct crypt_data * __restrict __data) - __THROW __nonnull ((1, 3)); #endif __END_DECLS diff --git a/crypt/crypt_util.c b/crypt/crypt_util.c index 4958918770..fbfc783751 100644 --- a/crypt/crypt_util.c +++ b/crypt/crypt_util.c @@ -34,6 +34,7 @@ #endif #include "crypt-private.h" +#include /* Prototypes for local functions. */ #ifndef __GNU_LIBRARY__ @@ -150,6 +151,7 @@ static const int sbox[8][4][16]= { } }; +#if SHLIB_COMPAT (libcrypt, GLIBC_2_0, GLIBC_2_28) /* * This is the initial * permutation matrix @@ -160,6 +162,7 @@ static const int initial_perm[64] = { 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 }; +#endif /* * This is the final @@ -785,6 +788,7 @@ _ufc_output_conversion_r (ufc_long v1, ufc_long v2, const char *salt, __data->crypt_3_buf[13] = 0; } +#if SHLIB_COMPAT (libcrypt, GLIBC_2_0, GLIBC_2_28) /* * UNIX encrypt function. Takes a bitvector @@ -885,12 +889,14 @@ __encrypt_r (char *__block, int __edflag, } } weak_alias (__encrypt_r, encrypt_r) +compat_symbol (libcrypt, encrypt_r, encrypt_r, GLIBC_2_0); void encrypt (char *__block, int __edflag) { __encrypt_r(__block, __edflag, &_ufc_foobar); } +compat_symbol (libcrypt, encrypt, encrypt, GLIBC_2_0); /* @@ -915,12 +921,15 @@ __setkey_r (const char *__key, struct crypt_data * __restrict __data) _ufc_mk_keytab_r((char *) ktab, __data); } weak_alias (__setkey_r, setkey_r) +compat_symbol (libcrypt, setkey_r, setkey_r, GLIBC_2_0); void setkey (const char *__key) { __setkey_r(__key, &_ufc_foobar); } +compat_symbol (libcrypt, setkey, setkey, GLIBC_2_0); +#endif /* SHLIB_COMPAT (libcrypt, GLIBC_2_0, GLIBC_2_28) */ void __b64_from_24bit (char **cp, int *buflen, diff --git a/manual/crypt.texi b/manual/crypt.texi index 99d2d8e092..6bbe2bfdc5 100644 --- a/manual/crypt.texi +++ b/manual/crypt.texi @@ -30,21 +30,10 @@ message-digest algorithm that is compatible with modern BSD systems, and the other based on the Data Encryption Standard (DES) that is compatible with Unix systems. -@vindex AUTH_DES -@cindex FIPS 140-2 -It also provides support for Secure RPC, and some library functions that -can be used to perform normal DES encryption. The @code{AUTH_DES} -authentication flavor in Secure RPC, as provided by @theglibc{}, -uses DES and does not comply with FIPS 140-2 nor does any other use of DES -within @theglibc{}. It is recommended that Secure RPC should not be used -for systems that need to comply with FIPS 140-2 since all flavors of -encrypted authentication use normal DES. - @menu * Legal Problems:: This software can get you locked up, or worse. * getpass:: Prompting the user for a password. * crypt:: A one-way function for passwords. -* DES Encryption:: Routines for DES encryption. * Unpredictable Bytes:: Randomness for cryptography purposes. @end menu @@ -223,196 +212,6 @@ The @code{crypt_r} function is a GNU extension. The @code{crypt} and @code{crypt_r} functions are prototyped in the header @file{crypt.h}. -@node DES Encryption -@section DES Encryption - -@cindex FIPS 46-3 -The Data Encryption Standard is described in the US Government Federal -Information Processing Standards (FIPS) 46-3 published by the National -Institute of Standards and Technology. The DES has been very thoroughly -analyzed since it was developed in the late 1970s, and no new -significant flaws have been found. - -However, the DES uses only a 56-bit key (plus 8 parity bits), and a -machine has been built in 1998 which can search through all possible -keys in about 6 days, which cost about US$200000; faster searches would -be possible with more money. This makes simple DES insecure for most -purposes, and NIST no longer permits new US government systems -to use simple DES. - -For serious encryption functionality, it is recommended that one of the -many free encryption libraries be used instead of these routines. - -The DES is a reversible operation which takes a 64-bit block and a -64-bit key, and produces another 64-bit block. Usually the bits are -numbered so that the most-significant bit, the first bit, of each block -is numbered 1. - -Under that numbering, every 8th bit of the key (the 8th, 16th, and so -on) is not used by the encryption algorithm itself. But the key must -have odd parity; that is, out of bits 1 through 8, and 9 through 16, and -so on, there must be an odd number of `1' bits, and this completely -specifies the unused bits. - -@deftypefun void setkey (const char *@var{key}) -@standards{BSD, crypt.h} -@standards{SVID, crypt.h} -@safety{@prelim{}@mtunsafe{@mtasurace{:crypt}}@asunsafe{@asucorrupt{} @asulock{}}@acunsafe{@aculock{}}} -@c The static buffer stores the key, making it fundamentally -@c thread-unsafe. The locking issues are only in the initialization -@c path; cancelling the initialization will leave the lock held, it -@c would otherwise repeat the initialization on the next call. - -The @code{setkey} function sets an internal data structure to be an -expanded form of @var{key}. @var{key} is specified as an array of 64 -bits each stored in a @code{char}, the first bit is @code{key[0]} and -the 64th bit is @code{key[63]}. The @var{key} should have the correct -parity. -@end deftypefun - -@deftypefun void encrypt (char *@var{block}, int @var{edflag}) -@standards{BSD, crypt.h} -@standards{SVID, crypt.h} -@safety{@prelim{}@mtunsafe{@mtasurace{:crypt}}@asunsafe{@asucorrupt{} @asulock{}}@acunsafe{@aculock{}}} -@c Same issues as setkey. - -The @code{encrypt} function encrypts @var{block} if -@var{edflag} is 0, otherwise it decrypts @var{block}, using a key -previously set by @code{setkey}. The result is -placed in @var{block}. - -Like @code{setkey}, @var{block} is specified as an array of 64 bits each -stored in a @code{char}, but there are no parity bits in @var{block}. -@end deftypefun - -@deftypefun void setkey_r (const char *@var{key}, {struct crypt_data *} @var{data}) -@deftypefunx void encrypt_r (char *@var{block}, int @var{edflag}, {struct crypt_data *} @var{data}) -@standards{GNU, crypt.h} -@c setkey_r: @safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{} @asulock{}}@acunsafe{@aculock{}}} -@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{} @asulock{}}@acunsafe{@aculock{}}} - -These are reentrant versions of @code{setkey} and @code{encrypt}. The -only difference is the extra parameter, which stores the expanded -version of @var{key}. Before calling @code{setkey_r} the first time, -@code{data->initialized} must be cleared to zero. -@end deftypefun - -The @code{setkey_r} and @code{encrypt_r} functions are GNU extensions. -@code{setkey}, @code{encrypt}, @code{setkey_r}, and @code{encrypt_r} are -defined in @file{crypt.h}. - -@deftypefun int ecb_crypt (char *@var{key}, char *@var{blocks}, unsigned int @var{len}, unsigned int @var{mode}) -@standards{SUNRPC, rpc/des_crypt.h} -@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} - -The function @code{ecb_crypt} encrypts or decrypts one or more blocks -using DES. Each block is encrypted independently. - -The @var{blocks} and the @var{key} are stored packed in 8-bit bytes, so -that the first bit of the key is the most-significant bit of -@code{key[0]} and the 63rd bit of the key is stored as the -least-significant bit of @code{key[7]}. The @var{key} should have the -correct parity. - -@var{len} is the number of bytes in @var{blocks}. It should be a -multiple of 8 (so that there are a whole number of blocks to encrypt). -@var{len} is limited to a maximum of @code{DES_MAXDATA} bytes. - -The result of the encryption replaces the input in @var{blocks}. - -The @var{mode} parameter is the bitwise OR of two of the following: - -@vtable @code -@item DES_ENCRYPT -@standards{SUNRPC, rpc/des_crypt.h} -This constant, used in the @var{mode} parameter, specifies that -@var{blocks} is to be encrypted. - -@item DES_DECRYPT -@standards{SUNRPC, rpc/des_crypt.h} -This constant, used in the @var{mode} parameter, specifies that -@var{blocks} is to be decrypted. - -@item DES_HW -@standards{SUNRPC, rpc/des_crypt.h} -This constant, used in the @var{mode} parameter, asks to use a hardware -device. If no hardware device is available, encryption happens anyway, -but in software. - -@item DES_SW -@standards{SUNRPC, rpc/des_crypt.h} -This constant, used in the @var{mode} parameter, specifies that no -hardware device is to be used. -@end vtable - -The result of the function will be one of these values: - -@vtable @code -@item DESERR_NONE -@standards{SUNRPC, rpc/des_crypt.h} -The encryption succeeded. - -@item DESERR_NOHWDEVICE -@standards{SUNRPC, rpc/des_crypt.h} -The encryption succeeded, but there was no hardware device available. - -@item DESERR_HWERROR -@standards{SUNRPC, rpc/des_crypt.h} -The encryption failed because of a hardware problem. - -@item DESERR_BADPARAM -@standards{SUNRPC, rpc/des_crypt.h} -The encryption failed because of a bad parameter, for instance @var{len} -is not a multiple of 8 or @var{len} is larger than @code{DES_MAXDATA}. -@end vtable -@end deftypefun - -@deftypefun int DES_FAILED (int @var{err}) -@standards{SUNRPC, rpc/des_crypt.h} -@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} -This macro returns 1 if @var{err} is a `success' result code from -@code{ecb_crypt} or @code{cbc_crypt}, and 0 otherwise. -@end deftypefun - -@deftypefun int cbc_crypt (char *@var{key}, char *@var{blocks}, unsigned int @var{len}, unsigned int @var{mode}, char *@var{ivec}) -@standards{SUNRPC, rpc/des_crypt.h} -@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} - -The function @code{cbc_crypt} encrypts or decrypts one or more blocks -using DES in Cipher Block Chaining mode. - -For encryption in CBC mode, each block is exclusive-ored with @var{ivec} -before being encrypted, then @var{ivec} is replaced with the result of -the encryption, then the next block is processed. Decryption is the -reverse of this process. - -This has the advantage that blocks which are the same before being -encrypted are very unlikely to be the same after being encrypted, making -it much harder to detect patterns in the data. - -Usually, @var{ivec} is set to 8 random bytes before encryption starts. -Then the 8 random bytes are transmitted along with the encrypted data -(without themselves being encrypted), and passed back in as @var{ivec} -for decryption. Another possibility is to set @var{ivec} to 8 zeroes -initially, and have the first block encrypted consist of 8 random -bytes. - -Otherwise, all the parameters are similar to those for @code{ecb_crypt}. -@end deftypefun - -@deftypefun void des_setparity (char *@var{key}) -@standards{SUNRPC, rpc/des_crypt.h} -@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} - -The function @code{des_setparity} changes the 64-bit @var{key}, stored -packed in 8-bit bytes, to have odd parity by altering the low bits of -each byte. -@end deftypefun - -The @code{ecb_crypt}, @code{cbc_crypt}, and @code{des_setparity} -functions and their accompanying macros are all defined in the header -@file{rpc/des_crypt.h}. - @node Unpredictable Bytes @section Generating Unpredictable Bytes diff --git a/manual/string.texi b/manual/string.texi index b07cfb4550..a1c58e58fa 100644 --- a/manual/string.texi +++ b/manual/string.texi @@ -36,8 +36,8 @@ too. for delimiters. * Erasing Sensitive Data:: Clearing memory which contains sensitive data, after it's no longer needed. -* strfry:: Function for flash-cooking a string. -* Trivial Encryption:: Obscuring data. +* Shuffling Bytes:: Or how to flash-cook a string. +* Obfuscating Data:: Reversibly obscuring data from casual view. * Encode Binary Data:: Encoding and Decoding of Binary Data. * Argz and Envz Vectors:: Null-separated string vectors. @end menu @@ -2426,73 +2426,73 @@ functionality under a different name, such as @code{explicit_memset}, systems it may be in @file{strings.h} instead. @end deftypefun -@node strfry -@section strfry + +@node Shuffling Bytes +@section Shuffling Bytes The function below addresses the perennial programming quandary: ``How do I take good data in string form and painlessly turn it into garbage?'' -This is actually a fairly simple task for C programmers who do not use -@theglibc{} string functions, but for programs based on @theglibc{}, -the @code{strfry} function is the preferred method for -destroying string data. +This is not a difficult thing to code for oneself, but the authors of +@theglibc{} wish to make it as convenient as possible. -The prototype for this function is in @file{string.h}. +To @emph{erase} data, use @code{explicit_bzero} (@pxref{Erasing +Sensitive Data}); to obfuscate it reversibly, use @code{memfrob} +(@pxref{Obfuscating Data}). @deftypefun {char *} strfry (char *@var{string}) @standards{GNU, string.h} @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} @c Calls initstate_r, time, getpid, strlen, and random_r. -@code{strfry} creates a pseudorandom anagram of a string, replacing the -input with the anagram in place. For each position in the string, -@code{strfry} swaps it with a position in the string selected at random -(from a uniform distribution). The two positions may be the same. +@code{strfry} performs an in-place shuffle on @var{string}. Each +character is swapped to a position selected at random, within the +portion of the string starting with the character's original position. +(This is the Fisher-Yates algorithm for unbiased shuffling.) + +Calling @code{strfry} will not disturb any of the random number +generators that have global state (@pxref{Pseudo-Random Numbers}). The return value of @code{strfry} is always @var{string}. @strong{Portability Note:} This function is unique to @theglibc{}. - +It is declared in @file{string.h}. @end deftypefun -@node Trivial Encryption -@section Trivial Encryption -@cindex encryption - - -The @code{memfrob} function converts an array of data to something -unrecognizable and back again. It is not encryption in its usual sense -since it is easy for someone to convert the encrypted data back to clear -text. The transformation is analogous to Usenet's ``Rot13'' encryption -method for obscuring offensive jokes from sensitive eyes and such. -Unlike Rot13, @code{memfrob} works on arbitrary binary data, not just -text. +@node Obfuscating Data +@section Obfuscating Data @cindex Rot13 -For true encryption, @xref{Cryptographic Functions}. +The @code{memfrob} function reversibly obfuscates an array of binary +data. This is not true encryption; the obfuscated data still bears a +clear relationship to the original, and no secret key is required to +undo the obfuscation. It is analogous to the ``Rot13'' cipher used on +Usenet for obscuring offensive jokes, spoilers for works of fiction, +and so on, but it can be applied to arbitrary binary data. -This function is declared in @file{string.h}. -@pindex string.h +Programs that need true encryption---a transformation that completely +obscures the original and cannot be reversed without knowledge of a +secret key---should use a dedicated cryptography library, such as +@uref{https://www.gnu.org/software/libgcrypt/,,libgcrypt}. + +Programs that need to @emph{destroy} data should use +@code{explicit_bzero} (@pxref{Erasing Sensitive Data}), or possibly +@code{strfry} (@pxref{Shuffling Bytes}). @deftypefun {void *} memfrob (void *@var{mem}, size_t @var{length}) @standards{GNU, string.h} @safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}} -@code{memfrob} transforms (frobnicates) each byte of the data structure -at @var{mem}, which is @var{length} bytes long, by bitwise exclusive -oring it with binary 00101010. It does the transformation in place and -its return value is always @var{mem}. +The function @code{memfrob} obfuscates @var{length} bytes of data +beginning at @var{mem}, in place. Each byte is bitwise xor-ed with +the binary pattern 00101010 (hexadecimal 0x2A). The return value is +always @var{mem}. -Note that @code{memfrob} a second time on the same data structure -returns it to its original state. - -This is a good function for hiding information from someone who doesn't -want to see it or doesn't want to see it very much. To really prevent -people from retrieving the information, use stronger encryption such as -that described in @xref{Cryptographic Functions}. +@code{memfrob} a second time on the same data returns it to +its original state. @strong{Portability Note:} This function is unique to @theglibc{}. - +It is declared in @file{string.h}. @end deftypefun @node Encode Binary Data diff --git a/posix/unistd.h b/posix/unistd.h index 4d149f9945..5c3da702b6 100644 --- a/posix/unistd.h +++ b/posix/unistd.h @@ -1118,20 +1118,11 @@ ssize_t copy_file_range (int __infd, __off64_t *__pinoff, extern int fdatasync (int __fildes); #endif /* Use POSIX199309 */ - -/* XPG4.2 specifies that prototypes for the encryption functions must - be defined here. */ #ifdef __USE_XOPEN /* Encrypt at most 8 characters from KEY using salt to perturb DES. */ extern char *crypt (const char *__key, const char *__salt) __THROW __nonnull ((1, 2)); -/* Encrypt data in BLOCK in place if EDFLAG is zero; otherwise decrypt - block in place. */ -extern void encrypt (char *__glibc_block, int __edflag) - __THROW __nonnull ((1)); - - /* Swab pairs bytes in the first N bytes of the area pointed to by FROM and copy the result to TO. The value of TO must not be in the range [FROM - N + 1, FROM - 1]. If N is odd the first byte in FROM diff --git a/stdlib/stdlib.h b/stdlib/stdlib.h index 6b1ead31e0..8e23e93557 100644 --- a/stdlib/stdlib.h +++ b/stdlib/stdlib.h @@ -958,12 +958,6 @@ extern int getsubopt (char **__restrict __optionp, #endif -#ifdef __USE_XOPEN -/* Setup DES tables according KEY. */ -extern void setkey (const char *__key) __THROW __nonnull ((1)); -#endif - - /* X/Open pseudo terminal handling. */ #ifdef __USE_XOPEN2KXSI diff --git a/sunrpc/Makefile b/sunrpc/Makefile index 8f2a3c8213..ab2e0daaea 100644 --- a/sunrpc/Makefile +++ b/sunrpc/Makefile @@ -51,7 +51,7 @@ rpcsvc = bootparam_prot.x nlm_prot.x rstat.x \ headers-sunrpc = $(addprefix rpc/,auth.h auth_unix.h clnt.h pmap_clnt.h \ pmap_prot.h pmap_rmt.h rpc.h rpc_msg.h \ svc.h svc_auth.h types.h xdr.h auth_des.h \ - des_crypt.h key_prot.h rpc_des.h) \ + key_prot.h) \ $(rpcsvc:%=rpcsvc/%) rpcsvc/bootparam.h headers = rpc/netdb.h install-others = $(inst_sysconfdir)/rpc diff --git a/sunrpc/des_crypt.c b/sunrpc/des_crypt.c index a4d8b2936b..9b4bd2d5dd 100644 --- a/sunrpc/des_crypt.c +++ b/sunrpc/des_crypt.c @@ -86,6 +86,9 @@ common_crypt (char *key, char *buf, register unsigned len, return desdev == DES_SW ? DESERR_NONE : DESERR_NOHWDEVICE; } +/* Note: these cannot be excluded from the build yet, because they are + still used internally. */ + /* * CBC mode encryption */ @@ -102,7 +105,7 @@ cbc_crypt (char *key, char *buf, unsigned int len, unsigned int mode, COPY8 (dp.des_ivec, ivec); return err; } -libc_hidden_nolink_sunrpc (cbc_crypt, GLIBC_2_1) +hidden_nolink (cbc_crypt, libc, GLIBC_2_1) /* * ECB mode encryption @@ -115,4 +118,4 @@ ecb_crypt (char *key, char *buf, unsigned int len, unsigned int mode) dp.des_mode = ECB; return common_crypt (key, buf, len, mode, &dp); } -libc_hidden_nolink_sunrpc (ecb_crypt, GLIBC_2_1) +hidden_nolink (ecb_crypt, libc, GLIBC_2_1) diff --git a/sunrpc/des_soft.c b/sunrpc/des_soft.c index f884f8f21b..a87de96cc7 100644 --- a/sunrpc/des_soft.c +++ b/sunrpc/des_soft.c @@ -71,4 +71,4 @@ des_setparity (char *p) p++; } } -libc_hidden_nolink_sunrpc (des_setparity, GLIBC_2_1) +hidden_nolink (des_setparity, libc, GLIBC_2_1) From patchwork Mon May 21 17:38:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zack Weinberg X-Patchwork-Id: 917763 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-92636-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=panix.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="iDpr5CPq"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40qQxv5gmqz9s1w for ; Tue, 22 May 2018 03:39:15 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; q=dns; s= default; b=RMW23lSbywAq+LJvGsntLk4dEKXCzqhWL9L3QOlzxpehbhXRw2BNQ jCSss57bHAEqBFdtf2HRWE/l1JdabZNcM5eWaN9kex2jF7Txv1b3VVU4OwpTDCTo qf5L0CuROfxWkb9hzJUsjr0VCk1/g/V4UY6RSjTWkn5PiiRXV74z9U= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; s=default; bh=eL30mtPGzx3bYWyofdlo9zq29HQ=; b=iDpr5CPqIOXIEjIzcRvjbUoeikg5 zVXfZFLx/nlInuEzTArAegkdbs3lqFji9luSyu0KwI7WqQqovI6wb62/a+GDeyzk HhiWxmQNoK4T5su6CdzVUal483dTDmz27hljziEd/lpz5WdQuEYm40KBMZuI+BY7 R+13UY7hm1Lf+ZQ= Received: (qmail 109772 invoked by alias); 21 May 2018 17:39:00 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 109158 invoked by uid 89); 21 May 2018 17:38:59 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.5 required=5.0 tests=AWL, BAYES_50, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.2 spammy=Republic, france, korea, France X-HELO: mailbackend.panix.com From: Zack Weinberg To: libc-alpha@sourceware.org Cc: carlos@redhat.com, fweimer@redhat.com, rj@2c3t.io, kukuk@suse.de Subject: [PATCH 2/4] Reorganize crypt.texi. Date: Mon, 21 May 2018 13:38:51 -0400 Message-Id: <20180521173853.5172-3-zackw@panix.com> In-Reply-To: <20180521173853.5172-1-zackw@panix.com> References: <20180521173853.5172-1-zackw@panix.com> MIME-Version: 1.0 In preparation for a major revision of the documentation for crypt(_r), getentropy, and getrandom, reorganize crypt.texi. This patch does not change any text; it only deletes and moves text. The description of 'getpass' moves to terminal.texi, since all it does is read a password from the controlling terminal with echo disabled. The "Legal Problems" section of crypt.texi is dropped, and the introductory text is shifted down to the "Encrypting Passwords" section; the next patch will add some new introductory text. Also, it is no longer true that crypt.texi's top @node needs to have no pointers. That was a vestige of crypt/ being an add-on. (makeinfo itself doesn't need @node pointers anymore, but the scripts that assemble the libc manual's topmost node rely on each chapter-level node having them.) * manual/crypt.texi: Use a normal top-level @node declaration. Move most of the introductory text to the 'crypt' section. Move the example programs below the @deftypefun for 'crypt_r'. Move the 'getpass' section... * manual/terminal.texi: ...here. --- manual/crypt.texi | 147 +++++++++---------------------------------- manual/terminal.texi | 45 +++++++++++++ 2 files changed, 73 insertions(+), 119 deletions(-) diff --git a/manual/crypt.texi b/manual/crypt.texi index 6bbe2bfdc5..0f04ee9899 100644 --- a/manual/crypt.texi +++ b/manual/crypt.texi @@ -1,8 +1,14 @@ -@c This node must have no pointers. -@node Cryptographic Functions -@c @node Cryptographic Functions, Debugging Support, System Configuration, Top -@chapter DES Encryption and Password Handling -@c %MENU% DES encryption and password handling +@node Cryptographic Functions, Debugging Support, System Configuration, Top +@chapter Cryptographic Functions +@c %MENU% Password storage and strongly unpredictable bytes + +@menu +* crypt:: A one-way function for passwords. +* Unpredictable Bytes:: Randomness for cryptography purposes. +@end menu + +@node crypt +@section Encrypting Passwords On many systems, it is unnecessary to have any kind of user authentication; for instance, a workstation which is not connected to a @@ -30,103 +36,6 @@ message-digest algorithm that is compatible with modern BSD systems, and the other based on the Data Encryption Standard (DES) that is compatible with Unix systems. -@menu -* Legal Problems:: This software can get you locked up, or worse. -* getpass:: Prompting the user for a password. -* crypt:: A one-way function for passwords. -* Unpredictable Bytes:: Randomness for cryptography purposes. -@end menu - -@node Legal Problems -@section Legal Problems - -Because of the continuously changing state of the law, it's not possible -to provide a definitive survey of the laws affecting cryptography. -Instead, this section warns you of some of the known trouble spots; this -may help you when you try to find out what the laws of your country are. - -Some countries require that you have a license to use, possess, or import -cryptography. These countries are believed to include Byelorussia, -Burma, India, Indonesia, Israel, Kazakhstan, Pakistan, Russia, and Saudi -Arabia. - -Some countries restrict the transmission of encrypted messages by radio; -some telecommunications carriers restrict the transmission of encrypted -messages over their network. - -Many countries have some form of export control for encryption software. -The Wassenaar Arrangement is a multilateral agreement between 33 -countries (Argentina, Australia, Austria, Belgium, Bulgaria, Canada, the -Czech Republic, Denmark, Finland, France, Germany, Greece, Hungary, -Ireland, Italy, Japan, Luxembourg, the Netherlands, New Zealand, Norway, -Poland, Portugal, the Republic of Korea, Romania, the Russian -Federation, the Slovak Republic, Spain, Sweden, Switzerland, Turkey, -Ukraine, the United Kingdom and the United States) which restricts some -kinds of encryption exports. Different countries apply the arrangement -in different ways; some do not allow the exception for certain kinds of -``public domain'' software (which would include this library), some -only restrict the export of software in tangible form, and others impose -significant additional restrictions. - -The United States has additional rules. This software would generally -be exportable under 15 CFR 740.13(e), which permits exports of -``encryption source code'' which is ``publicly available'' and which is -``not subject to an express agreement for the payment of a licensing fee or -royalty for commercial production or sale of any product developed with -the source code'' to most countries. - -The rules in this area are continuously changing. If you know of any -information in this manual that is out-of-date, please report it to -the bug database. @xref{Reporting Bugs}. - -@node getpass -@section Reading Passwords - -When reading in a password, it is desirable to avoid displaying it on -the screen, to help keep it secret. The following function handles this -in a convenient way. - -@deftypefun {char *} getpass (const char *@var{prompt}) -@standards{BSD, unistd.h} -@safety{@prelim{}@mtunsafe{@mtasuterm{}}@asunsafe{@ascuheap{} @asulock{} @asucorrupt{}}@acunsafe{@acuterm{} @aculock{} @acucorrupt{}}} -@c This function will attempt to create a stream for terminal I/O, but -@c will fallback to stdio/stderr. It attempts to change the terminal -@c mode in a thread-unsafe way, write out the prompt, read the password, -@c then restore the terminal mode. It has a cleanup to close the stream -@c in case of (synchronous) cancellation, but not to restore the -@c terminal mode. - -@code{getpass} outputs @var{prompt}, then reads a string in from the -terminal without echoing it. It tries to connect to the real terminal, -@file{/dev/tty}, if possible, to encourage users not to put plaintext -passwords in files; otherwise, it uses @code{stdin} and @code{stderr}. -@code{getpass} also disables the INTR, QUIT, and SUSP characters on the -terminal using the @code{ISIG} terminal attribute (@pxref{Local Modes}). -The terminal is flushed before and after @code{getpass}, so that -characters of a mistyped password are not accidentally visible. - -In other C libraries, @code{getpass} may only return the first -@code{PASS_MAX} bytes of a password. @Theglibc{} has no limit, so -@code{PASS_MAX} is undefined. - -The prototype for this function is in @file{unistd.h}. @code{PASS_MAX} -would be defined in @file{limits.h}. -@end deftypefun - -This precise set of operations may not suit all possible situations. In -this case, it is recommended that users write their own @code{getpass} -substitute. For instance, a very simple substitute is as follows: - -@smallexample -@include mygetpass.c.texi -@end smallexample - -The substitute takes the same parameters as @code{getline} -(@pxref{Line Input}); the user must print any prompt desired. - -@node crypt -@section Encrypting Passwords - @deftypefun {char *} crypt (const char *@var{key}, const char *@var{salt}) @standards{BSD, crypt.h} @standards{SVID, crypt.h} @@ -177,6 +86,23 @@ password against the result of a previous call to @code{crypt}, pass the result of the previous call as the @var{salt}. @end deftypefun +@deftypefun {char *} crypt_r (const char *@var{key}, const char *@var{salt}, {struct crypt_data *} @var{data}) +@standards{GNU, crypt.h} +@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{} @asulock{} @ascuheap{} @ascudlopen{}}@acunsafe{@aculock{} @acsmem{}}} +@c Compared with crypt, this function fixes the @mtasurace:crypt +@c problem, but nothing else. + +The @code{crypt_r} function does the same thing as @code{crypt}, but +takes an extra parameter which includes space for its result (among +other things), so it can be reentrant. @code{data@w{->}initialized} must be +cleared to zero before the first time @code{crypt_r} is called. + +The @code{crypt_r} function is a GNU extension. +@end deftypefun + +The @code{crypt} and @code{crypt_r} functions are prototyped in the +header @file{crypt.h}. + The following short program is an example of how to use @code{crypt} the first time a password is entered. Note that the @var{salt} generation is just barely acceptable; in particular, it is not unique between @@ -195,23 +121,6 @@ for a password and prints ``Access granted.'' if the user types @include testpass.c.texi @end smallexample -@deftypefun {char *} crypt_r (const char *@var{key}, const char *@var{salt}, {struct crypt_data *} @var{data}) -@standards{GNU, crypt.h} -@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{} @asulock{} @ascuheap{} @ascudlopen{}}@acunsafe{@aculock{} @acsmem{}}} -@c Compared with crypt, this function fixes the @mtasurace:crypt -@c problem, but nothing else. - -The @code{crypt_r} function does the same thing as @code{crypt}, but -takes an extra parameter which includes space for its result (among -other things), so it can be reentrant. @code{data@w{->}initialized} must be -cleared to zero before the first time @code{crypt_r} is called. - -The @code{crypt_r} function is a GNU extension. -@end deftypefun - -The @code{crypt} and @code{crypt_r} functions are prototyped in the -header @file{crypt.h}. - @node Unpredictable Bytes @section Generating Unpredictable Bytes diff --git a/manual/terminal.texi b/manual/terminal.texi index 4aace48b14..0b275fc002 100644 --- a/manual/terminal.texi +++ b/manual/terminal.texi @@ -24,6 +24,7 @@ descriptor is and how to open a file descriptor for a terminal device. * Line Control:: Sending break sequences, clearing terminal buffers @dots{} * Noncanon Example:: How to read single characters without echo. +* getpass:: Prompting the user for a password. * Pseudo-Terminals:: How to open a pseudo-terminal. @end menu @@ -1871,6 +1872,50 @@ existing shells do not actually do this, so you may wish to establish handlers for job control signals that reset terminal modes. The above example does so. +@node getpass +@section Reading Passwords + +When reading in a password, it is desirable to avoid displaying it on +the screen, to help keep it secret. The following function handles this +in a convenient way. + +@deftypefun {char *} getpass (const char *@var{prompt}) +@standards{BSD, unistd.h} +@safety{@prelim{}@mtunsafe{@mtasuterm{}}@asunsafe{@ascuheap{} @asulock{} @asucorrupt{}}@acunsafe{@acuterm{} @aculock{} @acucorrupt{}}} +@c This function will attempt to create a stream for terminal I/O, but +@c will fallback to stdio/stderr. It attempts to change the terminal +@c mode in a thread-unsafe way, write out the prompt, read the password, +@c then restore the terminal mode. It has a cleanup to close the stream +@c in case of (synchronous) cancellation, but not to restore the +@c terminal mode. + +@code{getpass} outputs @var{prompt}, then reads a string in from the +terminal without echoing it. It tries to connect to the real terminal, +@file{/dev/tty}, if possible, to encourage users not to put plaintext +passwords in files; otherwise, it uses @code{stdin} and @code{stderr}. +@code{getpass} also disables the INTR, QUIT, and SUSP characters on the +terminal using the @code{ISIG} terminal attribute (@pxref{Local Modes}). +The terminal is flushed before and after @code{getpass}, so that +characters of a mistyped password are not accidentally visible. + +In other C libraries, @code{getpass} may only return the first +@code{PASS_MAX} bytes of a password. @Theglibc{} has no limit, so +@code{PASS_MAX} is undefined. + +The prototype for this function is in @file{unistd.h}. @code{PASS_MAX} +would be defined in @file{limits.h}. +@end deftypefun + +This precise set of operations may not suit all possible situations. In +this case, it is recommended that users write their own @code{getpass} +substitute. For instance, a very simple substitute is as follows: + +@smallexample +@include mygetpass.c.texi +@end smallexample + +The substitute takes the same parameters as @code{getline} +(@pxref{Line Input}); the user must print any prompt desired. @node Pseudo-Terminals @section Pseudo-Terminals From patchwork Mon May 21 17:38:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zack Weinberg X-Patchwork-Id: 917766 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-92639-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=panix.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="bisVlN50"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40qQyT4vHdz9s2k for ; Tue, 22 May 2018 03:39:45 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; q=dns; s= default; b=RejUc4grS/h/qwOHnnKKY+c0alaeVZgp35M638OvSlU92HcXplVqu Se2d86msSwNmxPZXZO4TkClW/bnT8mVCapz160f6fL/S90n1FajRdZsVwIQ8bK9z pUUlI1j07gO/XEy17uvdrUVYeNXWNtLqBhkWonlKAaljeoO5KZO7Nw= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; s=default; bh=BiFi4K0s0Tem8pUSoXgW1PtEtZU=; b=bisVlN50P8rbu9DAz/TwADSus41e E0cmRyJfZUs5wE4tFhsXInTwTEubne5FiTH96LgA1mB8EUja2XWUMhs2Ih6y3LKo yO+Mm046C6y1rhMshBxoTCAhRaN7+uqhPMQrYMLMXlERZDKDtyVRdoSaNxvu6vtk mNRWyegn5KXzzH4= Received: (qmail 111648 invoked by alias); 21 May 2018 17:39:09 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 111168 invoked by uid 89); 21 May 2018 17:39:06 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-23.5 required=5.0 tests=AWL, BAYES_50, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS, SPF_PASS autolearn=ham version=3.3.2 spammy=4059, secure, Privacy, Password X-HELO: l2mail1.panix.com From: Zack Weinberg To: libc-alpha@sourceware.org Cc: carlos@redhat.com, fweimer@redhat.com, rj@2c3t.io, kukuk@suse.de Subject: [PATCH 3/4] Revise crypt.texi. Date: Mon, 21 May 2018 13:38:52 -0400 Message-Id: <20180521173853.5172-4-zackw@panix.com> In-Reply-To: <20180521173853.5172-1-zackw@panix.com> References: <20180521173853.5172-1-zackw@panix.com> MIME-Version: 1.0 This is a major rewrite of the description of 'crypt', 'getentropy', and 'getrandom'. A few highlights of the content changes: - Throughout the manual, public headers, and user-visible messages, I replaced the term "password" with "passphrase", the term "password database" with "user database", and the term "encrypt(ion)" with "(one-way) hashing" whenever it was applied to passphrases. I didn't bother making this change in internal code or tests. The use of the term "password" in ruserpass.c survives, because that refers to a keyword in netrc files, but it is adjusted to make this clearer. There is a note in crypt.texi explaining that they were traditionally called passwords but single words are not good enough anymore, and a note in users.texi explaining that actual passphrase hashes are found in a "shadow" database nowadays. - There is a new short introduction to the "Cryptographic Functions" section, explaining how we do not intend to be a general-purpose cryptography library, and cautioning that there _are_, or have been, legal restrictions on the use of cryptography in many countries, without getting into any kind of detail that we can't promise to keep up to date. - I added more detail about what a "one-way function" is, and why they are used to obscure passphrases for storage. I removed the paragraph saying that systems not connected to a network need no user authentication, because that's a pretty rare situation nowadays. (It still says "sometimes it is necessary" to authenticate the user, though.) - I added documentation for all of the hash functions that glibc actually supports, but not for the additional hash functions supported by libxcrypt. If we're going to keep this manual section around after the transition is more advanced, it would probably make sense to add them then. - There is much more detailed discussion of how to generate a salt, and the failure behavior for crypt is documented. (Returning an invalid hash on failure is what libxcrypt does; Solar Designer's notes say that this was done "for compatibility with old programs that assume crypt can never fail".) - As far as I can tell, the header 'crypt.h' is entirely a GNU invention, and never existed on any other Unix lineage. The function 'crypt', however, was in Issue 1 of the SVID and is now in the XSI component of POSIX. I tried to make all of the @standards annotations consistent with this, but I'm not sure I got them perfectly right. - The genpass.c example has been improved to use getentropy instead of the current time to generate the salt, and to use a SHA-256 hash instead of MD5. It uses more random bytes than is strictly necessary because I didn't want to complicate the code with proper base64 encoding. - The testpass.c example has three hardwired hashes now, to demonstrate that different one-way functions produce different hashes for the same input. It also demonstrates how DES hashing only pays attention to the first eight characters of the input. - There is new text explaining in more detail how a CSPRNG differs from a regular random number generator, and how getentropy/getrandom are not exactly a CSPRNG. I tried not to make specific falsifiable claims here. I also tried to make the blocking/cancellation/error behavior of both getentropy and getrandom clearer. * crypt/crypt.h, posix/unistd.h: Update comments and prototypes for crypt and crypt_r. * manual/crypt.texi (Cryptographic Functions): New initial exposition. (crypt): Section renamed to 'Passphrase Storage'. Full rewrite. (Unpredictable Bytes): Improve initial exposition. Clarify error behavior of getentropy and getrandom. * manual/examples/genpass.c: Generate a salt using getentropy instead of the current time. Use hash $5$ (SHA-2-256). * manual/examples/testpass.c: Demonstrate validation against hashes generated with three different one-way functions. * manual/intro.texi: crypt.texi does not need an overview anymore. * manual/nss.texi, manual/memory.texi, manual/socket.texi * manual/terminal.texi: Consistently refer to "passphrases" * instead of "passwords", and to the "user database" instead * of the "password database". * manual/users.texi: Similarly. Add notes about how actual passphrase hashes are now stored in the shadow database. Remove 20-year-old junk todo note. --- crypt/crypt.h | 21 +- inet/ruserpass.c | 2 +- manual/contrib.texi | 2 +- manual/crypt.texi | 391 +++++++++++++++++++++++------------- manual/examples/genpass.c | 44 ++-- manual/examples/mygetpass.c | 4 +- manual/examples/testpass.c | 52 +++-- manual/intro.texi | 1 - manual/memory.texi | 2 +- manual/nss.texi | 12 +- manual/socket.texi | 4 +- manual/terminal.texi | 14 +- manual/users.texi | 22 +- nscd/pwdcache.c | 4 +- posix/unistd.h | 10 +- pwd/pwd.h | 29 +-- shadow/shadow.h | 16 +- 17 files changed, 401 insertions(+), 229 deletions(-) diff --git a/crypt/crypt.h b/crypt/crypt.h index 3cb18de14d..ebe8607452 100644 --- a/crypt/crypt.h +++ b/crypt/crypt.h @@ -28,13 +28,18 @@ __BEGIN_DECLS -/* Encrypt at most 8 characters from KEY using salt to perturb DES. */ -extern char *crypt (const char *__key, const char *__salt) +/* One-way hash PHRASE, returning a string suitable for storage in the + user database. SALT selects the one-way function to use, and + ensures that no two users' hashes are the same, even if they use + the same passphrase. The return value points to static storage + which will be overwritten by the next call to crypt. */ +extern char *crypt (const char *__phrase, const char *__salt) __THROW __nonnull ((1, 2)); #ifdef __USE_GNU -/* Reentrant version of 'crypt'. The additional argument - points to a structure where the results are placed in. */ + +/* This structure provides scratch and output buffers for 'crypt_r'. + Its contents should not be accessed directly. */ struct crypt_data { char keysched[16 * 8]; @@ -49,7 +54,13 @@ struct crypt_data int direction, initialized; }; -extern char *crypt_r (const char *__key, const char *__salt, +/* Thread-safe version of 'crypt'. + DATA must point to a 'struct crypt_data' allocated by the caller. + Before the first call to 'crypt_r' with a new 'struct crypt_data', + that object must be initialized to all zeroes. The pointer + returned, if not NULL, will point within DATA. (It will still be + overwritten by the next call to 'crypt_r' with the same DATA.) */ +extern char *crypt_r (const char *__phrase, const char *__salt, struct crypt_data * __restrict __data) __THROW __nonnull ((1, 2, 3)); #endif diff --git a/inet/ruserpass.c b/inet/ruserpass.c index 5b2747bc50..4fa6520c1a 100644 --- a/inet/ruserpass.c +++ b/inet/ruserpass.c @@ -177,7 +177,7 @@ next: fstat64(fileno(cfile), &stb) >= 0 && (stb.st_mode & 077) != 0) { warnx(_("Error: .netrc file is readable by others.")); - warnx(_("Remove password or make file unreadable by others.")); + warnx(_("Remove 'password' line or make file unreadable by others.")); goto bad; } if (token() && *apass == 0) { diff --git a/manual/contrib.texi b/manual/contrib.texi index dd28e9293b..6191f46f31 100644 --- a/manual/contrib.texi +++ b/manual/contrib.texi @@ -129,7 +129,7 @@ Martin Galvan for contributing gdb pretty printer support to glibc and adding an initial set of pretty printers for structures in the POSIX Threads library. @item -Michael Glad for the DES encryption function @code{crypt} and related +Michael Glad for the passphrase-hashing function @code{crypt} and related functions. @item diff --git a/manual/crypt.texi b/manual/crypt.texi index 0f04ee9899..500649b4fc 100644 --- a/manual/crypt.texi +++ b/manual/crypt.texi @@ -1,121 +1,200 @@ @node Cryptographic Functions, Debugging Support, System Configuration, Top @chapter Cryptographic Functions -@c %MENU% Password storage and strongly unpredictable bytes +@c %MENU% Passphrase storage and strongly unpredictable bytes. + +@Theglibc{} includes only a few special-purpose cryptographic +functions: one-way hash functions for passphrase storage, and access +to a cryptographic randomness source, if one is provided by the +operating system. Programs that need general-purpose cryptography +should use a dedicated cryptography library, such as +@uref{https://www.gnu.org/software/libgcrypt/,,libgcrypt}. + +Many countries place legal restrictions on the import, export, +possession, or use of cryptographic software. We deplore these +restrictions, but we must still warn you that @theglibc{} may be +subject to them, even if you do not use the functions in this chapter +yourself. The restrictions vary from place to place and are changed +often, so we cannot give any more specific advice than this warning. @menu -* crypt:: A one-way function for passwords. -* Unpredictable Bytes:: Randomness for cryptography purposes. +* Passphrase Storage:: One-way hashing for passphrases. +* Unpredictable Bytes:: Randomness for cryptographic purposes. @end menu -@node crypt -@section Encrypting Passwords +@node Passphrase Storage +@section Passphrase Storage +@cindex passphrase hashing +@cindex one-way hashing +@cindex hashing, passphrase -On many systems, it is unnecessary to have any kind of user -authentication; for instance, a workstation which is not connected to a -network probably does not need any user authentication, because to use -the machine an intruder must have physical access. - -Sometimes, however, it is necessary to be sure that a user is authorized +Sometimes it is necessary to be sure that a user is authorized to use some service a machine provides---for instance, to log in as a particular user id (@pxref{Users and Groups}). One traditional way of -doing this is for each user to choose a secret @dfn{password}; then, the -system can ask someone claiming to be a user what the user's password -is, and if the person gives the correct password then the system can -grant the appropriate privileges. - -If all the passwords are just stored in a file somewhere, then this file -has to be very carefully protected. To avoid this, passwords are run -through a @dfn{one-way function}, a function which makes it difficult to -work out what its input was by looking at its output, before storing in -the file. - -@Theglibc{} provides a one-way function that is compatible with -the behavior of the @code{crypt} function introduced in FreeBSD 2.0. -It supports two one-way algorithms: one based on the MD5 -message-digest algorithm that is compatible with modern BSD systems, -and the other based on the Data Encryption Standard (DES) that is -compatible with Unix systems. - -@deftypefun {char *} crypt (const char *@var{key}, const char *@var{salt}) -@standards{BSD, crypt.h} -@standards{SVID, crypt.h} +doing this is for each user to choose a secret @dfn{passphrase}; then, the +system can ask someone claiming to be a user what the user's passphrase +is, and if the person gives the correct passphrase then the system can +grant the appropriate privileges. (Traditionally, these were called +``passwords,'' but nowadays a single word is too easy to guess.) + +Programs that handle passphrases must take special care not to reveal +them to anyone, no matter what. It is not enough to keep them in a +file that is only accessible with special privileges. The file might +be ``leaked'' via a bug or misconfiguration, and system administrators +shouldn't learn everyone's passphrase even if they have to edit that +file for some reason. To avoid this, passphrases should also be +converted into @dfn{one-way hashes}, using a @dfn{one-way function}, +before they are stored. + +A one-way function is easy to compute, but there is no known way to +compute its inverse. This means the system can easily check +passphrases, by hashing them and comparing the result with the stored +hash. But an attacker who discovers someone's passphrase hash can +only discover the passphrase it corresponds to by guessing and +checking. The one-way functions are designed to make this process +impractically slow, for all but the most obvious guesses. (Do not use +a word from the dictionary as your passphrase.) + +@Theglibc{} provides an interface to four one-way functions, based on +the SHA-2-512, SHA-2-256, MD5, and DES cryptographic primitives. New +passphrases should be hashed with either of the SHA-based functions. +The others are too weak for newly set passphrases, but we continue to +support them for verifying old passphrases. The DES-based hash is +especially weak, because it ignores all but the first eight characters +of its input. + +@deftypefun {char *} crypt (const char *@var{phrase}, const char *@var{salt}) +@standards{X/Open, unistd.h} +@standards{GNU, crypt.h} @safety{@prelim{}@mtunsafe{@mtasurace{:crypt}}@asunsafe{@asucorrupt{} @asulock{} @ascuheap{} @ascudlopen{}}@acunsafe{@aculock{} @acsmem{}}} @c Besides the obvious problem of returning a pointer into static @c storage, the DES initializer takes an internal lock with the usual -@c set of problems for AS- and AC-Safety. The FIPS mode checker and the -@c NSS implementations of may leak file descriptors if canceled. The +@c set of problems for AS- and AC-Safety. +@c The NSS implementations may leak file descriptors if cancelled. @c The MD5, SHA256 and SHA512 implementations will malloc on long keys, @c and NSS relies on dlopening, which brings about another can of worms. -The @code{crypt} function takes a password, @var{key}, as a string, and -a @var{salt} character array which is described below, and returns a -printable ASCII string which starts with another salt. It is believed -that, given the output of the function, the best way to find a @var{key} -that will produce that output is to guess values of @var{key} until the -original value of @var{key} is found. - -The @var{salt} parameter does two things. Firstly, it selects which -algorithm is used, the MD5-based one or the DES-based one. Secondly, it -makes life harder for someone trying to guess passwords against a file -containing many passwords; without a @var{salt}, an intruder can make a -guess, run @code{crypt} on it once, and compare the result with all the -passwords. With a @var{salt}, the intruder must run @code{crypt} once -for each different salt. - -For the MD5-based algorithm, the @var{salt} should consist of the string -@code{$1$}, followed by up to 8 characters, terminated by either -another @code{$} or the end of the string. The result of @code{crypt} -will be the @var{salt}, followed by a @code{$} if the salt didn't end -with one, followed by 22 characters from the alphabet -@code{./0-9A-Za-z}, up to 34 characters total. Every character in the -@var{key} is significant. - -For the DES-based algorithm, the @var{salt} should consist of two -characters from the alphabet @code{./0-9A-Za-z}, and the result of -@code{crypt} will be those two characters followed by 11 more from the -same alphabet, 13 in total. Only the first 8 characters in the -@var{key} are significant. - -The MD5-based algorithm has no limit on the useful length of the -password used, and is slightly more secure. It is therefore preferred -over the DES-based algorithm. - -When the user enters their password for the first time, the @var{salt} -should be set to a new string which is reasonably random. To verify a -password against the result of a previous call to @code{crypt}, pass -the result of the previous call as the @var{salt}. +The function @code{crypt} converts a passphrase string, @var{phrase}, +into a one-way hash suitable for storage in the user database. The +string that it returns will consist entirely of printable ASCII +characters. It will not contain whitespace, nor any of the characters +@samp{:}, @samp{;}, @samp{*}, @samp{!}, or @samp{\}. + +The @var{salt} parameter controls which one-way function is used, and +it also ensures that the output of the one-way function is different +for every user, even if they have the same passphrase. This makes it +harder to guess passphrases from a large user database. Without salt, +the attacker could make a guess, run @code{crypt} on it once, and +compare the result with all the hashes. Salt forces the attacker to +make separate calls to @code{crypt} for each user. + +To verify a passphrase, pass the previously hashed passphrase as the +@var{salt}. To hash a new passphrase for storage, set @var{salt} to a +string consisting of a prefix plus a sequence of randomly chosen +characters, according to this table: + +@multitable @columnfractions .2 .1 .3 +@headitem One-way function @tab Prefix @tab Random sequence +@item SHA-2-512 +@tab @samp{$6$} +@tab 16 characters +@item SHA-2-256 +@tab @samp{$5$} +@tab 16 characters +@item MD5 +@tab @samp{$1$} +@tab 8 characters +@item DES +@tab @samp{} +@tab 2 characters +@end multitable + +In all cases, the random characters should be chosen from the alphabet +@code{./0-9A-Za-z}. + +With all of the hash functions @emph{except} DES, @var{phrase} can be +arbitrarily long, and all eight bits of each byte are significant. +With DES, only the first eight characters of @var{phrase} affect the +output, and the eighth bit of each byte is also ignored. + +@code{crypt} can fail. Some implementations return @code{NULL} on +failure, and others return an @emph{invalid} hashed passphrase, which +will begin with a @samp{*} and will not be the same as @var{salt}. In +either case, @code{errno} will be set to indicate the problem. Some +of the possible error codes are: + +@table @code +@item EINVAL +@var{salt} is invalid; neither a previously hashed passphrase, nor a +well-formed new salt for any of the supported hash functions. + +@item EPERM +The system configuration forbids use of the hash function selected by +@var{salt}. + +@item ENOMEM +Failed to allocate internal scratch storage. + +@item ENOSYS +@itemx EOPNOTSUPP +Hashing passphrases is not supported at all, or the hash function +selected by @var{salt} is not supported. @Theglibc{} does not use +these error codes, but they may be encountered on other operating +systems. +@end table + +@code{crypt} uses static storage for both internal scratchwork and the +string it returns. It is not safe to call @code{crypt} from multiple +threads simultaneously, and the string it returns will be overwritten +by any subsequent call to @code{crypt}. + +@code{crypt} is specified in the X/Open Portability Guide and is +present on nearly all historical Unix systems. However, the XPG does +not specify any one-way functions. + +@code{crypt} is declared in @file{unistd.h}. @Theglibc{} also +declares this function in @file{crypt.h}. @end deftypefun -@deftypefun {char *} crypt_r (const char *@var{key}, const char *@var{salt}, {struct crypt_data *} @var{data}) +@deftypefun {char *} crypt_r (const char *@var{phrase}, const char *@var{salt}, struct crypt_data *@var{data}) @standards{GNU, crypt.h} @safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{} @asulock{} @ascuheap{} @ascudlopen{}}@acunsafe{@aculock{} @acsmem{}}} +@tindex struct crypt_data @c Compared with crypt, this function fixes the @mtasurace:crypt @c problem, but nothing else. -The @code{crypt_r} function does the same thing as @code{crypt}, but -takes an extra parameter which includes space for its result (among -other things), so it can be reentrant. @code{data@w{->}initialized} must be -cleared to zero before the first time @code{crypt_r} is called. - -The @code{crypt_r} function is a GNU extension. +The function @code{crypt_r} is a thread-safe version of @code{crypt}. +Instead of static storage, it uses the memory pointed to by its +@var{data} argument for both scratchwork and the string it returns. +It can safely be used from multiple threads, as long as different +@var{data} objects are used in each thread. The string it returns +will still be overwritten by another call with the same @var{data}. + +@var{data} must point to a @code{struct crypt_data} object allocated +by the caller. All of the fields of @code{struct crypt_data} are +private, but before one of these objects is used for the first time, +it must be initialized to all zeroes, using @code{memset} or similar. +After that, it can be reused for many calls to @code{crypt_r} without +erasing it again. @code{struct crypt_data} is very large, so it is +best to allocate it with @code{malloc} rather than as a local +variable. @xref{Memory Allocation}. + +@code{crypt_r} is a GNU extension. It is declared in @file{crypt.h}, +as is @code{struct crypt_data}. @end deftypefun -The @code{crypt} and @code{crypt_r} functions are prototyped in the -header @file{crypt.h}. - -The following short program is an example of how to use @code{crypt} the -first time a password is entered. Note that the @var{salt} generation -is just barely acceptable; in particular, it is not unique between -machines, and in many applications it would not be acceptable to let an -attacker know what time the user's password was last set. +The following program shows how to use @code{crypt} the first time a +passphrase is entered. It uses @code{getentropy} to make the salt as +unpredictable as possible; @pxref{Unpredictable Bytes}. @smallexample @include genpass.c.texi @end smallexample -The next program shows how to verify a password. It prompts the user -for a password and prints ``Access granted.'' if the user types -@code{GNU libc manual}. +The next program demonstrates how to verify a passphrase. It checks a +hash hardcoded into the program, because looking up real users' hashed +passphrases may require special privileges (@pxref{User Database}). +It also shows that different one-way functions produce different +hashes for the same passphrase. @smallexample @include testpass.c.texi @@ -123,93 +202,120 @@ for a password and prints ``Access granted.'' if the user types @node Unpredictable Bytes @section Generating Unpredictable Bytes - -Some cryptographic applications (such as session key generation) need -unpredictable bytes. - -In general, application code should use a deterministic random bit -generator, which could call the @code{getentropy} function described -below internally to obtain randomness to seed the generator. The -@code{getrandom} function is intended for low-level applications which -need additional control over the blocking behavior. +@cindex randomness source +@cindex random numbers, cryptographic +@cindex pseudo-random numbers, cryptographic +@cindex cryptographic random number generator +@cindex deterministic random bit generator +@cindex CRNG +@cindex CSPRNG +@cindex DRBG + +Cryptographic applications often need some random data that will be as +difficult as possible for a hostile eavesdropper to guess. For +instance, encryption keys should be chosen at random, and the ``salt'' +strings used by @code{crypt} (@pxref{Passphrase Storage}) should also +be chosen at random. + +The pseudo-random number generators described in @ref{Pseudo-Random +Numbers} are not unpredictable enough for these applications. They +need to use a @dfn{cryptographic random number generator} (CRNG), also +sometimes called a @dfn{cryptographically strong pseudo-random number +generator} (CSPRNG) or @dfn{deterministic random bit generator} (DRBG). + +Currently, @theglibc{} does not provide a cryptographic random number +generator. What it does provide is functions that read random data +from a @dfn{randomness source} supplied by the operating system. The +randomness source is a CRNG at heart, but it also also continually +``re-seeds'' itself from physical sources of randomness, such as +electronic noise and clock jitter. This means applications do not +need to do anything to ensure that the random numbers it produces are +different on each run. + +The catch, however, is that these functions will only produce +relatively short random strings in any one call. Often this is not a +problem, but applications that need more than a few kilobytes of +cryptographically strong random data should call these functions once +and use their output to seed a CRNG. + +Most applications should use @code{getentropy}. The @code{getrandom} +function is intended for low-level applications which need additional +control over blocking behavior. @deftypefun int getentropy (void *@var{buffer}, size_t @var{length}) @standards{GNU, sys/random.h} @safety{@mtsafe{}@assafe{}@acsafe{}} -This function writes @var{length} bytes of random data to the array -starting at @var{buffer}, which must be at most 256 bytes long. The -function returns zero on success. On failure, it returns @code{-1} and -@code{errno} is updated accordingly. - -The @code{getentropy} function is declared in the header file -@file{sys/random.h}. It is derived from OpenBSD. - -The @code{getentropy} function is not a cancellation point. A call to -@code{getentropy} can block if the system has just booted and the kernel -entropy pool has not yet been initialized. In this case, the function -will keep blocking even if a signal arrives, and return only after the -entropy pool has been initialized. - -The @code{getentropy} function can fail with several errors, some of -which are listed below. +This function writes exactly @var{length} bytes of random data to the +array starting at @var{buffer}. @var{length} can be no more than 256. +On success, it returns zero. On failure, it returns @math{-1}, and +@code{errno} is set to indicate the problem. Some of the possible +errors are listed below. @table @code @item ENOSYS -The kernel does not implement the required system call. +The operating system does not implement a randomness source, or does +not support this way of accessing it. (For instance, the system call +used by this function was added to the Linux kernel in version 3.17.) @item EFAULT The combination of @var{buffer} and @var{length} arguments specifies an invalid memory range. @item EIO -More than 256 bytes of randomness have been requested, or the buffer -could not be overwritten with random data for an unspecified reason. - +@var{length} is larger than 256, or the kernel entropy pool has +suffered a catastrophic failure. @end table +A call to @code{getentropy} can only block when the system has just +booted and the randomness source has not yet been initialized. +However, if it does block, it cannot be interrupted by signals or +thread cancellation. Programs intended to run in very early stages of +the boot process may need to use @code{getrandom} in non-blocking mode +instead, and be prepared to cope with random data not being available +at all. + +The @code{getentropy} function is declared in the header file +@file{sys/random.h}. It is derived from OpenBSD. @end deftypefun @deftypefun ssize_t getrandom (void *@var{buffer}, size_t @var{length}, unsigned int @var{flags}) @standards{GNU, sys/random.h} @safety{@mtsafe{}@assafe{}@acsafe{}} -This function writes @var{length} bytes of random data to the array -starting at @var{buffer}. On success, this function returns the number -of bytes which have been written to the buffer (which can be less than -@var{length}). On error, @code{-1} is returned, and @code{errno} is -updated accordingly. - -The @code{getrandom} function is declared in the header file -@file{sys/random.h}. It is a GNU extension. - -The following flags are defined for the @var{flags} argument: +This function writes up to @var{length} bytes of random data to the +array starting at @var{buffer}. The @var{flags} argument should be +either zero, or the bitwise OR of some of the following flags: @table @code @item GRND_RANDOM -Use the @file{/dev/random} (blocking) pool instead of the -@file{/dev/urandom} (non-blocking) pool to obtain randomness. If the -@code{GRND_RANDOM} flag is specified, the @code{getrandom} function can -block even after the randomness source has been initialized. +Use the @file{/dev/random} (blocking) source instead of the +@file{/dev/urandom} (non-blocking) source to obtain randomness. + +If this flag is specified, the call may block, potentially for quite +some time. If it is not specified, the call can only block when the +system has just booted and the randomness source has not yet been +initialized. @item GRND_NONBLOCK Instead of blocking, return to the caller immediately if no data is available. @end table -The @code{getrandom} function is a cancellation point. +Unlike @code{getentropy}, the @code{getrandom} function is a +cancellation point, and if it blocks, it can be interrupted by +signals. -Obtaining randomness from the @file{/dev/urandom} pool (i.e., a call -without the @code{GRND_RANDOM} flag) can block if the system has just -booted and the pool has not yet been initialized. - -The @code{getrandom} function can fail with several errors, some of -which are listed below. In addition, the function may not fill the -buffer completely and return a value less than @var{length}. +On success, @code{getrandom} returns the number of bytes which have +been written to the buffer, which may be less than @var{length}. On +error, it returns @math{-1}, and @code{errno} is set to indicate the +problem. Some of the possible errors are: @table @code @item ENOSYS -The kernel does not implement the @code{getrandom} system call. +The operating system does not implement a randomness source, or does +not support this way of accessing it. (For instance, the system call +used by this function was added to the Linux kernel in version 3.17.) @item EAGAIN No random data was available and @code{GRND_NONBLOCK} was specified in @@ -228,4 +334,7 @@ the kernel randomness pool is initialized, this can happen even if The @var{flags} argument contains an invalid combination of flags. @end table +The @code{getrandom} function is declared in the header file +@file{sys/random.h}. It is a GNU extension. + @end deftypefun diff --git a/manual/examples/genpass.c b/manual/examples/genpass.c index 5edb2e9b8a..23d20789fc 100644 --- a/manual/examples/genpass.c +++ b/manual/examples/genpass.c @@ -16,34 +16,44 @@ */ #include -#include #include #include int main(void) { - unsigned long seed[2]; - char salt[] = "$1$........"; - const char *const seedchars = + unsigned char ubytes[16]; + char salt[20]; + const char *const saltchars = "./0123456789ABCDEFGHIJKLMNOPQRST" "UVWXYZabcdefghijklmnopqrstuvwxyz"; - char *password; + char *hash; int i; - /* Generate a (not very) random seed. - You should do it better than this... */ - seed[0] = time(NULL); - seed[1] = getpid() ^ (seed[0] >> 14 & 0x30000); - - /* Turn it into printable characters from `seedchars'. */ - for (i = 0; i < 8; i++) - salt[3+i] = seedchars[(seed[i/5] >> (i%5)*6) & 0x3f]; - - /* Read in the user's password and encrypt it. */ - password = crypt(getpass("Password:"), salt); + /* Retrieve 16 unpredictable bytes from the operating system. */ + if (getentropy (ubytes, sizeof ubytes)) + { + perror ("getentropy"); + return 1; + } + + /* Use them to fill in the salt string. */ + salt[0] = '$'; + salt[1] = '5'; /* SHA-256 */ + salt[2] = '$'; + for (i = 0; i < 16; i++) + salt[3+i] = saltchars[ubytes[i] & 0x3f]; + salt[3+i] = '\0'; + + /* Read in the user's passphrase and hash it. */ + hash = crypt (getpass ("Enter new passphrase: "), salt); + if (!hash || hash[0] == '*') + { + perror ("crypt"); + return 1; + } /* Print the results. */ - puts(password); + puts (hash); return 0; } diff --git a/manual/examples/mygetpass.c b/manual/examples/mygetpass.c index dfc0c59a7f..13569b327a 100644 --- a/manual/examples/mygetpass.c +++ b/manual/examples/mygetpass.c @@ -1,4 +1,4 @@ -/* Reading Passwords +/* Reading Passphrases Manually Copyright (C) 1991-2018 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or @@ -32,7 +32,7 @@ my_getpass (char **lineptr, size_t *n, FILE *stream) if (tcsetattr (fileno (stream), TCSAFLUSH, &new) != 0) return -1; - /* Read the password. */ + /* Read the passphrase */ nread = getline (lineptr, n, stream); /* Restore terminal. */ diff --git a/manual/examples/testpass.c b/manual/examples/testpass.c index 19f1ae7de0..f8883fea17 100644 --- a/manual/examples/testpass.c +++ b/manual/examples/testpass.c @@ -1,4 +1,4 @@ -/* Verify a password. +/* Verify a passphrase. Copyright (C) 1991-2018 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or @@ -20,24 +20,48 @@ #include #include +/* @samp{GNU's Not Unix} hashed using SHA-256, MD5, and DES. */ +static const char hash_sha[] = + "$5$DQ2z5NHf1jNJnChB$kV3ZTR0aUaosujPhLzR84Llo3BsspNSe4/tsp7VoEn6"; +static const char hash_md5[] = "$1$A3TxDv41$rtXVTUXl2LkeSV0UU5xxs1"; +static const char hash_des[] = "FgkTuF98w5DaI"; + int main(void) { - /* Hashed form of "GNU libc manual". */ - const char *const pass = "$1$/iSaq7rB$EoUw5jJPPvAPECNaaWzMK/"; + char *phrase; + int status = 0; + + /* Prompt for a passphrase. */ + phrase = getpass ("Enter passphrase: "); + + /* Compare against the stored hashes. Any input that begins with + @samp{GNU's No} will match the DES hash, but the other two will + only match @samp{GNU's Not Unix}. */ - char *result; - int ok; + if (strcmp (crypt (phrase, hash_sha), hash_sha)) + { + puts ("SHA: not ok"); + status = 1; + } + else + puts ("SHA: ok"); -/*@group*/ - /* Read in the user's password and encrypt it, - passing the expected password in as the salt. */ - result = crypt(getpass("Password:"), pass); -/*@end group*/ + if (strcmp (crypt (phrase, hash_md5), hash_md5)) + { + puts ("MD5: not ok"); + status = 1; + } + else + puts ("MD5: ok"); - /* Test the result. */ - ok = strcmp (result, pass) == 0; + if (strcmp (crypt (phrase, hash_des), hash_des)) + { + puts ("DES: not ok"); + status = 1; + } + else + puts ("DES: ok"); - puts(ok ? "Access granted." : "Access denied."); - return ok ? 0 : 1; + return status; } diff --git a/manual/intro.texi b/manual/intro.texi index cc9c99f543..779fec8f3d 100644 --- a/manual/intro.texi +++ b/manual/intro.texi @@ -1321,7 +1321,6 @@ this manual. @c Message Translation (8) @c Resource Usage And Limitations (22) @c Inter-Process Communication (27) -@c DES Encryption and Password Handling (33) @c Debugging support (34) @c POSIX Threads (35) @c Internal Probes (36) diff --git a/manual/memory.texi b/manual/memory.texi index b95f6aa1b9..3fa56569c4 100644 --- a/manual/memory.texi +++ b/manual/memory.texi @@ -3452,7 +3452,7 @@ system performance. In this case, locking pages can help. @item Privacy. If you keep secrets in virtual memory and that virtual memory gets paged out, that increases the chance that the secrets will get out. -If a password gets written out to disk swap space, for example, it might +If a passphrase gets written out to disk swap space, for example, it might still be there long after virtual and real memory have been wiped clean. @end itemize diff --git a/manual/nss.texi b/manual/nss.texi index d534c260d3..18361b6f42 100644 --- a/manual/nss.texi +++ b/manual/nss.texi @@ -84,15 +84,15 @@ Network names and numbers, @pxref{Networks Database}. @item protocols Network protocols, @pxref{Protocols Database}. @item passwd -User passwords, @pxref{User Database}. +User identities, @pxref{User Database}. @item rpc -Remote procedure call names and numbers, +Remote procedure call names and numbers. @comment @pxref{RPC Database}. @item services Network services, @pxref{Services Database}. @item shadow -Shadow user passwords, -@comment @pxref{Shadow Password Database}. +User passphrase hashes and related information. +@comment @pxref{Shadow Passphrase Database}. @end table @noindent @@ -526,7 +526,7 @@ with the main application.) The @code{get@var{XXX}by@var{YYY}} functions are the most important functions in the NSS modules. But there are others which implement the other ways to access system databases (say for the -password database, there are @code{setpwent}, @code{getpwent}, and +user database, there are @code{setpwent}, @code{getpwent}, and @code{endpwent}). These will be described in more detail later. Here we give a general way to determine the signature of the module function: @@ -650,7 +650,7 @@ general rules must be followed by all functions. In fact there are four kinds of different functions which may appear in the interface. All derive from the traditional ones for system databases. @var{db} in the following table is normally an abbreviation for the -database (e.g., it is @code{pw} for the password database). +database (e.g., it is @code{pw} for the user database). @table @code @item enum nss_status _nss_@var{database}_set@var{db}ent (void) diff --git a/manual/socket.texi b/manual/socket.texi index 79eb4208be..a6c44b77c3 100644 --- a/manual/socket.texi +++ b/manual/socket.texi @@ -257,7 +257,7 @@ system assigns an address automatically if you have not specified one. Occasionally a client needs to specify an address because the server discriminates based on address; for example, the rsh and rlogin -protocols look at the client's socket address and only bypass password +protocols look at the client's socket address and only bypass passphrase checking if it is less than @code{IPPORT_RESERVED} (@pxref{Ports}). The details of socket addresses vary depending on what namespace you are @@ -3277,7 +3277,7 @@ or request that comes in. If @var{style} uses connections, then @var{user} is the user name that the server should run as. @code{inetd} runs as root, so it can set the user ID of its children arbitrarily. It's best to avoid using @samp{root} for @var{user} if you can; but some -servers, such as Telnet and FTP, read a username and password +servers, such as Telnet and FTP, read a username and passphrase themselves. These servers need to be root initially so they can log in as commanded by the data coming over the network. diff --git a/manual/terminal.texi b/manual/terminal.texi index 0b275fc002..d830baacd7 100644 --- a/manual/terminal.texi +++ b/manual/terminal.texi @@ -24,7 +24,7 @@ descriptor is and how to open a file descriptor for a terminal device. * Line Control:: Sending break sequences, clearing terminal buffers @dots{} * Noncanon Example:: How to read single characters without echo. -* getpass:: Prompting the user for a password. +* getpass:: Prompting the user for a passphrase. * Pseudo-Terminals:: How to open a pseudo-terminal. @end menu @@ -1873,9 +1873,9 @@ handlers for job control signals that reset terminal modes. The above example does so. @node getpass -@section Reading Passwords +@section Reading Passphrases -When reading in a password, it is desirable to avoid displaying it on +When reading in a passphrase, it is desirable to avoid displaying it on the screen, to help keep it secret. The following function handles this in a convenient way. @@ -1884,7 +1884,7 @@ in a convenient way. @safety{@prelim{}@mtunsafe{@mtasuterm{}}@asunsafe{@ascuheap{} @asulock{} @asucorrupt{}}@acunsafe{@acuterm{} @aculock{} @acucorrupt{}}} @c This function will attempt to create a stream for terminal I/O, but @c will fallback to stdio/stderr. It attempts to change the terminal -@c mode in a thread-unsafe way, write out the prompt, read the password, +@c mode in a thread-unsafe way, write out the prompt, read the passphrase, @c then restore the terminal mode. It has a cleanup to close the stream @c in case of (synchronous) cancellation, but not to restore the @c terminal mode. @@ -1892,14 +1892,14 @@ in a convenient way. @code{getpass} outputs @var{prompt}, then reads a string in from the terminal without echoing it. It tries to connect to the real terminal, @file{/dev/tty}, if possible, to encourage users not to put plaintext -passwords in files; otherwise, it uses @code{stdin} and @code{stderr}. +passphrases in files; otherwise, it uses @code{stdin} and @code{stderr}. @code{getpass} also disables the INTR, QUIT, and SUSP characters on the terminal using the @code{ISIG} terminal attribute (@pxref{Local Modes}). The terminal is flushed before and after @code{getpass}, so that -characters of a mistyped password are not accidentally visible. +characters of a mistyped passphrase are not accidentally visible. In other C libraries, @code{getpass} may only return the first -@code{PASS_MAX} bytes of a password. @Theglibc{} has no limit, so +@code{PASS_MAX} bytes of a passphrase. @Theglibc{} has no limit, so @code{PASS_MAX} is undefined. The prototype for this function is in @file{unistd.h}. @code{PASS_MAX} diff --git a/manual/users.texi b/manual/users.texi index 8690b65633..242f0aea0e 100644 --- a/manual/users.texi +++ b/manual/users.texi @@ -1722,7 +1722,6 @@ members. Older systems do not even have the @code{ut_host} member. @node User Database @section User Database @cindex user database -@cindex password database @pindex /etc/passwd This section describes how to search and scan the database of registered @@ -1730,6 +1729,16 @@ users. The database itself is kept in the file @file{/etc/passwd} on most systems, but on some systems a special network server gives access to it. +Historically, this database included one-way hashes of user +passphrases (@pxref{Passphrase Storage}) as well as public information +about each user (such as their user ID and full name). Many of the +functions and data structures associated with this database, and the +filename @file{/etc/passwd} itself, reflect this history. However, +the information in this database is available to all users, and it is +no longer considered safe to make passphrase hashes available to all +users, so they have been moved to a ``shadow'' database that can only +be accessed with special privileges. + @menu * User Data Structure:: What each user record contains. * Lookup User:: How to look for a particular user. @@ -1753,8 +1762,10 @@ entries in the system user data base. It has at least the following members: @item char *pw_name The user's login name. -@item char *pw_passwd. -The encrypted password string. +@item char *pw_passwd +Historically, this field would hold the one-way hash of the user's +passphrase. Nowadays, it will almost always be the single character +@samp{x}, indicating that the hash is in the shadow database. @item uid_t pw_uid The user ID number. @@ -2105,7 +2116,7 @@ rewritten on subsequent calls to @code{fgetpwent}. You must copy the contents of the structure if you wish to save the information. The stream must correspond to a file in the same format as the standard -password database file. +user database file. @end deftypefun @deftypefun int fgetpwent_r (FILE *@var{stream}, struct passwd *@var{result_buf}, char *@var{buffer}, size_t @var{buflen}, struct passwd **@var{result}) @@ -2126,7 +2137,7 @@ first @var{buflen} bytes of the additional buffer pointed to by strings which are pointed to by the elements of the result structure. The stream must correspond to a file in the same format as the standard -password database file. +user database file. If the function returns zero @var{result} points to the structure with the wanted data (normally this is in @var{result_buf}). If errors @@ -2234,7 +2245,6 @@ avoid using it, because it makes sense only on the assumption that the on a system which merges the traditional Unix data base with other extended information about users, adding an entry using this function would inevitably leave out much of the important information. -@c Then how are programmers to modify the password file? -zw The group and user ID fields are left empty if the group or user name starts with a - or +. diff --git a/nscd/pwdcache.c b/nscd/pwdcache.c index 997d7c08fc..96ba46345a 100644 --- a/nscd/pwdcache.c +++ b/nscd/pwdcache.c @@ -405,9 +405,9 @@ addpwbyX (struct database_dyn *db, int fd, request_header *req, if (__glibc_unlikely (debug_level > 0)) { if (he == NULL) - dbg_log (_("Haven't found \"%s\" in password cache!"), keystr); + dbg_log (_("Haven't found \"%s\" in user database cache!"), keystr); else - dbg_log (_("Reloading \"%s\" in password cache!"), keystr); + dbg_log (_("Reloading \"%s\" in user database cache!"), keystr); } while (lookup (req->type, key, &resultbuf, buffer, buflen, &pwd) != 0 diff --git a/posix/unistd.h b/posix/unistd.h index 5c3da702b6..9b30f553d7 100644 --- a/posix/unistd.h +++ b/posix/unistd.h @@ -107,7 +107,7 @@ __BEGIN_DECLS /* The X/Open Unix extensions are available. */ #define _XOPEN_UNIX 1 -/* Encryption is present. */ +/* One-way hashing of passphrases is available. */ #define _XOPEN_CRYPT 1 /* The enhanced internationalization capabilities according to XPG4.2 @@ -1119,8 +1119,12 @@ extern int fdatasync (int __fildes); #endif /* Use POSIX199309 */ #ifdef __USE_XOPEN -/* Encrypt at most 8 characters from KEY using salt to perturb DES. */ -extern char *crypt (const char *__key, const char *__salt) +/* One-way hash PHRASE, returning a string suitable for storage in the + user database. SALT selects the one-way function to use, and + ensures that no two users' hashes are the same, even if they use + the same passphrase. The return value points to static storage + which will be overwritten by the next call to crypt. */ +extern char *crypt (const char *__phrase, const char *__salt) __THROW __nonnull ((1, 2)); /* Swab pairs bytes in the first N bytes of the area pointed to by diff --git a/pwd/pwd.h b/pwd/pwd.h index 25c6b97551..e6d20cd78b 100644 --- a/pwd/pwd.h +++ b/pwd/pwd.h @@ -45,11 +45,12 @@ typedef __uid_t uid_t; # endif #endif -/* The passwd structure. */ +/* A record in the user database. */ struct passwd { char *pw_name; /* Username. */ - char *pw_passwd; /* Password. */ + char *pw_passwd; /* Hashed passphrase, if shadow database + not in use (see shadow.h). */ __uid_t pw_uid; /* User ID. */ __gid_t pw_gid; /* Group ID. */ char *pw_gecos; /* Real name. */ @@ -64,19 +65,19 @@ struct passwd #if defined __USE_MISC || defined __USE_XOPEN_EXTENDED -/* Rewind the password-file stream. +/* Rewind the user database stream. This function is a possible cancellation point and therefore not marked with __THROW. */ extern void setpwent (void); -/* Close the password-file stream. +/* Close the user database stream. This function is a possible cancellation point and therefore not marked with __THROW. */ extern void endpwent (void); -/* Read an entry from the password-file stream, opening it if necessary. +/* Read an entry from the user database stream, opening it if necessary. This function is a possible cancellation point and therefore not marked with __THROW. */ @@ -84,7 +85,7 @@ extern struct passwd *getpwent (void); #endif #ifdef __USE_MISC -/* Read an entry from STREAM. +/* Read a user database entry from STREAM. This function is not part of POSIX and therefore no official cancellation point. But due to similarity with an POSIX interface @@ -92,7 +93,7 @@ extern struct passwd *getpwent (void); therefore not marked with __THROW. */ extern struct passwd *fgetpwent (FILE *__stream) __nonnull ((1)); -/* Write the given entry onto the given stream. +/* Write a given user database entry onto the given stream. This function is not part of POSIX and therefore no official cancellation point. But due to similarity with an POSIX interface @@ -102,13 +103,13 @@ extern int putpwent (const struct passwd *__restrict __p, FILE *__restrict __f); #endif -/* Search for an entry with a matching user ID. +/* Retrieve the user database entry for the given user ID. This function is a possible cancellation point and therefore not marked with __THROW. */ extern struct passwd *getpwuid (__uid_t __uid); -/* Search for an entry with a matching username. +/* Retrieve the user database entry for the given username. This function is a possible cancellation point and therefore not marked with __THROW. */ @@ -155,8 +156,8 @@ extern int getpwnam_r (const char *__restrict __name, # ifdef __USE_MISC -/* Read an entry from STREAM. This function is not standardized and - probably never will. +/* Read a user database entry from STREAM. This function is not + standardized and probably never will. This function is not part of POSIX and therefore no official cancellation point. But due to similarity with an POSIX interface @@ -172,9 +173,9 @@ extern int fgetpwent_r (FILE *__restrict __stream, #endif /* POSIX or reentrant */ #ifdef __USE_GNU -/* Re-construct the password-file line for the given uid - in the given buffer. This knows the format that the caller - will expect, but this need not be the format of the password file. +/* Write a traditional /etc/passwd line, based on the user database + entry for the given UID, to BUFFER; space for BUFFER must be + allocated by the caller. This function is not part of POSIX and therefore no official cancellation point. But due to similarity with an POSIX interface diff --git a/shadow/shadow.h b/shadow/shadow.h index 6f3a570e4b..351882e448 100644 --- a/shadow/shadow.h +++ b/shadow/shadow.h @@ -15,7 +15,11 @@ License along with the GNU C Library; if not, see . */ -/* Declaration of types and functions for shadow password suite. */ +/* Declaration of types and functions for "shadow" storage of hashed + passphrases. The shadow database is like the user database, but is + only accessible with special privileges, so that malicious users + cannot retrieve everyone else's hashed passphrase to brute-force at + their convenience. */ #ifndef _SHADOW_H #define _SHADOW_H 1 @@ -35,11 +39,11 @@ __BEGIN_DECLS -/* Structure of the password file. */ +/* A record in the shadow database. */ struct spwd { char *sp_namp; /* Login name. */ - char *sp_pwdp; /* Encrypted password. */ + char *sp_pwdp; /* Hashed passphrase. */ long int sp_lstchg; /* Date of last change. */ long int sp_min; /* Minimum number of days between changes. */ long int sp_max; /* Maximum number of days between changes. */ @@ -101,7 +105,7 @@ extern struct spwd *sgetspent (const char *__string); therefore not marked with __THROW. */ extern struct spwd *fgetspent (FILE *__stream); -/* Write line containing shadow password entry to stream. +/* Write line containing shadow entry to stream. This function is not part of POSIX and therefore no official cancellation point. But due to similarity with an POSIX interface @@ -137,10 +141,10 @@ extern int fgetspent_r (FILE *__stream, struct spwd *__result_buf, /* The simple locking functionality provided here is not suitable for multi-threaded applications. */ -/* Protect password file against multi writers. */ +/* Request exclusive access to /etc/passwd and /etc/shadow. */ extern int lckpwdf (void) __THROW; -/* Unlock password file. */ +/* Release exclusive access to /etc/passwd and /etc/shadow. */ extern int ulckpwdf (void) __THROW; __END_DECLS From patchwork Mon May 21 17:38:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Zack Weinberg X-Patchwork-Id: 917764 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=sourceware.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=libc-alpha-return-92637-incoming=patchwork.ozlabs.org@sourceware.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=panix.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; secure) header.d=sourceware.org header.i=@sourceware.org header.b="hzlBqVei"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40qQy501tsz9s1w for ; Tue, 22 May 2018 03:39:24 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; q=dns; s= default; b=E7BzSVY15LwpoEZHAdmUdEyMPtdh/Y8qub9EOZ0oy1G+B/FHp1/u4 shK3arFA4tE0vwN76rBsyJ57JrOeNMvrtjqi52jGymVfz8UMGjM5FKaTwv408sx+ BUkrzInlT2/Ohb2AaxIwJr/quNU+C2pKZ1HAJ5EZbOplxwxZYpb3AE= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=sourceware.org; h=list-id :list-unsubscribe:list-subscribe:list-archive:list-post :list-help:sender:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; s=default; bh=P+TJ5nXz+n9z+p3NtCqdc/c/Ky8=; b=hzlBqVeiNBQN+oRcHy4+6i2aViQM B5JKVzpOLI70DbtU5V9R2ZHMqjOKIxxqD+1rgOxCWHrF4DHFSgaiYGX4mll4LOIY aDO7Z+z7JgV7uJarO5j53YcZC5DSyHj8Rm/0YB3ogpszMdwMRgLEUiBVDteXHnv0 IvKFgZd8s2QVg+I= Received: (qmail 110393 invoked by alias); 21 May 2018 17:39:01 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 109455 invoked by uid 89); 21 May 2018 17:39:00 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.9 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, SPF_PASS autolearn=ham version=3.3.2 spammy=maintenance, facilitate, 2096, pwd X-HELO: mailbackend.panix.com From: Zack Weinberg To: libc-alpha@sourceware.org Cc: carlos@redhat.com, fweimer@redhat.com, rj@2c3t.io, kukuk@suse.de Subject: [PATCH 4/4] New configure option --disable-crypt. Date: Mon, 21 May 2018 13:38:53 -0400 Message-Id: <20180521173853.5172-5-zackw@panix.com> In-Reply-To: <20180521173853.5172-1-zackw@panix.com> References: <20180521173853.5172-1-zackw@panix.com> MIME-Version: 1.0 Some Linux distributions are experimenting with a new, separately maintained and hopefully more agile implementation of the crypt(3) API. To facilitate this, add a configure option which disables glibc's embedded libcrypt. When this option is given, libcrypt.* and crypt.h will not be built nor installed. unistd.h continues to define _XOPEN_CRYPT to 1 and to declare crypt. The bulk of the patch is just various places that need to take note of libcrypt possibly not getting built. * configure.ac: New command-line option --disable-crypt. Force --disable-nss-crypt when --disable-crypt is given, with a warning if it was explicitly enabled. * configure: Regenerate. * config.make.in: New boolean substitution variable $(build-crypt). * Makeconfig: Only include 'crypt' in all-subdirs and rpath-dirs when $(build-crypt). * manual/install.texi: Document --disable-crypt. * INSTALL: Regenerate. * crypt/Makefile: Remove code conditional on $(crypt-in-libc), which is never set. * conform/Makefile: Only include libcrypt.a in linknamespace-libs-xsi and linknamespace-libs-XPG4 when $(build-crypt). * elf/Makefile (CFLAGS-tst-linkall-static.c): Only define USE_CRYPT to 1 when $(build-crypt). (tst-linkall-static): Only link libcrypt.a when $(build-crypt). (localplt-built-dso): Only add libcrypt.so when $(build-crypt). * elf/tst-linkall-static.c: Only include crypt.h when USE_CRYPT. --- INSTALL | 11 +++++++++++ Makeconfig | 9 +++++++-- NEWS | 13 +++++++++++++ config.make.in | 1 + configure | 18 ++++++++++++++++++ configure.ac | 11 +++++++++++ conform/Makefile | 11 +++++++---- crypt/Makefile | 4 ---- elf/Makefile | 27 +++++++++++++++++++-------- elf/tst-linkall-static.c | 4 +++- manual/install.texi | 12 ++++++++++++ 11 files changed, 102 insertions(+), 19 deletions(-) diff --git a/INSTALL b/INSTALL index 052b1b6f89..37ec68fb3d 100644 --- a/INSTALL +++ b/INSTALL @@ -197,6 +197,17 @@ if 'CFLAGS' is specified it must enable optimization. For example: libnss_nisplus are not built at all. Use this option to enable libnsl with all depending NSS modules and header files. +'--disable-crypt' + Do not install the passphrase-hashing library 'libcrypt' or the + header file 'crypt.h'. 'unistd.h' will still declare the function + 'crypt', as required by POSIX. Using this option does not change + the set of programs that may need to be linked with '-lcrypt'; it + only means that the GNU C Library will not provide that library. + + This option is for hackers and distributions experimenting with + independently-maintained implementations of libcrypt. It may + become the default in a future release. + '--disable-experimental-malloc' By default, a per-thread cache is enabled in 'malloc'. While this cache can be disabled on a per-application basis using tunables diff --git a/Makeconfig b/Makeconfig index 1afe86475c..608ffe648c 100644 --- a/Makeconfig +++ b/Makeconfig @@ -566,7 +566,7 @@ link-libc-printers-tests = $(link-libc-rpath) \ $(link-libc-tests-after-rpath-link) # This is how to find at build-time things that will be installed there. -rpath-dirs = math elf dlfcn nss nis rt resolv crypt mathvec support +rpath-dirs = math elf dlfcn nss nis rt resolv mathvec support rpath-link = \ $(common-objdir):$(subst $(empty) ,:,$(patsubst ../$(subdir),.,$(rpath-dirs:%=$(common-objpfx)%))) else # build-static @@ -1205,9 +1205,14 @@ all-subdirs = csu assert ctype locale intl catgets math setjmp signal \ stdlib stdio-common libio malloc string wcsmbs time dirent \ grp pwd posix io termios resource misc socket sysvipc gmon \ gnulib iconv iconvdata wctype manual shadow gshadow po argp \ - crypt localedata timezone rt conform debug mathvec support \ + localedata timezone rt conform debug mathvec support \ dlfcn elf +ifeq ($(build-crypt),yes) +all-subdirs += crypt +rpath-dirs += crypt +endif + ifndef avoid-generated # sysd-sorted itself will contain rules making the sysd-sorted target # depend on Depend files. But if you just added a Depend file to an diff --git a/NEWS b/NEWS index 0bd21948f6..e80d3d800c 100644 --- a/NEWS +++ b/NEWS @@ -86,6 +86,19 @@ Deprecated and removed features, and other changes affecting compatibility: binaries. It was just another name for the standard function 'crypt', and it has not appeared in any header file in many years. +* We have tentative plans to hand off maintenance of the passphrase-hashing + library, libcrypt, to a separate development project that will, we hope, + keep up better with new passphrase-hashing algorithms. We will continue + to declare 'crypt' in , as required by POSIX, and programs that + use 'crypt' or 'crypt_r' should not need to change at all; however, system + integrators will need to install and libcrypt from the separate + project. + + In this release, if the configure option --disable-crypt is used, glibc + will not install or libcrypt, making room for the separate + project's versions of these files. The plan is to make this the default + behavior in a future release. + Changes to build and runtime requirements: [Add changes to build and runtime requirements here] diff --git a/config.make.in b/config.make.in index 9e5e24b2c6..d9891b2cd8 100644 --- a/config.make.in +++ b/config.make.in @@ -96,6 +96,7 @@ cross-compiling = @cross_compiling@ force-install = @force_install@ link-obsolete-rpc = @link_obsolete_rpc@ build-obsolete-nsl = @build_obsolete_nsl@ +build-crypt = @build_crypt@ build-nscd = @build_nscd@ use-nscd = @use_nscd@ build-hardcoded-path-in-tests= @hardcoded_path_in_tests@ diff --git a/configure b/configure index 7a8bd3f817..ef18302215 100755 --- a/configure +++ b/configure @@ -676,6 +676,7 @@ build_obsolete_nsl link_obsolete_rpc libc_cv_static_nss_crypt libc_cv_nss_crypt +build_crypt experimental_malloc enable_werror all_warnings @@ -779,6 +780,7 @@ enable_all_warnings enable_werror enable_multi_arch enable_experimental_malloc +enable_crypt enable_nss_crypt enable_obsolete_rpc enable_obsolete_nsl @@ -1448,6 +1450,8 @@ Optional Features: architectures --disable-experimental-malloc disable experimental malloc features + --disable-crypt do not build nor install the passphrase hashing + library, libcrypt --enable-nss-crypt enable libcrypt to use nss --enable-obsolete-rpc build and install the obsolete RPC code for link-time usage @@ -3505,6 +3509,15 @@ fi +# Check whether --enable-crypt was given. +if test "${enable_crypt+set}" = set; then : + enableval=$enable_crypt; build_crypt=$enableval +else + build_crypt=yes +fi + + + # Check whether --enable-nss-crypt was given. if test "${enable_nss_crypt+set}" = set; then : enableval=$enable_nss_crypt; nss_crypt=$enableval @@ -3512,6 +3525,11 @@ else nss_crypt=no fi +if test x$build_libcrypt = xno && test x$nss_crypt = xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: --enable-nss-crypt has no effect when libcrypt is disabled" >&5 +$as_echo "$as_me: WARNING: --enable-nss-crypt has no effect when libcrypt is disabled" >&2;} + nss_crypt=no +fi if test x$nss_crypt = xyes; then nss_includes=-I$(nss-config --includedir 2>/dev/null) if test $? -ne 0; then diff --git a/configure.ac b/configure.ac index ca1282a6b3..dc517017f5 100644 --- a/configure.ac +++ b/configure.ac @@ -302,11 +302,22 @@ AC_ARG_ENABLE([experimental-malloc], [experimental_malloc=yes]) AC_SUBST(experimental_malloc) +AC_ARG_ENABLE([crypt], + AC_HELP_STRING([--disable-crypt], + [do not build nor install the passphrase hashing library, libcrypt]), + [build_crypt=$enableval], + [build_crypt=yes]) +AC_SUBST(build_crypt) + AC_ARG_ENABLE([nss-crypt], AC_HELP_STRING([--enable-nss-crypt], [enable libcrypt to use nss]), [nss_crypt=$enableval], [nss_crypt=no]) +if test x$build_libcrypt = xno && test x$nss_crypt = xyes; then + AC_MSG_WARN([--enable-nss-crypt has no effect when libcrypt is disabled]) + nss_crypt=no +fi if test x$nss_crypt = xyes; then nss_includes=-I$(nss-config --includedir 2>/dev/null) if test $? -ne 0; then diff --git a/conform/Makefile b/conform/Makefile index 864fdeca21..74fbda0786 100644 --- a/conform/Makefile +++ b/conform/Makefile @@ -193,13 +193,11 @@ linknamespace-libs-thr = $(linknamespace-libs-isoc) \ $(common-objpfx)rt/librt.a $(static-thread-library) linknamespace-libs-posix = $(linknamespace-libs-thr) \ $(common-objpfx)dlfcn/libdl.a -linknamespace-libs-xsi = $(linknamespace-libs-posix) \ - $(common-objpfx)crypt/libcrypt.a +linknamespace-libs-xsi = $(linknamespace-libs-posix) linknamespace-libs-ISO = $(linknamespace-libs-isoc) linknamespace-libs-ISO99 = $(linknamespace-libs-isoc) linknamespace-libs-ISO11 = $(linknamespace-libs-isoc) -linknamespace-libs-XPG4 = $(linknamespace-libs-isoc) \ - $(common-objpfx)crypt/libcrypt.a +linknamespace-libs-XPG4 = $(linknamespace-libs-isoc) linknamespace-libs-XPG42 = $(linknamespace-libs-XPG4) linknamespace-libs-POSIX = $(linknamespace-libs-thr) linknamespace-libs-UNIX98 = $(linknamespace-libs-xsi) @@ -209,6 +207,11 @@ linknamespace-libs-XOPEN2K8 = $(linknamespace-libs-xsi) linknamespace-libs = $(foreach std,$(conformtest-standards),\ $(linknamespace-libs-$(std))) +ifeq ($(build-crypt),yes) +linknamespace-libs-xsi += $(common-objpfx)crypt/libcrypt.a +linknamespace-libs-XPG4 += $(common-objpfx)crypt/libcrypt.a +endif + $(linknamespace-symlist-stdlibs-tests): $(objpfx)symlist-stdlibs-%: \ $(linknamespace-libs) LC_ALL=C $(READELF) -W -s $(linknamespace-libs-$*) > $@; \ diff --git a/crypt/Makefile b/crypt/Makefile index 303800df73..3811b6e298 100644 --- a/crypt/Makefile +++ b/crypt/Makefile @@ -32,10 +32,6 @@ libcrypt-routines := crypt-entry md5-crypt sha256-crypt sha512-crypt crypt \ tests := cert md5c-test sha256c-test sha512c-test badsalttest -ifeq ($(crypt-in-libc),yes) -routines += $(libcrypt-routines) -endif - ifeq ($(nss-crypt),yes) nss-cpp-flags := -DUSE_NSS \ -I$(shell nss-config --includedir) -I$(shell nspr-config --includedir) diff --git a/elf/Makefile b/elf/Makefile index 2dcd2b88e0..5b94f8d038 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -387,14 +387,21 @@ $(objpfx)tst-_dl_addr_inside_object: $(objpfx)dl-addr-obj.os CFLAGS-tst-_dl_addr_inside_object.c += $(PIE-ccflag) endif -# By default tst-linkall-static should try to use crypt routines to test -# static libcrypt use. +# We can only test static libcrypt use if libcrypt has been built, +# and either NSS crypto is not in use, or static NSS libraries are +# available. +ifeq ($(build-crypt),no) +CFLAGS-tst-linkall-static.c += -DUSE_CRYPT=0 +else +ifeq ($(nss-crypt),no) +CFLAGS-tst-linkall-static.c += -DUSE_CRYPT=1 +else +ifeq ($(static-nss-crypt),no) +CFLAGS-tst-linkall-static.c += -DUSE_CRYPT=0 +else CFLAGS-tst-linkall-static.c += -DUSE_CRYPT=1 -# However, if we are using NSS crypto and we don't have a static -# library, then we exclude the use of crypt functions in the test. -# We similarly exclude libcrypt.a from the static link (see below). -ifeq (yesno,$(nss-crypt)$(static-nss-crypt)) -CFLAGS-tst-linkall-static.c += -UUSE_CRYPT -DUSE_CRYPT=0 +endif +endif endif include ../Rules @@ -1115,7 +1122,6 @@ localplt-built-dso := $(addprefix $(common-objpfx),\ rt/librt.so \ dlfcn/libdl.so \ resolv/libresolv.so \ - crypt/libcrypt.so \ ) ifeq ($(build-mathvec),yes) localplt-built-dso += $(addprefix $(common-objpfx), mathvec/libmvec.so) @@ -1123,6 +1129,9 @@ endif ifeq ($(have-thread-library),yes) localplt-built-dso += $(filter-out %_nonshared.a, $(shared-thread-library)) endif +ifeq ($(build-crypt),yes) +localplt-built-dso += $(addprefix $(common-objpfx), crypt/libcrypt.so) +endif vpath localplt.data $(+sysdep_dirs) @@ -1397,6 +1406,7 @@ $(objpfx)tst-linkall-static: \ $(common-objpfx)resolv/libanl.a \ $(static-thread-library) +ifeq ($(build-crypt),yes) # If we are using NSS crypto and we have the ability to link statically # then we include libcrypt.a, otherwise we leave out libcrypt.a and # link as much as we can into the tst-linkall-static test. This assumes @@ -1412,6 +1422,7 @@ ifeq (no,$(nss-crypt)) $(objpfx)tst-linkall-static: \ $(common-objpfx)crypt/libcrypt.a endif +endif # The application depends on the DSO, and the DSO loads the plugin. # The plugin also depends on the DSO. This creates the circular diff --git a/elf/tst-linkall-static.c b/elf/tst-linkall-static.c index e8df38f74e..d0f2592e67 100644 --- a/elf/tst-linkall-static.c +++ b/elf/tst-linkall-static.c @@ -18,7 +18,9 @@ #include #include -#include +#if USE_CRYPT +# include +#endif #include #include #include diff --git a/manual/install.texi b/manual/install.texi index 4bbbfcffa5..6e18f85b8b 100644 --- a/manual/install.texi +++ b/manual/install.texi @@ -230,6 +230,18 @@ libnss_nisplus are not built at all. Use this option to enable libnsl with all depending NSS modules and header files. +@item --disable-crypt +Do not install the passphrase-hashing library @file{libcrypt} or the +header file @file{crypt.h}. @file{unistd.h} will still declare the +function @code{crypt}, as required by POSIX@. Using this option does +not change the set of programs that may need to be linked with +@option{-lcrypt}; it only means that @theglibc{} will not provide that +library. + +This option is for hackers and distributions experimenting with +independently-maintained implementations of libcrypt. It may become +the default in a future release. + @item --disable-experimental-malloc By default, a per-thread cache is enabled in @code{malloc}. While this cache can be disabled on a per-application basis using tunables