Author: ed
Date: Wed Aug 10 15:16:28 2016
New Revision: 303920
URL: https://svnweb.freebsd.org/changeset/base/303920

Log:
  Make libcrypt thread-safe. Add crypt_r(3).
  
  glibc has a pretty nice function called crypt_r(3), which is nothing
  more than crypt(3), but thread-safe. It accomplishes this by introducing
  a 'struct crypt_data' structure that contains a buffer that is large
  enough to hold the resulting string.
  
  Let's go ahead and also add this function. It would be a shame if a
  useful function like this wouldn't be usable in multithreaded apps.
  Refactor crypt.c and all of the backends to no longer declare static
  arrays, but write their output in a provided buffer.
  
  There is no need to do any buffer length computation here, as we'll just
  need to ensure that 'struct crypt_data' is large enough, which it is.
  _PASSWORD_LEN is defined to 128 bytes, but in this case I'm picking 256,
  as this is going to be part of the actual ABI.
  
  Differential Revision:        https://reviews.freebsd.org/D7306

Modified:
  head/include/unistd.h
  head/lib/libcrypt/Makefile
  head/lib/libcrypt/crypt-md5.c
  head/lib/libcrypt/crypt-nthash.c
  head/lib/libcrypt/crypt-sha256.c
  head/lib/libcrypt/crypt-sha512.c
  head/lib/libcrypt/crypt.3
  head/lib/libcrypt/crypt.c
  head/lib/libcrypt/crypt.h
  head/lib/libcrypt/misc.c
  head/secure/lib/libcrypt/crypt-blowfish.c
  head/secure/lib/libcrypt/crypt-des.c

Modified: head/include/unistd.h
==============================================================================
--- head/include/unistd.h       Wed Aug 10 14:41:53 2016        (r303919)
+++ head/include/unistd.h       Wed Aug 10 15:16:28 2016        (r303920)
@@ -484,11 +484,18 @@ pid_t      vfork(void) __returns_twice;
 
 #if __BSD_VISIBLE
 struct timeval;                                /* select(2) */
+
+struct crypt_data {
+       int     initialized;    /* For compatibility with glibc. */
+       char    __buf[256];     /* Buffer returned by crypt_r(). */
+};
+
 int     acct(const char *);
 int     async_daemon(void);
 int     check_utility_compat(const char *);
 const char *
         crypt_get_format(void);
+char   *crypt_r(const char *, const char *, struct crypt_data *);
 int     crypt_set_format(const char *);
 int     des_cipher(const char *, char *, long, int);
 int     des_setkey(const char *key);

Modified: head/lib/libcrypt/Makefile
==============================================================================
--- head/lib/libcrypt/Makefile  Wed Aug 10 14:41:53 2016        (r303919)
+++ head/lib/libcrypt/Makefile  Wed Aug 10 15:16:28 2016        (r303920)
@@ -17,7 +17,8 @@ SRCS=         crypt.c misc.c \
                crypt-sha256.c sha256c.c \
                crypt-sha512.c sha512c.c
 MAN=           crypt.3
-MLINKS=                crypt.3 crypt_get_format.3 crypt.3 crypt_set_format.3
+MLINKS=                crypt.3 crypt_get_format.3 crypt.3 crypt_r.3 \
+               crypt.3 crypt_set_format.3
 CFLAGS+=       -I${.CURDIR}/../libmd -I${.CURDIR}/../libutil \
                -I${.CURDIR}/../../sys/crypto/sha2
 

Modified: head/lib/libcrypt/crypt-md5.c
==============================================================================
--- head/lib/libcrypt/crypt-md5.c       Wed Aug 10 14:41:53 2016        
(r303919)
+++ head/lib/libcrypt/crypt-md5.c       Wed Aug 10 15:16:28 2016        
(r303920)
@@ -41,31 +41,27 @@ __FBSDID("$FreeBSD$");
  * UNIX password
  */
 
