summaryrefslogtreecommitdiff
path: root/mkpasswd.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2019-12-06 13:10:00 +0300
committerIgor Pashev <pashev.igor@gmail.com>2019-12-06 13:10:00 +0300
commit8c13fdabc9833ead8afb57f6c4b476fb7a1ab9e6 (patch)
tree6acdbdadfef2a251bb95ef0aed0f673f0f2bbfa9 /mkpasswd.c
parent45eb26992d9fa4efd74b7b283834dcfc212a403f (diff)
parentabf1f11b61b525aa6b95673e50d4be90505b1d67 (diff)
downloadwhois-8c13fdabc9833ead8afb57f6c4b476fb7a1ab9e6.tar.gz
Merge git://github.com/rfc1036/whoisHEADmaster
Diffstat (limited to 'mkpasswd.c')
-rw-r--r--mkpasswd.c232
1 files changed, 167 insertions, 65 deletions
diff --git a/mkpasswd.c b/mkpasswd.c
index a80e7e9..002bb42 100644
--- a/mkpasswd.c
+++ b/mkpasswd.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2001-2008 Marco d'Itri
+ * Copyright (C) 2001-2019 Marco d'Itri <md@linux.it>.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -11,14 +11,14 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/* for crypt, snprintf and strcasecmp */
#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600
+#define _XOPEN_SOURCE 500
#endif
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
@@ -37,14 +37,14 @@
#endif
#include <fcntl.h>
#include <string.h>
+#include <strings.h>
#include <time.h>
#include <sys/types.h>
-#ifdef HAVE_XCRYPT
+#ifdef HAVE_XCRYPT_H
#include <xcrypt.h>
#include <sys/stat.h>
#endif
-#ifdef HAVE_LINUX_CRYPT_GENSALT
-#define _OW_SOURCE
+#ifdef HAVE_CRYPT_H
#include <crypt.h>
#endif
#ifdef HAVE_GETTIMEOFDAY
@@ -86,27 +86,45 @@ struct crypt_method {
const char *desc; /* long description for the methods list */
};
+/* XCRYPT_VERSION_NUM is defined in crypt.h from libxcrypt */
+#if defined XCRYPT_VERSION_NUM
+# define HAVE_SHA_CRYPT
+# define HAVE_BCRYPT
+# define HAVE_BSDICRYPT
+#endif
+
static const struct crypt_method methods[] = {
/* method prefix minlen, maxlen rounds description */
- { "des", "", 2, 2, 0,
- N_("standard 56 bit DES-based crypt(3)") },
- { "md5", "$1$", 8, 8, 0, "MD5" },
-#if defined OpenBSD || defined FreeBSD || (defined __SVR4 && defined __sun)
- { "bf", "$2a$", 22, 22, 1, "Blowfish" },
+#ifdef CRYPT_GENSALT_IMPLEMENTS_DEFAULT_PREFIX
+ { "auto", NULL, 0, 0, 0, NULL },
#endif
-#if defined HAVE_LINUX_CRYPT_GENSALT
- { "bf", "$2a$", 22, 22, 1, "Blowfish, system-specific on 8-bit chars" },
- /* algorithm 2y fixes CVE-2011-2483 */
- { "bfy", "$2y$", 22, 22, 1, "Blowfish, correct handling of 8-bit chars" },
+ /* compatibility aliases for mkpasswd versions < 5.4.0 */
+ { "des", "", 2, 2, 0, NULL },
+ { "md5", "$1$", 8, 8, 0, NULL },
+#if defined XCRYPT_VERSION_NUM
+ { "yescrypt", "$y$", 0, 0, 0, "Yescrypt" },
+#if XCRYPT_VERSION_NUM >= ((4 << 16) | 4)
+ { "gost-yescrypt", "$gy$", 0, 0, 0, "GOST Yescrypt" },
#endif
-#if defined FreeBSD
- { "nt", "$3$", 0, 0, 0, "NT-Hash" },
+ { "scrypt", "$7$", 0, 0, 0, "scrypt" },
+#endif
+#ifdef HAVE_BCRYPT_OBSOLETE
+ /* http://marc.info/?l=openbsd-misc&m=139320023202696 */
+ { "bf", "$2a$", 22, 22, 2, "bcrypt" },
+#endif
+#ifdef HAVE_BCRYPT
+ { "bcrypt", "$2b$", 22, 22, 2, "bcrypt" },
+ { "bcrypt-a", "$2a$", 22, 22, 2, "bcrypt (obsolete $2a$ version)" },
#endif
#if defined HAVE_SHA_CRYPT
/* http://people.redhat.com/drepper/SHA-crypt.txt */
- { "sha-256", "$5$", 8, 16, 1, "SHA-256" },
- { "sha-512", "$6$", 8, 16, 1, "SHA-512" },
+ { "sha512crypt", "$6$", 8, 16, 1, "SHA-512" },
+ { "sha256crypt", "$5$", 8, 16, 1, "SHA-256" },
+ /* compatibility aliases for mkpasswd versions < 5.4.0 */
+ { "sha-256", "$5$", 8, 16, 1, NULL },
+ { "sha-512", "$6$", 8, 16, 1, NULL },
#endif
+#if (defined __SVR4 && defined __sun) || defined XCRYPT_VERSION_NUM
/* http://www.crypticide.com/dropsafe/article/1389 */
/*
* Actually the maximum salt length is arbitrary, but Solaris by default
@@ -114,17 +132,27 @@ static const struct crypt_method methods[] = {
* http://cvs.opensolaris.org/source/xref/onnv/onnv-gate/ \
* usr/src/lib/crypt_modules/sunmd5/sunmd5.c#crypt_gensalt_impl
*/
-#if defined __SVR4 && defined __sun
{ "sunmd5", "$md5$", 8, 8, 1, "SunMD5" },
#endif
+ { "md5crypt", "$1$", 8, 8, 0, "MD5" },
+#ifdef HAVE_BSDICRYPT
+ { "bsdicrypt", "_", 0, 0, 0,
+ N_("BSDI extended DES-based crypt(3)") },
+#endif
+ { "descrypt", "", 2, 2, 0,
+ N_("standard 56 bit DES-based crypt(3)") },
+#if defined FreeBSD || defined XCRYPT_VERSION_NUM
+ { "nt", "$3$", 0, 0, 0, "NT-Hash" },
+#endif
{ NULL, NULL, 0, 0, 0, NULL }
};
void generate_salt(char *const buf, const unsigned int len);
-void *get_random_bytes(const int len);
-void display_help(int error);
+void *get_random_bytes(const unsigned int len);
+void NORETURN display_help(int error);
void display_version(void);
void display_methods(void);
+char *read_line(FILE *fp);
int main(int argc, char *argv[])
{
@@ -149,7 +177,7 @@ int main(int argc, char *argv[])
/* prepend options from environment */
argv = merge_args(getenv("MKPASSWD_OPTIONS"), argv, &argc);
- while ((ch = GETOPT_LONGISH(argc, argv, "hH:m:5P:R:sS:V", longopts, 0))
+ while ((ch = GETOPT_LONGISH(argc, argv, "hH:m:5P:R:sS:V", longopts, NULL))
> 0) {
switch (ch) {
case '5':
@@ -161,6 +189,17 @@ int main(int argc, char *argv[])
display_methods();
exit(0);
}
+#if defined HAVE_LINUX_CRYPT_GENSALT || defined HAVE_SOLARIS_CRYPT_GENSALT
+ if (optarg[0] == '$'
+ && strlen(optarg) > 2
+ && *(optarg + strlen(optarg) - 1) == '$') {
+ salt_prefix = NOFAIL(strdup(optarg));
+ salt_minlen = 0;
+ salt_maxlen = 0;
+ rounds_support = 0;
+ break;
+ }
+#endif
for (i = 0; methods[i].method != NULL; i++)
if (strcaseeq(methods[i].method, optarg)) {
salt_prefix = methods[i].prefix;
@@ -227,18 +266,21 @@ int main(int argc, char *argv[])
display_help(EXIT_FAILURE);
}
- /* default: DES password */
+ /* default: DES password, or else whatever crypt_gensalt chooses */
if (!salt_prefix) {
salt_minlen = methods[0].minlen;
salt_maxlen = methods[0].maxlen;
salt_prefix = methods[0].prefix;
+ rounds_support = methods[0].rounds;
}
- if (streq(salt_prefix, "$2a$") || streq(salt_prefix, "$2y$")) {
- /* OpenBSD Blowfish and derivatives */
+ if (!salt_prefix) {
+ /* NULL means that crypt_gensalt will choose one later */
+ } else if (rounds_support == 2) {
+ /* bcrypt strings always contain the rounds number */
if (rounds <= 5)
rounds = 5;
- /* actually for 2a/2y it is the logarithm of the number of rounds */
+ /* actually it is the logarithm of the number of rounds */
snprintf(rounds_str, sizeof(rounds_str), "%02u$", rounds);
} else if (rounds_support && rounds)
snprintf(rounds_str, sizeof(rounds_str), "rounds=%u$", rounds);
@@ -279,17 +321,20 @@ int main(int argc, char *argv[])
} else {
#ifdef HAVE_SOLARIS_CRYPT_GENSALT
salt = crypt_gensalt(salt_prefix, NULL);
- if (!salt)
- perror("crypt_gensalt");
+ if (!salt) {
+ perror("crypt_gensalt");
+ exit(2);
+ }
#elif defined HAVE_LINUX_CRYPT_GENSALT
void *entropy = get_random_bytes(64);
salt = crypt_gensalt(salt_prefix, rounds, entropy, 64);
if (!salt) {
- fprintf(stderr, "crypt_gensalt failed.\n");
- exit(2);
+ perror("crypt_gensalt");
+ exit(2);
}
- free(entropy);
+ if (entropy)
+ free(entropy);
#else
unsigned int salt_len = salt_maxlen;
@@ -310,24 +355,20 @@ int main(int argc, char *argv[])
if (password) {
} else if (password_fd != -1) {
FILE *fp;
- char *p;
if (isatty(password_fd))
fprintf(stderr, _("Password: "));
- password = NOFAIL(malloc(128));
fp = fdopen(password_fd, "r");
if (!fp) {
perror("fdopen");
exit(2);
}
- if (!fgets(password, 128, fp)) {
- perror("fgets");
+
+ password = read_line(fp);
+ if (!password) {
+ perror("fgetc");
exit(2);
}
-
- p = strpbrk(password, "\n\r");
- if (p)
- *p = '\0';
} else {
password = getpass(_("Password: "));
if (!password) {
@@ -341,12 +382,13 @@ int main(int argc, char *argv[])
result = crypt(password, salt);
/* xcrypt returns "*0" on errors */
if (!result || result[0] == '*') {
- fprintf(stderr, "crypt failed.\n");
+ if (CRYPT_SETS_ERRNO)
+ perror("crypt");
+ else
+ fprintf(stderr, "crypt failed.\n");
exit(2);
}
- /* yes, using strlen(salt_prefix) on salt. It's not
- * documented whether crypt_gensalt may change the prefix */
- if (!strneq(result, salt, strlen(salt_prefix))) {
+ if (!strneq(result, salt, strlen(salt))) {
fprintf(stderr, _("Method not supported by crypt(3).\n"));
exit(2);
}
@@ -356,44 +398,73 @@ int main(int argc, char *argv[])
exit(0);
}
-#ifdef RANDOM_DEVICE
-void* get_random_bytes(const int count)
+#ifdef CRYPT_GENSALT_IMPLEMENTS_AUTO_ENTROPY
+
+/*
+ * If NULL is passed to the libxcrypt version of crypt_gensalt() instead of
+ * the buffer of random bytes then the function will obtain by itself the
+ * required randomness.
+ */
+inline void *get_random_bytes(const unsigned int count)
{
- char *buf;
+ return NULL;
+}
+
+#elif defined HAVE_SOLARIS_CRYPT_GENSALT
+
+/*
+ * The Solaris version of crypt_gensalt() gathers the random data by itself.
+ */
+
+#elif defined RANDOM_DEVICE || defined HAVE_ARC4RANDOM_BUF || defined HAVE_GETENTROPY
+
+void *get_random_bytes(const unsigned int count)
+{
+ char *buf = NOFAIL(malloc(count));
+
+#if defined HAVE_ARC4RANDOM_BUF
+ arc4random_buf(buf, count);
+#elif defined HAVE_GETENTROPY
+ if (getentropy(buf, count) < 0)
+ perror("getentropy");
+#else
int fd;
+ ssize_t bytes_read;
- buf = NOFAIL(malloc(count));
fd = open(RANDOM_DEVICE, O_RDONLY);
if (fd < 0) {
perror("open(" RANDOM_DEVICE ")");
exit(2);
}
- if (read(fd, buf, count) != count) {
- if (count < 0)
- perror("read(" RANDOM_DEVICE ")");
- else
- fprintf(stderr, "Short read of %s.\n", RANDOM_DEVICE);
+ bytes_read = read(fd, buf, count);
+ if (bytes_read < 0) {
+ perror("read(" RANDOM_DEVICE ")");
+ exit(2);
+ }
+ if (bytes_read != count) {
+ fprintf(stderr, "Short read of %s.\n", RANDOM_DEVICE);
exit(2);
}
close(fd);
+#endif
return buf;
}
-#endif
-
-#ifdef RANDOM_DEVICE
void generate_salt(char *const buf, const unsigned int len)
{
unsigned int i;
+ unsigned char *entropy;
+
+ entropy = get_random_bytes(len);
- unsigned char *entropy = get_random_bytes(len * sizeof(unsigned char));
for (i = 0; i < len; i++)
buf[i] = valid_salts[entropy[i] % (sizeof valid_salts - 1)];
buf[i] = '\0';
+ free(entropy);
}
-#else /* RANDOM_DEVICE */
+#else /* RANDOM_DEVICE || HAVE_ARC4RANDOM_BUF || HAVE_GETENTROPY */
void generate_salt(char *const buf, const unsigned int len)
{
@@ -421,21 +492,25 @@ void generate_salt(char *const buf, const unsigned int len)
buf[i] = '\0';
}
-#endif /* RANDOM_DEVICE */
+#endif /* RANDOM_DEVICE || HAVE_ARC4RANDOM_BUF || HAVE_GETENTROPY*/
-void display_help(int error)
+void NORETURN display_help(int error)
{
fprintf((EXIT_SUCCESS == error) ? stdout : stderr,
_("Usage: mkpasswd [OPTIONS]... [PASSWORD [SALT]]\n"
"Crypts the PASSWORD using crypt(3).\n\n"));
- fprintf(stderr, _(
+ fprintf((EXIT_SUCCESS == error) ? stdout : stderr, _(
" -m, --method=TYPE select method TYPE\n"
" -5 like --method=md5\n"
" -S, --salt=SALT use the specified SALT\n"
+ ));
+ fprintf((EXIT_SUCCESS == error) ? stdout : stderr, _(
" -R, --rounds=NUMBER use the specified NUMBER of rounds\n"
" -P, --password-fd=NUM read the password from file descriptor NUM\n"
" instead of /dev/tty\n"
" -s, --stdin like --password-fd=0\n"
+ ));
+ fprintf((EXIT_SUCCESS == error) ? stdout : stderr, _(
" -h, --help display this help and exit\n"
" -V, --version output version information and exit\n"
"\n"
@@ -450,7 +525,7 @@ void display_help(int error)
void display_version(void)
{
printf("mkpasswd %s\n\n", VERSION);
- puts("Copyright (C) 2001-2008 Marco d'Itri\n"
+ puts("Copyright (C) 2001-2019 Marco d'Itri\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
}
@@ -461,6 +536,33 @@ void display_methods(void)
printf(_("Available methods:\n"));
for (i = 0; methods[i].method != NULL; i++)
- printf("%s\t%s\n", methods[i].method, methods[i].desc);
+ if (methods[i].desc)
+ printf("%-15s %s\n", methods[i].method, methods[i].desc);
+}
+
+char *read_line(FILE *fp) {
+ int size = 128;
+ int ch;
+ size_t pos = 0;
+ char *password;
+
+ password = NOFAIL(malloc(size));
+
+ while ((ch = fgetc(fp)) != EOF) {
+ if (ch == '\n' || ch == '\r')
+ break;
+ password[pos++] = ch;
+ if (pos == size) {
+ size += 128;
+ password = NOFAIL(realloc(password, size));
+ }
+ }
+ password[pos] = '\0';
+
+ if (ferror(fp)) {
+ free(password);
+ return NULL;
+ }
+ return password;
}