10cd13cbfSwyllys /*
20cd13cbfSwyllys * CDDL HEADER START
30cd13cbfSwyllys *
40cd13cbfSwyllys * The contents of this file are subject to the terms of the
50cd13cbfSwyllys * Common Development and Distribution License (the "License").
60cd13cbfSwyllys * You may not use this file except in compliance with the License.
70cd13cbfSwyllys *
80cd13cbfSwyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90cd13cbfSwyllys * or http://www.opensolaris.org/os/licensing.
100cd13cbfSwyllys * See the License for the specific language governing permissions
110cd13cbfSwyllys * and limitations under the License.
120cd13cbfSwyllys *
130cd13cbfSwyllys * When distributing Covered Code, include this CDDL HEADER in each
140cd13cbfSwyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150cd13cbfSwyllys * If applicable, add the following below this CDDL HEADER, with the
160cd13cbfSwyllys * fields enclosed by brackets "[]" replaced with your own identifying
170cd13cbfSwyllys * information: Portions Copyright [yyyy] [name of copyright owner]
180cd13cbfSwyllys *
190cd13cbfSwyllys * CDDL HEADER END
200cd13cbfSwyllys */
210cd13cbfSwyllys /*
220ca46ac5SWyllys Ingersoll * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230cd13cbfSwyllys * Use is subject to license terms.
240cd13cbfSwyllys */
250cd13cbfSwyllys
260cd13cbfSwyllys /*
270cd13cbfSwyllys * Portions of this code from crypt_bsdmd5.so (bsdmd5.c) :
280cd13cbfSwyllys * ----------------------------------------------------------------------------
290cd13cbfSwyllys * "THE BEER-WARE LICENSE" (Revision 42):
300cd13cbfSwyllys * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you
310cd13cbfSwyllys * can do whatever you want with this stuff. If we meet some day, and you think
320cd13cbfSwyllys * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
330cd13cbfSwyllys * ----------------------------------------------------------------------------
340cd13cbfSwyllys *
350cd13cbfSwyllys * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $
360cd13cbfSwyllys *
370cd13cbfSwyllys */
380cd13cbfSwyllys
390cd13cbfSwyllys /*
400cd13cbfSwyllys * Implements the specification from:
410cd13cbfSwyllys *
420cd13cbfSwyllys * From http://people.redhat.com/drepper/SHA-crypt.txt
430cd13cbfSwyllys *
440cd13cbfSwyllys * Portions of the code taken from inspired by or verified against the
450cd13cbfSwyllys * source in the above document which is licensed as:
460cd13cbfSwyllys *
470cd13cbfSwyllys * "Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>."
480cd13cbfSwyllys */
490cd13cbfSwyllys
500cd13cbfSwyllys
510cd13cbfSwyllys #include <sys/types.h>
520cd13cbfSwyllys #include <sys/stat.h>
530cd13cbfSwyllys #include <sys/sysmacros.h>
540cd13cbfSwyllys #include <fcntl.h>
550cd13cbfSwyllys #include <unistd.h>
560cd13cbfSwyllys #include <string.h>
570cd13cbfSwyllys #include <stdio.h>
580cd13cbfSwyllys #include <errno.h>
590cd13cbfSwyllys #include <stdlib.h>
600cd13cbfSwyllys #include <alloca.h>
610cd13cbfSwyllys
620cd13cbfSwyllys #include <sha2.h>
630cd13cbfSwyllys #include <crypt.h>
640cd13cbfSwyllys
650cd13cbfSwyllys #define MAX_SALT_LEN 16
660cd13cbfSwyllys #define ROUNDS_DEFAULT 5000
670cd13cbfSwyllys #define ROUNDS_MIN 1000
680cd13cbfSwyllys #define ROUNDS_MAX 999999999
690cd13cbfSwyllys
700cd13cbfSwyllys #ifdef CRYPT_SHA256
710cd13cbfSwyllys
720cd13cbfSwyllys #define DIGEST_CTX SHA256_CTX
730cd13cbfSwyllys #define DIGESTInit SHA256Init
740cd13cbfSwyllys #define DIGESTUpdate SHA256Update
750cd13cbfSwyllys #define DIGESTFinal SHA256Final
760cd13cbfSwyllys #define DIGEST_LEN SHA256_DIGEST_LENGTH
770cd13cbfSwyllys #define MIXCHARS 32
780ca46ac5SWyllys Ingersoll static const char crypt_alg_magic[] = "$5";
790cd13cbfSwyllys
800cd13cbfSwyllys #elif CRYPT_SHA512
810cd13cbfSwyllys
820cd13cbfSwyllys #define DIGEST_CTX SHA512_CTX
830cd13cbfSwyllys #define DIGESTInit SHA512Init
840cd13cbfSwyllys #define DIGESTUpdate SHA512Update
850cd13cbfSwyllys #define DIGESTFinal SHA512Final
860cd13cbfSwyllys #define DIGEST_LEN SHA512_DIGEST_LENGTH
870cd13cbfSwyllys #define MIXCHARS 64
880ca46ac5SWyllys Ingersoll static const char crypt_alg_magic[] = "$6";
890cd13cbfSwyllys
900cd13cbfSwyllys #else
910cd13cbfSwyllys #error "One of CRYPT_256 or CRYPT_512 must be defined"
920cd13cbfSwyllys #endif
930cd13cbfSwyllys
940cd13cbfSwyllys static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1;
950cd13cbfSwyllys
960cd13cbfSwyllys
970cd13cbfSwyllys static uchar_t b64t[] = /* 0 ... 63 => ascii - 64 */
980cd13cbfSwyllys "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
990cd13cbfSwyllys
1000cd13cbfSwyllys #define b64_from_24bit(B2, B1, B0, N) \
1010cd13cbfSwyllys { \
1020cd13cbfSwyllys uint_t w = ((B2) << 16) | ((B1) << 8) | (B0); \
1030cd13cbfSwyllys int n = (N); \
1040cd13cbfSwyllys while (--n >= 0 && ctbufflen > 0) { \
1050cd13cbfSwyllys *p++ = b64t[w & 0x3f]; \
1060cd13cbfSwyllys w >>= 6; \
1070cd13cbfSwyllys ctbufflen--; \
1080cd13cbfSwyllys } \
1090cd13cbfSwyllys }
1100cd13cbfSwyllys
1110cd13cbfSwyllys static void
to64(char * s,uint64_t v,int n)1120cd13cbfSwyllys to64(char *s, uint64_t v, int n)
1130cd13cbfSwyllys {
1140cd13cbfSwyllys while (--n >= 0) {
115*1dbc1fedSDan OpenSolaris Anderson *s++ = b64t[v & 0x3f];
1160cd13cbfSwyllys v >>= 6;
1170cd13cbfSwyllys }
1180cd13cbfSwyllys }
1190cd13cbfSwyllys
1200ca46ac5SWyllys Ingersoll #define ROUNDS "rounds="
1210ca46ac5SWyllys Ingersoll #define ROUNDSLEN (sizeof (ROUNDS) - 1)
1220ca46ac5SWyllys Ingersoll
1230ca46ac5SWyllys Ingersoll /*
1240ca46ac5SWyllys Ingersoll * get the integer value after rounds= where ever it occurs in the string.
1250ca46ac5SWyllys Ingersoll * if the last char after the int is a , or $ that is fine anything else is an
1260ca46ac5SWyllys Ingersoll * error.
1270ca46ac5SWyllys Ingersoll */
1280ca46ac5SWyllys Ingersoll static uint32_t
getrounds(const char * s)1290ca46ac5SWyllys Ingersoll getrounds(const char *s)
1300ca46ac5SWyllys Ingersoll {
1310ca46ac5SWyllys Ingersoll char *r, *p, *e;
1320ca46ac5SWyllys Ingersoll long val;
1330ca46ac5SWyllys Ingersoll
1340ca46ac5SWyllys Ingersoll if (s == NULL)
1350ca46ac5SWyllys Ingersoll return (0);
1360ca46ac5SWyllys Ingersoll
1370ca46ac5SWyllys Ingersoll if ((r = strstr(s, ROUNDS)) == NULL) {
1380ca46ac5SWyllys Ingersoll return (0);
1390ca46ac5SWyllys Ingersoll }
1400ca46ac5SWyllys Ingersoll
1410ca46ac5SWyllys Ingersoll if (strncmp(r, ROUNDS, ROUNDSLEN) != 0) {
1420ca46ac5SWyllys Ingersoll return (0);
1430ca46ac5SWyllys Ingersoll }
1440ca46ac5SWyllys Ingersoll
1450ca46ac5SWyllys Ingersoll p = r + ROUNDSLEN;
1460ca46ac5SWyllys Ingersoll errno = 0;
1470ca46ac5SWyllys Ingersoll val = strtol(p, &e, 10);
1480ca46ac5SWyllys Ingersoll /*
149*1dbc1fedSDan OpenSolaris Anderson * An error occurred or there is non-numeric stuff at the end
1500ca46ac5SWyllys Ingersoll * which isn't one of the crypt(3c) special chars ',' or '$'
1510ca46ac5SWyllys Ingersoll */
1520ca46ac5SWyllys Ingersoll if (errno != 0 || val < 0 ||
1530ca46ac5SWyllys Ingersoll !(*e == '\0' || *e == ',' || *e == '$')) {
1540ca46ac5SWyllys Ingersoll return (0);
1550ca46ac5SWyllys Ingersoll }
1560ca46ac5SWyllys Ingersoll
1570ca46ac5SWyllys Ingersoll return ((uint32_t)val);
1580ca46ac5SWyllys Ingersoll }
1590ca46ac5SWyllys Ingersoll
1600ca46ac5SWyllys Ingersoll
161*1dbc1fedSDan OpenSolaris Anderson /* ARGSUSED4 */
1620cd13cbfSwyllys char *
crypt_genhash_impl(char * ctbuffer,size_t ctbufflen,const char * plaintext,const char * switchsalt,const char ** params)1630cd13cbfSwyllys crypt_genhash_impl(char *ctbuffer,
1640cd13cbfSwyllys size_t ctbufflen,
1650cd13cbfSwyllys const char *plaintext,
1660cd13cbfSwyllys const char *switchsalt,
1670cd13cbfSwyllys const char **params)
1680cd13cbfSwyllys {
1690cd13cbfSwyllys int salt_len, plaintext_len, i;
1700cd13cbfSwyllys char *salt;
1710cd13cbfSwyllys uchar_t A[DIGEST_LEN];
1720cd13cbfSwyllys uchar_t B[DIGEST_LEN];
1730cd13cbfSwyllys uchar_t DP[DIGEST_LEN];
1740cd13cbfSwyllys uchar_t DS[DIGEST_LEN];
1750cd13cbfSwyllys DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS;
1760cd13cbfSwyllys int rounds = ROUNDS_DEFAULT;
1770ca46ac5SWyllys Ingersoll int srounds = 0;
1780cd13cbfSwyllys boolean_t custom_rounds = B_FALSE;
1790cd13cbfSwyllys char *p;
1800cd13cbfSwyllys char *P, *Pp;
1810cd13cbfSwyllys char *S, *Sp;
1820cd13cbfSwyllys
1830cd13cbfSwyllys /* Refine the salt */
1840cd13cbfSwyllys salt = (char *)switchsalt;
1850cd13cbfSwyllys
1860cd13cbfSwyllys /* skip our magic string */
1870cd13cbfSwyllys if (strncmp((char *)salt, crypt_alg_magic, crypt_alg_magic_len) == 0) {
1880ca46ac5SWyllys Ingersoll salt += crypt_alg_magic_len + 1;
1890cd13cbfSwyllys }
1900cd13cbfSwyllys
1910ca46ac5SWyllys Ingersoll srounds = getrounds(salt);
1920ca46ac5SWyllys Ingersoll if (srounds != 0) {
1930ca46ac5SWyllys Ingersoll rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX));
1940ca46ac5SWyllys Ingersoll custom_rounds = B_TRUE;
1950ca46ac5SWyllys Ingersoll p = strchr(salt, '$');
1960ca46ac5SWyllys Ingersoll if (p != NULL)
1970ca46ac5SWyllys Ingersoll salt = p + 1;
1980cd13cbfSwyllys }
1990cd13cbfSwyllys
2000cd13cbfSwyllys salt_len = MIN(strcspn(salt, "$"), MAX_SALT_LEN);
2010cd13cbfSwyllys plaintext_len = strlen(plaintext);
2020cd13cbfSwyllys
2030cd13cbfSwyllys /* 1. */
2040cd13cbfSwyllys DIGESTInit(&ctxA);
2050cd13cbfSwyllys
2060cd13cbfSwyllys /* 2. The password first, since that is what is most unknown */
2070cd13cbfSwyllys DIGESTUpdate(&ctxA, plaintext, plaintext_len);
2080cd13cbfSwyllys
2090cd13cbfSwyllys /* 3. Then the raw salt */
2100cd13cbfSwyllys DIGESTUpdate(&ctxA, salt, salt_len);
2110cd13cbfSwyllys
2120cd13cbfSwyllys /* 4. - 8. */
2130cd13cbfSwyllys DIGESTInit(&ctxB);
2140cd13cbfSwyllys DIGESTUpdate(&ctxB, plaintext, plaintext_len);
2150cd13cbfSwyllys DIGESTUpdate(&ctxB, salt, salt_len);
2160cd13cbfSwyllys DIGESTUpdate(&ctxB, plaintext, plaintext_len);
2170cd13cbfSwyllys DIGESTFinal(B, &ctxB);
2180cd13cbfSwyllys
2190cd13cbfSwyllys /* 9. - 10. */
2200cd13cbfSwyllys for (i = plaintext_len; i > MIXCHARS; i -= MIXCHARS)
2210cd13cbfSwyllys DIGESTUpdate(&ctxA, B, MIXCHARS);
2220cd13cbfSwyllys DIGESTUpdate(&ctxA, B, i);
2230cd13cbfSwyllys
2240cd13cbfSwyllys /* 11. */
2250cd13cbfSwyllys for (i = plaintext_len; i > 0; i >>= 1) {
2260cd13cbfSwyllys if ((i & 1) != 0) {
2270cd13cbfSwyllys DIGESTUpdate(&ctxA, B, MIXCHARS);
2280cd13cbfSwyllys } else {
2290cd13cbfSwyllys DIGESTUpdate(&ctxA, plaintext, plaintext_len);
2300cd13cbfSwyllys }
2310cd13cbfSwyllys }
2320cd13cbfSwyllys
2330cd13cbfSwyllys /* 12. */
2340cd13cbfSwyllys DIGESTFinal(A, &ctxA);
2350cd13cbfSwyllys
2360cd13cbfSwyllys /* 13. - 15. */
2370cd13cbfSwyllys DIGESTInit(&ctxDP);
2380cd13cbfSwyllys for (i = 0; i < plaintext_len; i++)
2390cd13cbfSwyllys DIGESTUpdate(&ctxDP, plaintext, plaintext_len);
2400cd13cbfSwyllys DIGESTFinal(DP, &ctxDP);
2410cd13cbfSwyllys
2420cd13cbfSwyllys /* 16. */
2430cd13cbfSwyllys Pp = P = alloca(plaintext_len);
2440cd13cbfSwyllys for (i = plaintext_len; i >= MIXCHARS; i -= MIXCHARS) {
2450cd13cbfSwyllys Pp = (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS;
2460cd13cbfSwyllys }
247*1dbc1fedSDan OpenSolaris Anderson (void) memcpy(Pp, DP, i);
2480cd13cbfSwyllys
2490cd13cbfSwyllys /* 17. - 19. */
2500cd13cbfSwyllys DIGESTInit(&ctxDS);
2510cd13cbfSwyllys for (i = 0; i < 16 + (uint8_t)A[0]; i++)
2520cd13cbfSwyllys DIGESTUpdate(&ctxDS, salt, salt_len);
2530cd13cbfSwyllys DIGESTFinal(DS, &ctxDS);
2540cd13cbfSwyllys
2550cd13cbfSwyllys /* 20. */
2560cd13cbfSwyllys Sp = S = alloca(salt_len);
2570cd13cbfSwyllys for (i = salt_len; i >= MIXCHARS; i -= MIXCHARS) {
2580cd13cbfSwyllys Sp = (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS;
2590cd13cbfSwyllys }
260*1dbc1fedSDan OpenSolaris Anderson (void) memcpy(Sp, DS, i);
2610cd13cbfSwyllys
2620cd13cbfSwyllys /* 21. */
2630cd13cbfSwyllys for (i = 0; i < rounds; i++) {
2640cd13cbfSwyllys DIGESTInit(&ctxC);
2650cd13cbfSwyllys
2660cd13cbfSwyllys if ((i & 1) != 0) {
2670cd13cbfSwyllys DIGESTUpdate(&ctxC, P, plaintext_len);
2680cd13cbfSwyllys } else {
2690cd13cbfSwyllys if (i == 0)
2700cd13cbfSwyllys DIGESTUpdate(&ctxC, A, MIXCHARS);
2710cd13cbfSwyllys else
2720cd13cbfSwyllys DIGESTUpdate(&ctxC, DP, MIXCHARS);
2730cd13cbfSwyllys }
2740cd13cbfSwyllys
2750cd13cbfSwyllys if (i % 3 != 0) {
2760cd13cbfSwyllys DIGESTUpdate(&ctxC, S, salt_len);
2770cd13cbfSwyllys }
2780cd13cbfSwyllys
2790cd13cbfSwyllys if (i % 7 != 0) {
2800cd13cbfSwyllys DIGESTUpdate(&ctxC, P, plaintext_len);
2810cd13cbfSwyllys }
2820cd13cbfSwyllys
2830cd13cbfSwyllys if ((i & 1) != 0) {
2840cd13cbfSwyllys if (i == 0)
2850cd13cbfSwyllys DIGESTUpdate(&ctxC, A, MIXCHARS);
2860cd13cbfSwyllys else
2870cd13cbfSwyllys DIGESTUpdate(&ctxC, DP, MIXCHARS);
2880cd13cbfSwyllys } else {
2890cd13cbfSwyllys DIGESTUpdate(&ctxC, P, plaintext_len);
2900cd13cbfSwyllys }
2910cd13cbfSwyllys DIGESTFinal(DP, &ctxC);
2920cd13cbfSwyllys }
2930cd13cbfSwyllys
2940cd13cbfSwyllys /* 22. Now make the output string */
2950cd13cbfSwyllys if (custom_rounds) {
2960cd13cbfSwyllys (void) snprintf(ctbuffer, ctbufflen,
2970ca46ac5SWyllys Ingersoll "%s$rounds=%zu$", crypt_alg_magic, rounds);
2980ca46ac5SWyllys Ingersoll } else {
2990ca46ac5SWyllys Ingersoll (void) snprintf(ctbuffer, ctbufflen,
3000ca46ac5SWyllys Ingersoll "%s$", crypt_alg_magic);
3010cd13cbfSwyllys }
30220ed34ccSWyllys Ingersoll (void) strncat(ctbuffer, (const char *)salt, salt_len);
3030cd13cbfSwyllys (void) strlcat(ctbuffer, "$", ctbufflen);
3040ca46ac5SWyllys Ingersoll
3050cd13cbfSwyllys p = ctbuffer + strlen(ctbuffer);
3060cd13cbfSwyllys ctbufflen -= strlen(ctbuffer);
3070cd13cbfSwyllys
3080cd13cbfSwyllys #ifdef CRYPT_SHA256
3090cd13cbfSwyllys b64_from_24bit(DP[ 0], DP[10], DP[20], 4);
3100cd13cbfSwyllys b64_from_24bit(DP[21], DP[ 1], DP[11], 4);
3110cd13cbfSwyllys b64_from_24bit(DP[12], DP[22], DP[ 2], 4);
3120cd13cbfSwyllys b64_from_24bit(DP[ 3], DP[13], DP[23], 4);
3130cd13cbfSwyllys b64_from_24bit(DP[24], DP[ 4], DP[14], 4);
3140cd13cbfSwyllys b64_from_24bit(DP[15], DP[25], DP[ 5], 4);
3150cd13cbfSwyllys b64_from_24bit(DP[ 6], DP[16], DP[26], 4);
3160cd13cbfSwyllys b64_from_24bit(DP[27], DP[ 7], DP[17], 4);
3170cd13cbfSwyllys b64_from_24bit(DP[18], DP[28], DP[ 8], 4);
3180cd13cbfSwyllys b64_from_24bit(DP[ 9], DP[19], DP[29], 4);
3190cd13cbfSwyllys b64_from_24bit(0, DP[31], DP[30], 3);
3200cd13cbfSwyllys #elif CRYPT_SHA512
3210cd13cbfSwyllys b64_from_24bit(DP[ 0], DP[21], DP[42], 4);
3220cd13cbfSwyllys b64_from_24bit(DP[22], DP[43], DP[ 1], 4);
3230cd13cbfSwyllys b64_from_24bit(DP[44], DP[ 2], DP[23], 4);
3240cd13cbfSwyllys b64_from_24bit(DP[ 3], DP[24], DP[45], 4);
3250cd13cbfSwyllys b64_from_24bit(DP[25], DP[46], DP[ 4], 4);
3260cd13cbfSwyllys b64_from_24bit(DP[47], DP[ 5], DP[26], 4);
3270cd13cbfSwyllys b64_from_24bit(DP[ 6], DP[27], DP[48], 4);
3280cd13cbfSwyllys b64_from_24bit(DP[28], DP[49], DP[ 7], 4);
3290cd13cbfSwyllys b64_from_24bit(DP[50], DP[ 8], DP[29], 4);
3300cd13cbfSwyllys b64_from_24bit(DP[ 9], DP[30], DP[51], 4);
3310cd13cbfSwyllys b64_from_24bit(DP[31], DP[52], DP[10], 4);
3320cd13cbfSwyllys b64_from_24bit(DP[53], DP[11], DP[32], 4);
3330cd13cbfSwyllys b64_from_24bit(DP[12], DP[33], DP[54], 4);
3340cd13cbfSwyllys b64_from_24bit(DP[34], DP[55], DP[13], 4);
3350cd13cbfSwyllys b64_from_24bit(DP[56], DP[14], DP[35], 4);
3360cd13cbfSwyllys b64_from_24bit(DP[15], DP[36], DP[57], 4);
3370cd13cbfSwyllys b64_from_24bit(DP[37], DP[58], DP[16], 4);
3380cd13cbfSwyllys b64_from_24bit(DP[59], DP[17], DP[38], 4);
3390cd13cbfSwyllys b64_from_24bit(DP[18], DP[39], DP[60], 4);
3400cd13cbfSwyllys b64_from_24bit(DP[40], DP[61], DP[19], 4);
3410cd13cbfSwyllys b64_from_24bit(DP[62], DP[20], DP[41], 4);
3420cd13cbfSwyllys b64_from_24bit(0, 0, DP[63], 2);
3430cd13cbfSwyllys #endif
3440cd13cbfSwyllys *p = '\0';
3450cd13cbfSwyllys
3460cd13cbfSwyllys (void) memset(A, 0, sizeof (A));
3470cd13cbfSwyllys (void) memset(B, 0, sizeof (B));
3480cd13cbfSwyllys (void) memset(DP, 0, sizeof (DP));
3490cd13cbfSwyllys (void) memset(DS, 0, sizeof (DS));
3500cd13cbfSwyllys
3510cd13cbfSwyllys return (ctbuffer);
3520cd13cbfSwyllys }
3530cd13cbfSwyllys
354*1dbc1fedSDan OpenSolaris Anderson
355*1dbc1fedSDan OpenSolaris Anderson /* ARGSUSED3 */
3560cd13cbfSwyllys char *
crypt_gensalt_impl(char * gsbuffer,size_t gsbufflen,const char * oldsalt,const struct passwd * userinfo,const char ** params)3570cd13cbfSwyllys crypt_gensalt_impl(char *gsbuffer,
3580cd13cbfSwyllys size_t gsbufflen,
3590cd13cbfSwyllys const char *oldsalt,
3600cd13cbfSwyllys const struct passwd *userinfo,
3610cd13cbfSwyllys const char **params)
3620cd13cbfSwyllys {
3630cd13cbfSwyllys int fd;
3640cd13cbfSwyllys int err;
3650cd13cbfSwyllys ssize_t got;
3660cd13cbfSwyllys uint64_t rndval;
3670ca46ac5SWyllys Ingersoll uint32_t confrounds = 0;
3680ca46ac5SWyllys Ingersoll uint32_t saltrounds;
3690ca46ac5SWyllys Ingersoll char rndstr[sizeof (rndval) + 1];
3700ca46ac5SWyllys Ingersoll int i;
3710ca46ac5SWyllys Ingersoll
3720ca46ac5SWyllys Ingersoll for (i = 0; params != NULL && params[i] != NULL; i++) {
3730ca46ac5SWyllys Ingersoll if (strncmp(params[i], ROUNDS, ROUNDSLEN) == 0) {
3740ca46ac5SWyllys Ingersoll confrounds = getrounds(params[i]);
3750ca46ac5SWyllys Ingersoll } else {
3760ca46ac5SWyllys Ingersoll errno = EINVAL;
3770ca46ac5SWyllys Ingersoll return (NULL);
3780ca46ac5SWyllys Ingersoll }
3790ca46ac5SWyllys Ingersoll }
3800ca46ac5SWyllys Ingersoll
3810ca46ac5SWyllys Ingersoll /*
3820ca46ac5SWyllys Ingersoll * If the config file has a higher value for rounds= than what
3830ca46ac5SWyllys Ingersoll * was in the old salt use that, otherwise keep what was in the
3840ca46ac5SWyllys Ingersoll * old salt.
3850ca46ac5SWyllys Ingersoll */
3860ca46ac5SWyllys Ingersoll saltrounds = getrounds(oldsalt);
3870ca46ac5SWyllys Ingersoll if (confrounds > saltrounds) {
3880ca46ac5SWyllys Ingersoll saltrounds = confrounds;
3890ca46ac5SWyllys Ingersoll }
3900cd13cbfSwyllys
3910cd13cbfSwyllys if ((fd = open("/dev/urandom", O_RDONLY)) == -1) {
3920cd13cbfSwyllys return (NULL);
3930cd13cbfSwyllys }
3940cd13cbfSwyllys
3950cd13cbfSwyllys got = read(fd, &rndval, sizeof (rndval));
3960cd13cbfSwyllys if (got < sizeof (rndval)) {
3970cd13cbfSwyllys err = errno;
3980cd13cbfSwyllys (void) close(fd);
3990cd13cbfSwyllys errno = err;
4000cd13cbfSwyllys return (NULL);
4010cd13cbfSwyllys }
4020ca46ac5SWyllys Ingersoll (void) close(fd);
4030cd13cbfSwyllys
4040ca46ac5SWyllys Ingersoll to64((char *)&rndstr, rndval, sizeof (rndval));
4050ca46ac5SWyllys Ingersoll rndstr[sizeof (rndstr) - 1] = 0;
4060ca46ac5SWyllys Ingersoll
4070ca46ac5SWyllys Ingersoll if (saltrounds > 0) {
4080ca46ac5SWyllys Ingersoll if (snprintf(gsbuffer, gsbufflen,
4090ca46ac5SWyllys Ingersoll "%s$rounds=%d$",
4100ca46ac5SWyllys Ingersoll crypt_alg_magic, saltrounds) >= gsbufflen)
4110ca46ac5SWyllys Ingersoll goto fail;
4120ca46ac5SWyllys Ingersoll } else {
4130ca46ac5SWyllys Ingersoll if (snprintf(gsbuffer, gsbufflen,
4140ca46ac5SWyllys Ingersoll "%s$", crypt_alg_magic) >= gsbufflen)
4150ca46ac5SWyllys Ingersoll goto fail;
4160ca46ac5SWyllys Ingersoll }
4170ca46ac5SWyllys Ingersoll if (strlcat(gsbuffer, rndstr, gsbufflen) >= gsbufflen)
4180ca46ac5SWyllys Ingersoll goto fail;
4190ca46ac5SWyllys Ingersoll if (strlcat(gsbuffer, "$", gsbufflen) >= gsbufflen)
4200ca46ac5SWyllys Ingersoll goto fail;
4210cd13cbfSwyllys
4220ca46ac5SWyllys Ingersoll return (gsbuffer);
4230cd13cbfSwyllys
4240ca46ac5SWyllys Ingersoll fail:
4250ca46ac5SWyllys Ingersoll (void) memset(gsbuffer, 0, gsbufflen);
4260cd13cbfSwyllys return (gsbuffer);
4270cd13cbfSwyllys }
428