-char *
-crypt_md5(const char *pw, const char *salt)
+int
+crypt_md5(const char *pw, const char *salt, char *buffer)
 {
        MD5_CTX ctx,ctx1;
        unsigned long l;
        int sl, pl;
        u_int i;
        u_char final[MD5_SIZE];
-       static const char *sp, *ep;
-       static char passwd[120], *p;
+       const char *ep;
        static const char *magic = "$1$";
 
-       /* Refine the Salt first */
-       sp = salt;
-
-       /* If it starts with the magic string, then skip that */
-       if(!strncmp(sp, magic, strlen(magic)))
-               sp += strlen(magic);
+       /* If the salt starts with the magic string, skip that. */
+       if (!strncmp(salt, magic, strlen(magic)))
+               salt += strlen(magic);
 
        /* It stops at the first '$', max 8 chars */
-       for(ep = sp; *ep && *ep != '$' && ep < (sp + 8); ep++)
+       for (ep = salt; *ep && *ep != '$' && ep < salt + 8; ep++)
                continue;
 
        /* get the length of the true salt */
-       sl = ep - sp;
+       sl = ep - salt;
 
        MD5Init(&ctx);
 
@@ -76,12 +72,12 @@ crypt_md5(const char *pw, const char *sa
        MD5Update(&ctx, (const u_char *)magic, strlen(magic));
 
        /* Then the raw salt */
-       MD5Update(&ctx, (const u_char *)sp, (u_int)sl);
+       MD5Update(&ctx, (const u_char *)salt, (u_int)sl);
 
        /* Then just as many characters of the MD5(pw,salt,pw) */
        MD5Init(&ctx1);
        MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
-       MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
+       MD5Update(&ctx1, (const u_char *)salt, (u_int)sl);
        MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
        MD5Final(final, &ctx1);
        for(pl = (int)strlen(pw); pl > 0; pl -= MD5_SIZE)
@@ -99,9 +95,9 @@ crypt_md5(const char *pw, const char *sa
                    MD5Update(&ctx, (const u_char *)pw, 1);
 
        /* Now make the output string */
-       strcpy(passwd, magic);
-       strncat(passwd, sp, (u_int)sl);
-       strcat(passwd, "$");
+       buffer = stpcpy(buffer, magic);
+       buffer = stpncpy(buffer, salt, (u_int)sl);
+       *buffer++ = '$';
 
        MD5Final(final, &ctx);
 
@@ -118,7 +114,7 @@ crypt_md5(const char *pw, const char *sa
                        MD5Update(&ctx1, (const u_char *)final, MD5_SIZE);
 
                if(i % 3)
-                       MD5Update(&ctx1, (const u_char *)sp, (u_int)sl);
+                       MD5Update(&ctx1, (const u_char *)salt, (u_int)sl);
 
                if(i % 7)
                        MD5Update(&ctx1, (const u_char *)pw, strlen(pw));
@@ -130,24 +126,22 @@ crypt_md5(const char *pw, const char *sa
                MD5Final(final, &ctx1);
        }
 
-       p = passwd + strlen(passwd);
-
        l = (final[ 0]<<16) | (final[ 6]<<8) | final[12];
-       _crypt_to64(p, l, 4); p += 4;
+       _crypt_to64(buffer, l, 4); buffer += 4;
        l = (final[ 1]<<16) | (final[ 7]<<8) | final[13];
-       _crypt_to64(p, l, 4); p += 4;
+       _crypt_to64(buffer, l, 4); buffer += 4;
        l = (final[ 2]<<16) | (final[ 8]<<8) | final[14];
-       _crypt_to64(p, l, 4); p += 4;
+       _crypt_to64(buffer, l, 4); buffer += 4;
        l = (final[ 3]<<16) | (final[ 9]<<8) | final[15];
-       _crypt_to64(p, l, 4); p += 4;
+       _crypt_to64(buffer, l, 4); buffer += 4;
        l = (final[ 4]<<16) | (final[10]<<8) | final[ 5];
-       _crypt_to64(p, l, 4); p += 4;
+       _crypt_to64(buffer, l, 4); buffer += 4;
        l = final[11];
-       _crypt_to64(p, l, 2); p += 2;
-       *p = '\0';
+       _crypt_to64(buffer, l, 2); buffer += 2;
+       *buffer = '\0';
 
        /* Don't leave anything around in vm they could use. */
        memset(final, 0, sizeof(final));
 
-       return (passwd);
+       return (0);
 }

Modified: head/lib/libcrypt/crypt-nthash.c
==============================================================================
--- head/lib/libcrypt/crypt-nthash.c    Wed Aug 10 14:41:53 2016        
(r303919)
+++ head/lib/libcrypt/crypt-nthash.c    Wed Aug 10 15:16:28 2016        
(r303920)
@@ -46,16 +46,14 @@ __FBSDID("$FreeBSD$");
  */
 
 /* ARGSUSED */
-char *
-crypt_nthash(const char *pw, const char *salt __unused)
+int
+crypt_nthash(const char *pw, const char *salt __unused, char *buffer)
 {
        size_t unipwLen;
-       int i, j;
-       static char hexconvtab[] = "0123456789abcdef";
+       int i;
+       static const char hexconvtab[] = "0123456789abcdef";
        static const char *magic = "$3$";
-       static char passwd[120];
        u_int16_t unipw[128];
-       char final[MD4_SIZE*2 + 1];
        u_char hash[MD4_SIZE];
        const char *s;
        MD4_CTX ctx;
@@ -70,19 +68,14 @@ crypt_nthash(const char *pw, const char 
        MD4Init(&ctx);
        MD4Update(&ctx, (u_char *)unipw, unipwLen*sizeof(u_int16_t));
        MD4Final(hash, &ctx);  
-       
-       for (i = j = 0; i < MD4_SIZE; i++) {
-               final[j++] = hexconvtab[hash[i] >> 4];
-               final[j++] = hexconvtab[hash[i] & 15];
-       }
-       final[j] = '\0';
-
-       strcpy(passwd, magic);
-       strcat(passwd, "$");
-       strncat(passwd, final, MD4_SIZE*2);
 
-       /* Don't leave anything around in vm they could use. */
-       memset(final, 0, sizeof(final));
+       buffer = stpcpy(buffer, magic);
+       *buffer++ = '$';
+       for (i = 0; i < MD4_SIZE; i++) {
+               *buffer++ = hexconvtab[hash[i] >> 4];
+               *buffer++ = hexconvtab[hash[i] & 15];
+       }
+       *buffer = '\0';
 
-       return (passwd);
+       return (0);
 }

Modified: head/lib/libcrypt/crypt-sha256.c
==============================================================================
--- head/lib/libcrypt/crypt-sha256.c    Wed Aug 10 14:41:53 2016        
(r303919)
+++ head/lib/libcrypt/crypt-sha256.c    Wed Aug 10 15:16:28 2016        
(r303920)
@@ -59,11 +59,10 @@ static const char sha256_rounds_prefix[]
 /* Maximum number of rounds. */
 #define ROUNDS_MAX 999999999
 
-static char *
-crypt_sha256_r(const char *key, const char *salt, char *buffer, int buflen)
+int
+crypt_sha256(const char *key, const char *salt, char *buffer)
 {
        u_long srounds;
-       int n;
        uint8_t alt_result[32], temp_result[32];
        SHA256_CTX ctx, alt_ctx;
        size_t salt_len, key_len, cnt, rounds;
@@ -210,42 +209,27 @@ crypt_sha256_r(const char *key, const ch
 
        /* Now we can construct the result string. It consists of three
         * parts. */
-       cp = stpncpy(buffer, sha256_salt_prefix, MAX(0, buflen));
-       buflen -= sizeof(sha256_salt_prefix) - 1;
+       cp = stpcpy(buffer, sha256_salt_prefix);
 
-       if (rounds_custom) {
-               n = snprintf(cp, MAX(0, buflen), "%s%zu$",
-                        sha256_rounds_prefix, rounds);
+       if (rounds_custom)
+               cp += sprintf(cp, "%s%zu$", sha256_rounds_prefix, rounds);
 
-               cp += n;
-               buflen -= n;
-       }
+       cp = stpncpy(cp, salt, salt_len);
 
-       cp = stpncpy(cp, salt, MIN((size_t)MAX(0, buflen), salt_len));
-       buflen -= MIN((size_t)MAX(0, buflen), salt_len);
+       *cp++ = '$';
 
-       if (buflen > 0) {
-               *cp++ = '$';
-               --buflen;
-       }
-
-       b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4, 
&buflen, &cp);
-       b64_from_24bit(0, alt_result[31], alt_result[30], 3, &buflen, &cp);
-       if (buflen <= 0) {
-               errno = ERANGE;
-               buffer = NULL;
-       }
-       else
-               *cp = '\0';     /* Terminate the string. */
+       b64_from_24bit(alt_result[0], alt_result[10], alt_result[20], 4, &cp);
+       b64_from_24bit(alt_result[21], alt_result[1], alt_result[11], 4, &cp);
+       b64_from_24bit(alt_result[12], alt_result[22], alt_result[2], 4, &cp);
+       b64_from_24bit(alt_result[3], alt_result[13], alt_result[23], 4, &cp);
+       b64_from_24bit(alt_result[24], alt_result[4], alt_result[14], 4, &cp);
+       b64_from_24bit(alt_result[15], alt_result[25], alt_result[5], 4, &cp);
+       b64_from_24bit(alt_result[6], alt_result[16], alt_result[26], 4, &cp);
+       b64_from_24bit(alt_result[27], alt_result[7], alt_result[17], 4, &cp);
+       b64_from_24bit(alt_result[18], alt_result[28], alt_result[8], 4, &cp);
+       b64_from_24bit(alt_result[9], alt_result[19], alt_result[29], 4, &cp);
+       b64_from_24bit(0, alt_result[31], alt_result[30], 3, &cp);
+       *cp = '\0';     /* Terminate the string. */
 
        /* Clear the buffer for the intermediate result so that people
         * attaching to processes or reading core dumps cannot get any
@@ -263,37 +247,7 @@ crypt_sha256_r(const char *key, const ch
        if (copied_salt != NULL)
                memset(copied_salt, '\0', salt_len);
 
-       return buffer;
-}
-
-/* This entry point is equivalent to crypt(3). */
-char *
-crypt_sha256(const char *key, const char *salt)
-{
-       /* We don't want to have an arbitrary limit in the size of the
-        * password. We can compute an upper bound for the size of the
-        * result in advance and so we can prepare the buffer we pass to
-        * `crypt_sha256_r'. */
-       static char *buffer;
-       static int buflen;
-       int needed;
-       char *new_buffer;
-
-       needed = (sizeof(sha256_salt_prefix) - 1
-             + sizeof(sha256_rounds_prefix) + 9 + 1
-             + strlen(salt) + 1 + 43 + 1);
-
-       if (buflen < needed) {
-               new_buffer = (char *)realloc(buffer, needed);
-
-               if (new_buffer == NULL)
-                       return NULL;
-
-               buffer = new_buffer;
-               buflen = needed;
-       }
-
-       return crypt_sha256_r(key, salt, buffer, buflen);
+       return (0);
 }
 
 #ifdef TEST

Modified: head/lib/libcrypt/crypt-sha512.c
==============================================================================
--- head/lib/libcrypt/crypt-sha512.c    Wed Aug 10 14:41:53 2016        
(r303919)
+++ head/lib/libcrypt/crypt-sha512.c    Wed Aug 10 15:16:28 2016        
(r303920)
@@ -59,11 +59,10 @@ static const char sha512_rounds_prefix[]
 /* Maximum number of rounds. */
 #define ROUNDS_MAX 999999999
 
-static char *
-crypt_sha512_r(const char *key, const char *salt, char *buffer, int buflen)
+int
+crypt_sha512(const char *key, const char *salt, char *buffer)
 {
        u_long srounds;
-       int n;
        uint8_t alt_result[64], temp_result[64];
        SHA512_CTX ctx, alt_ctx;
        size_t salt_len, key_len, cnt, rounds;
@@ -210,54 +209,39 @@ crypt_sha512_r(const char *key, const ch
 
        /* Now we can construct the result string. It consists of three
         * parts. */
-       cp = stpncpy(buffer, sha512_salt_prefix, MAX(0, buflen));
-       buflen -= sizeof(sha512_salt_prefix) - 1;
+       cp = stpcpy(buffer, sha512_salt_prefix);
 
-       if (rounds_custom) {
-               n = snprintf(cp, MAX(0, buflen), "%s%zu$",
-                        sha512_rounds_prefix, rounds);
+       if (rounds_custom)
+               cp += sprintf(cp, "%s%zu$", sha512_rounds_prefix, rounds);
 
-               cp += n;
-               buflen -= n;
-       }
+       cp = stpncpy(cp, salt, salt_len);
 
-       cp = stpncpy(cp, salt, MIN((size_t)MAX(0, buflen), salt_len));
-       buflen -= MIN((size_t)MAX(0, buflen), salt_len);
+       *cp++ = '$';
 
-       if (buflen > 0) {
-               *cp++ = '$';
-               --buflen;
-       }
+       b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4, &cp);
+       b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4, &cp);
+       b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4, &cp);
+       b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4, &cp);
+       b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4, &cp);
+       b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4, &cp);
+       b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4, &cp);
+       b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4, &cp);
+       b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4, &cp);
+       b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4, &cp);
+       b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4, &cp);
+       b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4, &cp);
+       b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4, &cp);
+       b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4, &cp);
+       b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4, &cp);
+       b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4, &cp);
+       b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4, &cp);
+       b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4, &cp);
+       b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4, &cp);
+       b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4, &cp);
+       b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4, &cp);
+       b64_from_24bit(0, 0, alt_result[63], 2, &cp);
 
