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 1120cd13cbfSwyllys to64(char *s, uint64_t v, int n) 1130cd13cbfSwyllys { 1140cd13cbfSwyllys while (--n >= 0) { 1150cd13cbfSwyllys *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 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 * 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) { 1930cd13cbfSwyllys rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX)); 1940cd13cbfSwyllys 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 * 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 } 4020cd13cbfSwyllys (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; 4210ca46ac5SWyllys Ingersoll 4220ca46ac5SWyllys Ingersoll return (gsbuffer); 4230ca46ac5SWyllys Ingersoll 4240ca46ac5SWyllys Ingersoll fail: 4250ca46ac5SWyllys Ingersoll (void) memset(gsbuffer, 0, gsbufflen); 4260cd13cbfSwyllys return (gsbuffer); 4270cd13cbfSwyllys } 428