Retiring crypt
tedunangst.com
tedunangst.com
The printf("%s %s", foo(), foo()) problem is unusual for crypt() --- but it isn't for other functions that return points to global static memory, inet_ntoa() in particular (you often want to print both source and destination addresses). To get around this, I used to have a preloaded inet_ntoa that alternated between two global static buffers. :)
The NetBSD man page for inet_ntoa lists "The string returned by inet_ntoa() resides in a static memory area" in the BUGS section, Linux is not so forward about it.
The string is returned in a statically allocated buffer, which subsequent calls will overwrite.Our codebase has quite a few functions like inet_ntoa():
/* returns ptr. to internal static storage */
const char *type_to_str(const Type *type);
You could pass an explicit argument, but that's pretty ugly: /* Explicit buffer argument */
char msg_buf1[256], msg_buf2[256], msg_buf3[256], ..., msg_buf16[256];
char *type_to_str(char *buf_to_use, size_t buf_size, const Type *type)
Alternatively, you could give C99 a workout and abuse compound literals as anonymous storage: #include <stdio.h>
struct foo {
int bar;
};
#define FOO_TO_STR_SIZE 256
#define foo_to_str(foo) \
foo_to_str_((char [FOO_TO_STR_SIZE]){ 0 }, FOO_TO_STR_SIZE, (foo))
/* Implementation detail */
__attribute__((nonnull))
static char *foo_to_str_(char *buf_to_use, size_t size,
const struct foo *foo)
{
(void)snprintf(buf_to_use, size, "%d", foo->bar);
return buf_to_use;
}
int main(void)
{
const struct foo foo = {
.bar = 42
}, foo2 = {
.bar = 43
};
printf("%s %s\n", foo_to_str(&foo),
foo_to_str(&foo2));
return 0;
}
(Warning: this is probably too clever. Note that you need the explicit size argument if you offer a library, or you risk your callers using a different FOO_TO_STR_SIZE than you do. There is probably a very minor performance penalty to this solution as the caller must, in general, completely initialize the string. Note the gcc warnings about compound literals in C++ - see https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.html for a discussion.) string password_hash ( string $password , integer $algo [, array $options ] )
boolean password_verify ( string $password , string $hash )
boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )For NIS, you'd need to ensure that every machine that touches passwords via NIS is configured to use the same algorithm when users change passwords. On Solaris, just configure CRYPT_* in /etc/security/policy.conf the same on every machine. (See the policy.conf man page — in short, you want to change the default algorithm to 1 [or whatever] and set __unix__ to be deprecated.) On Linux and *BSD, how you do it depends on the distro/version.
Fun fact about changing passwords in NIS: When a yppasswd client contacts rpc.yppasswdd to change a user's password, the user's new password is sent crypt()ed, but the user's old password is sent in the clear.
OpenBSD implemented bcrypt more than 17 years ago http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/crypt/...