-       b64_from_24bit(alt_result[0], alt_result[21], alt_result[42], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[22], alt_result[43], alt_result[1], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[44], alt_result[2], alt_result[23], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[3], alt_result[24], alt_result[45], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[25], alt_result[46], alt_result[4], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[47], alt_result[5], alt_result[26], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[6], alt_result[27], alt_result[48], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[28], alt_result[49], alt_result[7], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[50], alt_result[8], alt_result[29], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[9], alt_result[30], alt_result[51], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[31], alt_result[52], alt_result[10], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[53], alt_result[11], alt_result[32], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[12], alt_result[33], alt_result[54], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[34], alt_result[55], alt_result[13], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[56], alt_result[14], alt_result[35], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[15], alt_result[36], alt_result[57], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[37], alt_result[58], alt_result[16], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[59], alt_result[17], alt_result[38], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[18], alt_result[39], alt_result[60], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[40], alt_result[61], alt_result[19], 4, 
&buflen, &cp);
-       b64_from_24bit(alt_result[62], alt_result[20], alt_result[41], 4, 
&buflen, &cp);
-       b64_from_24bit(0, 0, alt_result[63], 2, &buflen, &cp);
-
-       if (buflen <= 0) {
-               errno = ERANGE;
-               buffer = NULL;
-       }
-       else
-               *cp = '\0';     /* Terminate the string. */
+       *cp = '\0';     /* Terminate the string. */
 
        /* Clear the buffer for the intermediate result so that people
         * attaching to processes or reading core dumps cannot get any
@@ -275,37 +259,7 @@ crypt_sha512_r(const char *key, const ch
        if (copied_salt != NULL)
                memset(copied_salt, '\0', salt_len);
 
-       return buffer;
-}
-
-/* This entry point is equivalent to crypt(3). */
-char *
-crypt_sha512(const char *key, const char *salt)
-{
-       /* We don't want to have an arbitrary limit in the size of the
-        * password. We can compute an upper bound for the size of the
-        * result in advance and so we can prepare the buffer we pass to
-        * `crypt_sha512_r'. */
-       static char *buffer;
-       static int buflen;
-       int needed;
-       char *new_buffer;
-
-       needed = (sizeof(sha512_salt_prefix) - 1
-             + sizeof(sha512_rounds_prefix) + 9 + 1
-             + strlen(salt) + 1 + 86 + 1);
-
-       if (buflen < needed) {
-               new_buffer = (char *)realloc(buffer, needed);
-
-               if (new_buffer == NULL)
-                       return NULL;
-
-               buffer = new_buffer;
-               buflen = needed;
-       }
-
-       return crypt_sha512_r(key, salt, buffer, buflen);
+       return (0);
 }
 
 #ifdef TEST

Modified: head/lib/libcrypt/crypt.3
==============================================================================
--- head/lib/libcrypt/crypt.3   Wed Aug 10 14:41:53 2016        (r303919)
+++ head/lib/libcrypt/crypt.3   Wed Aug 10 15:16:28 2016        (r303920)
@@ -29,7 +29,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd March 9, 2014
+.Dd August 10, 2016
 .Dt CRYPT 3
 .Os
 .Sh NAME
@@ -41,6 +41,8 @@
 .In unistd.h
 .Ft char *
 .Fn crypt "const char *key" "const char *salt"
+.Ft char *
+.Fn crypt_r "const char *key" "const char *salt" "struct crypt_data *data"
 .Ft const char *
 .Fn crypt_get_format "void"
 .Ft int
@@ -246,10 +248,20 @@ The
 .Fn crypt_set_format
 function sets the default encoding format according to the supplied
 .Fa string .
+.Pp
+The
+.Fn crypt_r
+function behaves identically to
+.Fn crypt ,
+except that the resulting string is stored in
+.Fa data ,
+making it thread-safe.
 .Sh RETURN VALUES
 The
 .Fn crypt
-function returns a pointer to the encrypted value on success, and NULL on
+and
+.Fn crypt_r
+functions return a pointer to the encrypted value on success, and NULL on
 failure.
 Note: this is not a standard behaviour, AT&T
 .Fn crypt
@@ -280,6 +292,11 @@ section of the code (FreeSec 1.0) was de
 States of America as an unencumbered replacement for the U.S.-only
 .Nx
 libcrypt encryption library.
+.Pp
+The
+.Fn crypt_r
+function was added in
+.Fx 12.0 .
 .Sh AUTHORS
 .An -nosplit
 Originally written by

Modified: head/lib/libcrypt/crypt.c
==============================================================================
--- head/lib/libcrypt/crypt.c   Wed Aug 10 14:41:53 2016        (r303919)
+++ head/lib/libcrypt/crypt.c   Wed Aug 10 15:16:28 2016        (r303920)
@@ -46,9 +46,9 @@ __FBSDID("$FreeBSD$");
  * and it needs to be the default for backward compatibility.
  */
 static const struct crypt_format {
-       const char *const name;
-       char *(*const func)(const char *, const char *);
-       const char *const magic;
+       const char *name;
+       int (*func)(const char *, const char *, char *);
+       const char *magic;
 } crypt_formats[] = {
        { "md5",        crypt_md5,              "$1$"   },
 #ifdef HAS_BLOWFISH
@@ -104,20 +104,37 @@ crypt_set_format(const char *format)
  * otherwise, the currently selected format is used.
  */
 char *
-crypt(const char *passwd, const char *salt)
+crypt_r(const char *passwd, const char *salt, struct crypt_data *data)
 {
        const struct crypt_format *cf;
+       int (*func)(const char *, const char *, char *);
 #ifdef HAS_DES
        int len;
 #endif
 
        for (cf = crypt_formats; cf->name != NULL; ++cf)
-               if (cf->magic != NULL && strstr(salt, cf->magic) == salt)
-                       return (cf->func(passwd, salt));
+               if (cf->magic != NULL && strstr(salt, cf->magic) == salt) {
+                       func = cf->func;
+                       goto match;
+               }
 #ifdef HAS_DES
        len = strlen(salt);
-       if ((len == 13 || len == 2) && strspn(salt, DES_SALT_ALPHABET) == len)
-               return (crypt_des(passwd, salt));
+       if ((len == 13 || len == 2) && strspn(salt, DES_SALT_ALPHABET) == len) {
+               func = crypt_des;
+               goto match;
+       }
 #endif
-       return (crypt_format->func(passwd, salt));
+       func = crypt_format->func;
+match:
+       if (func(passwd, salt, data->__buf) != 0)
+               return (NULL);
+       return (data->__buf);
+}
+
+char *
+crypt(const char *passwd, const char *salt)
+{
+       static struct crypt_data data;
+
+       return (crypt_r(passwd, salt, &data));
 }

Modified: head/lib/libcrypt/crypt.h
==============================================================================
--- head/lib/libcrypt/crypt.h   Wed Aug 10 14:41:53 2016        (r303919)
+++ head/lib/libcrypt/crypt.h   Wed Aug 10 15:16:28 2016        (r303920)
@@ -32,12 +32,12 @@
 #define MD4_SIZE 16
 #define MD5_SIZE 16
 
-char *crypt_des(const char *pw, const char *salt);
-char *crypt_md5(const char *pw, const char *salt);
-char *crypt_nthash(const char *pw, const char *salt);
-char *crypt_blowfish(const char *pw, const char *salt);
-char *crypt_sha256 (const char *pw, const char *salt);
-char *crypt_sha512 (const char *pw, const char *salt);
+int crypt_des(const char *pw, const char *salt, char *buf);
+int crypt_md5(const char *pw, const char *salt, char *buf);
+int crypt_nthash(const char *pw, const char *salt, char *buf);
+int crypt_blowfish(const char *pw, const char *salt, char *buf);
+int crypt_sha256 (const char *pw, const char *salt, char *buf);
+int crypt_sha512 (const char *pw, const char *salt, char *buf);
 
 extern void _crypt_to64(char *s, u_long v, int n);
-extern void b64_from_24bit(uint8_t B2, uint8_t B1, uint8_t B0, int n, int 
*buflen, char **cp);
+extern void b64_from_24bit(uint8_t B2, uint8_t B1, uint8_t B0, int n, char 
**cp);

Modified: head/lib/libcrypt/misc.c
==============================================================================
--- head/lib/libcrypt/misc.c    Wed Aug 10 14:41:53 2016        (r303919)
+++ head/lib/libcrypt/misc.c    Wed Aug 10 15:16:28 2016        (r303920)
@@ -47,7 +47,7 @@ _crypt_to64(char *s, u_long v, int n)
 }
 
 void
-b64_from_24bit(uint8_t B2, uint8_t B1, uint8_t B0, int n, int *buflen, char 
**cp)
+b64_from_24bit(uint8_t B2, uint8_t B1, uint8_t B0, int n, char **cp)
 {
        uint32_t w;
        int i;
@@ -56,8 +56,6 @@ b64_from_24bit(uint8_t B2, uint8_t B1, u
        for (i = 0; i < n; i++) {
                **cp = itoa64[w&0x3f];
                (*cp)++;
-               if ((*buflen)-- < 0)
-                       break;
                w >>= 6;
        }
 }

Modified: head/secure/lib/libcrypt/crypt-blowfish.c
==============================================================================
--- head/secure/lib/libcrypt/crypt-blowfish.c   Wed Aug 10 14:41:53 2016        
(r303919)
+++ head/secure/lib/libcrypt/crypt-blowfish.c   Wed Aug 10 15:16:28 2016        
(r303920)
@@ -75,8 +75,6 @@ __FBSDID("$FreeBSD$");
 static void encode_base64(u_int8_t *, u_int8_t *, u_int16_t);
 static void decode_base64(u_int8_t *, u_int16_t, const u_int8_t *);
 
-static char    encrypted[_PASSWORD_LEN];
-
 const static u_int8_t Base64Code[] =
 "./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
 
@@ -135,8 +133,8 @@ decode_base64(u_int8_t *buffer, u_int16_
 /* We handle $Vers$log2(NumRounds)$salt+passwd$
    i.e. $2$04$iwouldntknowwhattosayetKdJ6iFtacBqJdKe6aW7ou */
 
-char   *
-crypt_blowfish(const char *key, const char *salt)
+int
+crypt_blowfish(const char *key, const char *salt, char *buffer)
 {
        blf_ctx state;
        u_int32_t rounds, i, k;
@@ -157,10 +155,8 @@ crypt_blowfish(const char *key, const ch
                /* Discard "$" identifier */
                salt++;
 
-               if (*salt > BCRYPT_VERSION) {
-                       /* How do I handle errors ? Return NULL */
-                       return NULL;
-               }
+               if (*salt > BCRYPT_VERSION)
+                       return (-1);
 
                /* Check for minor versions */
                if (salt[1] != '$') {
@@ -174,7 +170,7 @@ crypt_blowfish(const char *key, const ch
                                 salt++;
                                 break;
                         default:
-                                return NULL;
+                                return (-1);
                         }
                } else
                         minr = 0;
@@ -184,15 +180,15 @@ crypt_blowfish(const char *key, const ch
 
                if (salt[2] != '$')
                        /* Out of sync with passwd entry */
-                       return NULL;
+                       return (-1);
 
                memcpy(arounds, salt, sizeof(arounds));
                if (arounds[sizeof(arounds) - 1] != '$')
-                       return NULL;
+                       return (-1);
                arounds[sizeof(arounds) - 1] = 0;
                logr = strtonum(arounds, BCRYPT_MINLOGROUNDS, 31, NULL);
                if (logr == 0)
-                       return NULL;
+                       return (-1);
                /* Computer power doesn't increase linearly, 2^x should be fine 
*/
                rounds = 1U << logr;
 
@@ -201,7 +197,7 @@ crypt_blowfish(const char *key, const ch
        }
 
        if (strlen(salt) * 3 / 4 < BCRYPT_MAXSALT)
-               return NULL;
+               return (-1);
 
        /* We dont want the base64 salt but the raw data */
        decode_base64(csalt, BCRYPT_MAXSALT, (const u_int8_t *) salt);
@@ -248,23 +244,23 @@ crypt_blowfish(const char *key, const ch
        }
 
 
-       i = 0;
-       encrypted[i++] = '$';
-       encrypted[i++] = BCRYPT_VERSION;
+       *buffer++ = '$';
+       *buffer++ = BCRYPT_VERSION;
        if (minr)
-               encrypted[i++] = minr;
-       encrypted[i++] = '$';
+               *buffer++ = minr;
+       *buffer++ = '$';
 
-       snprintf(encrypted + i, 4, "%2.2u$", logr);
+       snprintf(buffer, 4, "%2.2u$", logr);
+       buffer += 3;
 
-       encode_base64((u_int8_t *) encrypted + i + 3, csalt, BCRYPT_MAXSALT);
-       encode_base64((u_int8_t *) encrypted + strlen(encrypted), ciphertext,
-           4 * BCRYPT_BLOCKS - 1);
+       encode_base64((u_int8_t *)buffer, csalt, BCRYPT_MAXSALT);
+       buffer += strlen(buffer);
+       encode_base64((u_int8_t *)buffer, ciphertext, 4 * BCRYPT_BLOCKS - 1);
        memset(&state, 0, sizeof(state));
        memset(ciphertext, 0, sizeof(ciphertext));
        memset(csalt, 0, sizeof(csalt));
        memset(cdata, 0, sizeof(cdata));
-       return encrypted;
+       return (0);
 }
 
 static void

Modified: head/secure/lib/libcrypt/crypt-des.c
==============================================================================
--- head/secure/lib/libcrypt/crypt-des.c        Wed Aug 10 14:41:53 2016        
(r303919)
+++ head/secure/lib/libcrypt/crypt-des.c        Wed Aug 10 15:16:28 2016        
(r303920)
@@ -588,13 +588,12 @@ des_cipher(const char *in, char *out, u_
        return(retval);
 }
 
-char *
-crypt_des(const char *key, const char *setting)
+int
+crypt_des(const char *key, const char *setting, char *buffer)
 {
        int             i;
        u_int32_t       count, salt, l, r0, r1, keybuf[2];
-       u_char          *p, *q;
-       static char     output[21];
+       u_char          *q;
 
        if (!des_initialised)
                des_init();
@@ -610,7 +609,7 @@ crypt_des(const char *key, const char *s
                        key++;
        }
        if (des_setkey((char *)keybuf))
-               return(NULL);
+               return (-1);
 
        if (*setting == _PASSWORD_EFMT1) {
                /*
@@ -629,7 +628,7 @@ crypt_des(const char *key, const char *s
                         * Encrypt the key with itself.
                         */
                        if (des_cipher((char *)keybuf, (char *)keybuf, 0L, 1))
-                               return(NULL);
+                               return (-1);
                        /*
                         * And XOR with the next 8 characters of the key.
                         */
@@ -638,19 +637,9 @@ crypt_des(const char *key, const char *s
                                *q++ ^= *key++ << 1;
 
                        if (des_setkey((char *)keybuf))
-                               return(NULL);
+                               return (-1);
                }
-               strncpy(output, setting, 9);
-
-               /*
-                * Double check that we weren't given a short setting.
-                * If we were, the above code will probably have created
-                * wierd values for count and salt, but we don't really care.
-                * Just make sure the output string doesn't have an extra
-                * NUL in it.
-                */
-               output[9] = '\0';
-               p = (u_char *)output + strlen(output);
+               buffer = stpncpy(buffer, setting, 9);
        } else {
                /*
                 * "old"-style:
@@ -662,43 +651,41 @@ crypt_des(const char *key, const char *s
                salt = (ascii_to_bin(setting[1]) << 6)
                     |  ascii_to_bin(setting[0]);
 
-               output[0] = setting[0];
+               *buffer++ = setting[0];
                /*
                 * If the encrypted password that the salt was extracted from
                 * is only 1 character long, the salt will be corrupted.  We
                 * need to ensure that the output string doesn't have an extra
                 * NUL in it!
                 */
-               output[1] = setting[1] ? setting[1] : output[0];
-
-               p = (u_char *)output + 2;
+               *buffer++ = setting[1] ? setting[1] : setting[0];
        }
        setup_salt(salt);
        /*
         * Do it.
         */
        if (do_des(0L, 0L, &r0, &r1, (int)count))
-               return(NULL);
+               return (-1);
        /*
         * Now encode the result...
         */
        l = (r0 >> 8);
-       *p++ = ascii64[(l >> 18) & 0x3f];
-       *p++ = ascii64[(l >> 12) & 0x3f];
-       *p++ = ascii64[(l >> 6) & 0x3f];
-       *p++ = ascii64[l & 0x3f];
+       *buffer++ = ascii64[(l >> 18) & 0x3f];
+       *buffer++ = ascii64[(l >> 12) & 0x3f];
+       *buffer++ = ascii64[(l >> 6) & 0x3f];
+       *buffer++ = ascii64[l & 0x3f];
 
        l = (r0 << 16) | ((r1 >> 16) & 0xffff);
-       *p++ = ascii64[(l >> 18) & 0x3f];
-       *p++ = ascii64[(l >> 12) & 0x3f];
-       *p++ = ascii64[(l >> 6) & 0x3f];
-       *p++ = ascii64[l & 0x3f];
+       *buffer++ = ascii64[(l >> 18) & 0x3f];
+       *buffer++ = ascii64[(l >> 12) & 0x3f];
+       *buffer++ = ascii64[(l >> 6) & 0x3f];
+       *buffer++ = ascii64[l & 0x3f];
 
        l = r1 << 2;
-       *p++ = ascii64[(l >> 12) & 0x3f];
-       *p++ = ascii64[(l >> 6) & 0x3f];
-       *p++ = ascii64[l & 0x3f];
-       *p = 0;
+       *buffer++ = ascii64[(l >> 12) & 0x3f];
+       *buffer++ = ascii64[(l >> 6) & 0x3f];
+       *buffer++ = ascii64[l & 0x3f];
+       *buffer = '\0';
 
-       return(output);
+       return (0);
 }
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to