16532Swyllys /* 26532Swyllys * CDDL HEADER START 36532Swyllys * 46532Swyllys * The contents of this file are subject to the terms of the 56532Swyllys * Common Development and Distribution License (the "License"). 66532Swyllys * You may not use this file except in compliance with the License. 76532Swyllys * 86532Swyllys * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96532Swyllys * or http://www.opensolaris.org/os/licensing. 106532Swyllys * See the License for the specific language governing permissions 116532Swyllys * and limitations under the License. 126532Swyllys * 136532Swyllys * When distributing Covered Code, include this CDDL HEADER in each 146532Swyllys * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156532Swyllys * If applicable, add the following below this CDDL HEADER, with the 166532Swyllys * fields enclosed by brackets "[]" replaced with your own identifying 176532Swyllys * information: Portions Copyright [yyyy] [name of copyright owner] 186532Swyllys * 196532Swyllys * CDDL HEADER END 206532Swyllys */ 216532Swyllys /* 22*9557SWyllys.Ingersoll@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 236532Swyllys * Use is subject to license terms. 246532Swyllys */ 256532Swyllys 266532Swyllys /* 276532Swyllys * Portions of this code from crypt_bsdmd5.so (bsdmd5.c) : 286532Swyllys * ---------------------------------------------------------------------------- 296532Swyllys * "THE BEER-WARE LICENSE" (Revision 42): 306532Swyllys * <phk@login.dknet.dk> wrote this file. As long as you retain this notice you 316532Swyllys * can do whatever you want with this stuff. If we meet some day, and you think 326532Swyllys * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 336532Swyllys * ---------------------------------------------------------------------------- 346532Swyllys * 356532Swyllys * $FreeBSD: crypt.c,v 1.5 1996/10/14 08:34:02 phk Exp $ 366532Swyllys * 376532Swyllys */ 386532Swyllys 396532Swyllys /* 406532Swyllys * Implements the specification from: 416532Swyllys * 426532Swyllys * From http://people.redhat.com/drepper/SHA-crypt.txt 436532Swyllys * 446532Swyllys * Portions of the code taken from inspired by or verified against the 456532Swyllys * source in the above document which is licensed as: 466532Swyllys * 476532Swyllys * "Released into the Public Domain by Ulrich Drepper <drepper@redhat.com>." 486532Swyllys */ 496532Swyllys 506532Swyllys 516532Swyllys #include <sys/types.h> 526532Swyllys #include <sys/stat.h> 536532Swyllys #include <sys/sysmacros.h> 546532Swyllys #include <fcntl.h> 556532Swyllys #include <unistd.h> 566532Swyllys #include <string.h> 576532Swyllys #include <stdio.h> 586532Swyllys #include <errno.h> 596532Swyllys #include <stdlib.h> 606532Swyllys #include <alloca.h> 616532Swyllys 626532Swyllys #include <sha2.h> 636532Swyllys #include <crypt.h> 646532Swyllys 656532Swyllys #define MAX_SALT_LEN 16 666532Swyllys #define ROUNDS_DEFAULT 5000 676532Swyllys #define ROUNDS_MIN 1000 686532Swyllys #define ROUNDS_MAX 999999999 696532Swyllys 706532Swyllys #ifdef CRYPT_SHA256 716532Swyllys 726532Swyllys #define DIGEST_CTX SHA256_CTX 736532Swyllys #define DIGESTInit SHA256Init 746532Swyllys #define DIGESTUpdate SHA256Update 756532Swyllys #define DIGESTFinal SHA256Final 766532Swyllys #define DIGEST_LEN SHA256_DIGEST_LENGTH 776532Swyllys #define MIXCHARS 32 78*9557SWyllys.Ingersoll@Sun.COM static const char crypt_alg_magic[] = "$5"; 796532Swyllys 806532Swyllys #elif CRYPT_SHA512 816532Swyllys 826532Swyllys #define DIGEST_CTX SHA512_CTX 836532Swyllys #define DIGESTInit SHA512Init 846532Swyllys #define DIGESTUpdate SHA512Update 856532Swyllys #define DIGESTFinal SHA512Final 866532Swyllys #define DIGEST_LEN SHA512_DIGEST_LENGTH 876532Swyllys #define MIXCHARS 64 88*9557SWyllys.Ingersoll@Sun.COM static const char crypt_alg_magic[] = "$6"; 896532Swyllys 906532Swyllys #else 916532Swyllys #error "One of CRYPT_256 or CRYPT_512 must be defined" 926532Swyllys #endif 936532Swyllys 946532Swyllys static const int crypt_alg_magic_len = sizeof (crypt_alg_magic) - 1; 956532Swyllys 966532Swyllys 976532Swyllys static uchar_t b64t[] = /* 0 ... 63 => ascii - 64 */ 986532Swyllys "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; 996532Swyllys 1006532Swyllys #define b64_from_24bit(B2, B1, B0, N) \ 1016532Swyllys { \ 1026532Swyllys uint_t w = ((B2) << 16) | ((B1) << 8) | (B0); \ 1036532Swyllys int n = (N); \ 1046532Swyllys while (--n >= 0 && ctbufflen > 0) { \ 1056532Swyllys *p++ = b64t[w & 0x3f]; \ 1066532Swyllys w >>= 6; \ 1076532Swyllys ctbufflen--; \ 1086532Swyllys } \ 1096532Swyllys } 1106532Swyllys 1116532Swyllys static void 1126532Swyllys to64(char *s, uint64_t v, int n) 1136532Swyllys { 1146532Swyllys while (--n >= 0) { 1156532Swyllys *s++ = b64t[v&0x3f]; 1166532Swyllys v >>= 6; 1176532Swyllys } 1186532Swyllys } 1196532Swyllys 120*9557SWyllys.Ingersoll@Sun.COM #define ROUNDS "rounds=" 121*9557SWyllys.Ingersoll@Sun.COM #define ROUNDSLEN (sizeof (ROUNDS) - 1) 122*9557SWyllys.Ingersoll@Sun.COM 123*9557SWyllys.Ingersoll@Sun.COM /* 124*9557SWyllys.Ingersoll@Sun.COM * get the integer value after rounds= where ever it occurs in the string. 125*9557SWyllys.Ingersoll@Sun.COM * if the last char after the int is a , or $ that is fine anything else is an 126*9557SWyllys.Ingersoll@Sun.COM * error. 127*9557SWyllys.Ingersoll@Sun.COM */ 128*9557SWyllys.Ingersoll@Sun.COM static uint32_t 129*9557SWyllys.Ingersoll@Sun.COM getrounds(const char *s) 130*9557SWyllys.Ingersoll@Sun.COM { 131*9557SWyllys.Ingersoll@Sun.COM char *r, *p, *e; 132*9557SWyllys.Ingersoll@Sun.COM long val; 133*9557SWyllys.Ingersoll@Sun.COM 134*9557SWyllys.Ingersoll@Sun.COM if (s == NULL) 135*9557SWyllys.Ingersoll@Sun.COM return (0); 136*9557SWyllys.Ingersoll@Sun.COM 137*9557SWyllys.Ingersoll@Sun.COM if ((r = strstr(s, ROUNDS)) == NULL) { 138*9557SWyllys.Ingersoll@Sun.COM return (0); 139*9557SWyllys.Ingersoll@Sun.COM } 140*9557SWyllys.Ingersoll@Sun.COM 141*9557SWyllys.Ingersoll@Sun.COM if (strncmp(r, ROUNDS, ROUNDSLEN) != 0) { 142*9557SWyllys.Ingersoll@Sun.COM return (0); 143*9557SWyllys.Ingersoll@Sun.COM } 144*9557SWyllys.Ingersoll@Sun.COM 145*9557SWyllys.Ingersoll@Sun.COM p = r + ROUNDSLEN; 146*9557SWyllys.Ingersoll@Sun.COM errno = 0; 147*9557SWyllys.Ingersoll@Sun.COM val = strtol(p, &e, 10); 148*9557SWyllys.Ingersoll@Sun.COM /* 149*9557SWyllys.Ingersoll@Sun.COM * An error occured or there is non-numeric stuff at the end 150*9557SWyllys.Ingersoll@Sun.COM * which isn't one of the crypt(3c) special chars ',' or '$' 151*9557SWyllys.Ingersoll@Sun.COM */ 152*9557SWyllys.Ingersoll@Sun.COM if (errno != 0 || val < 0 || 153*9557SWyllys.Ingersoll@Sun.COM !(*e == '\0' || *e == ',' || *e == '$')) { 154*9557SWyllys.Ingersoll@Sun.COM return (0); 155*9557SWyllys.Ingersoll@Sun.COM } 156*9557SWyllys.Ingersoll@Sun.COM 157*9557SWyllys.Ingersoll@Sun.COM return ((uint32_t)val); 158*9557SWyllys.Ingersoll@Sun.COM } 159*9557SWyllys.Ingersoll@Sun.COM 160*9557SWyllys.Ingersoll@Sun.COM 1616532Swyllys char * 1626532Swyllys crypt_genhash_impl(char *ctbuffer, 1636532Swyllys size_t ctbufflen, 1646532Swyllys const char *plaintext, 1656532Swyllys const char *switchsalt, 1666532Swyllys const char **params) 1676532Swyllys { 1686532Swyllys int salt_len, plaintext_len, i; 1696532Swyllys char *salt; 1706532Swyllys uchar_t A[DIGEST_LEN]; 1716532Swyllys uchar_t B[DIGEST_LEN]; 1726532Swyllys uchar_t DP[DIGEST_LEN]; 1736532Swyllys uchar_t DS[DIGEST_LEN]; 1746532Swyllys DIGEST_CTX ctxA, ctxB, ctxC, ctxDP, ctxDS; 1756532Swyllys int rounds = ROUNDS_DEFAULT; 176*9557SWyllys.Ingersoll@Sun.COM int srounds = 0; 1776532Swyllys boolean_t custom_rounds = B_FALSE; 1786532Swyllys char *p; 1796532Swyllys char *P, *Pp; 1806532Swyllys char *S, *Sp; 1816532Swyllys 1826532Swyllys /* Refine the salt */ 1836532Swyllys salt = (char *)switchsalt; 1846532Swyllys 1856532Swyllys /* skip our magic string */ 1866532Swyllys if (strncmp((char *)salt, crypt_alg_magic, crypt_alg_magic_len) == 0) { 187*9557SWyllys.Ingersoll@Sun.COM salt += crypt_alg_magic_len + 1; 1886532Swyllys } 1896532Swyllys 190*9557SWyllys.Ingersoll@Sun.COM srounds = getrounds(salt); 191*9557SWyllys.Ingersoll@Sun.COM if (srounds != 0) { 192*9557SWyllys.Ingersoll@Sun.COM rounds = MAX(ROUNDS_MIN, MIN(srounds, ROUNDS_MAX)); 193*9557SWyllys.Ingersoll@Sun.COM custom_rounds = B_TRUE; 194*9557SWyllys.Ingersoll@Sun.COM p = strchr(salt, '$'); 195*9557SWyllys.Ingersoll@Sun.COM if (p != NULL) 196*9557SWyllys.Ingersoll@Sun.COM salt = p + 1; 1976532Swyllys } 1986532Swyllys 1996532Swyllys salt_len = MIN(strcspn(salt, "$"), MAX_SALT_LEN); 2006532Swyllys plaintext_len = strlen(plaintext); 2016532Swyllys 2026532Swyllys /* 1. */ 2036532Swyllys DIGESTInit(&ctxA); 2046532Swyllys 2056532Swyllys /* 2. The password first, since that is what is most unknown */ 2066532Swyllys DIGESTUpdate(&ctxA, plaintext, plaintext_len); 2076532Swyllys 2086532Swyllys /* 3. Then the raw salt */ 2096532Swyllys DIGESTUpdate(&ctxA, salt, salt_len); 2106532Swyllys 2116532Swyllys /* 4. - 8. */ 2126532Swyllys DIGESTInit(&ctxB); 2136532Swyllys DIGESTUpdate(&ctxB, plaintext, plaintext_len); 2146532Swyllys DIGESTUpdate(&ctxB, salt, salt_len); 2156532Swyllys DIGESTUpdate(&ctxB, plaintext, plaintext_len); 2166532Swyllys DIGESTFinal(B, &ctxB); 2176532Swyllys 2186532Swyllys /* 9. - 10. */ 2196532Swyllys for (i = plaintext_len; i > MIXCHARS; i -= MIXCHARS) 2206532Swyllys DIGESTUpdate(&ctxA, B, MIXCHARS); 2216532Swyllys DIGESTUpdate(&ctxA, B, i); 2226532Swyllys 2236532Swyllys /* 11. */ 2246532Swyllys for (i = plaintext_len; i > 0; i >>= 1) { 2256532Swyllys if ((i & 1) != 0) { 2266532Swyllys DIGESTUpdate(&ctxA, B, MIXCHARS); 2276532Swyllys } else { 2286532Swyllys DIGESTUpdate(&ctxA, plaintext, plaintext_len); 2296532Swyllys } 2306532Swyllys } 2316532Swyllys 2326532Swyllys /* 12. */ 2336532Swyllys DIGESTFinal(A, &ctxA); 2346532Swyllys 2356532Swyllys /* 13. - 15. */ 2366532Swyllys DIGESTInit(&ctxDP); 2376532Swyllys for (i = 0; i < plaintext_len; i++) 2386532Swyllys DIGESTUpdate(&ctxDP, plaintext, plaintext_len); 2396532Swyllys DIGESTFinal(DP, &ctxDP); 2406532Swyllys 2416532Swyllys /* 16. */ 2426532Swyllys Pp = P = alloca(plaintext_len); 2436532Swyllys for (i = plaintext_len; i >= MIXCHARS; i -= MIXCHARS) { 2446532Swyllys Pp = (char *)(memcpy(Pp, DP, MIXCHARS)) + MIXCHARS; 2456532Swyllys } 2466532Swyllys memcpy(Pp, DP, i); 2476532Swyllys 2486532Swyllys /* 17. - 19. */ 2496532Swyllys DIGESTInit(&ctxDS); 2506532Swyllys for (i = 0; i < 16 + (uint8_t)A[0]; i++) 2516532Swyllys DIGESTUpdate(&ctxDS, salt, salt_len); 2526532Swyllys DIGESTFinal(DS, &ctxDS); 2536532Swyllys 2546532Swyllys /* 20. */ 2556532Swyllys Sp = S = alloca(salt_len); 2566532Swyllys for (i = salt_len; i >= MIXCHARS; i -= MIXCHARS) { 2576532Swyllys Sp = (char *)(memcpy(Sp, DS, MIXCHARS)) + MIXCHARS; 2586532Swyllys } 2596532Swyllys memcpy(Sp, DS, i); 2606532Swyllys 2616532Swyllys /* 21. */ 2626532Swyllys for (i = 0; i < rounds; i++) { 2636532Swyllys DIGESTInit(&ctxC); 2646532Swyllys 2656532Swyllys if ((i & 1) != 0) { 2666532Swyllys DIGESTUpdate(&ctxC, P, plaintext_len); 2676532Swyllys } else { 2686532Swyllys if (i == 0) 2696532Swyllys DIGESTUpdate(&ctxC, A, MIXCHARS); 2706532Swyllys else 2716532Swyllys DIGESTUpdate(&ctxC, DP, MIXCHARS); 2726532Swyllys } 2736532Swyllys 2746532Swyllys if (i % 3 != 0) { 2756532Swyllys DIGESTUpdate(&ctxC, S, salt_len); 2766532Swyllys } 2776532Swyllys 2786532Swyllys if (i % 7 != 0) { 2796532Swyllys DIGESTUpdate(&ctxC, P, plaintext_len); 2806532Swyllys } 2816532Swyllys 2826532Swyllys if ((i & 1) != 0) { 2836532Swyllys if (i == 0) 2846532Swyllys DIGESTUpdate(&ctxC, A, MIXCHARS); 2856532Swyllys else 2866532Swyllys DIGESTUpdate(&ctxC, DP, MIXCHARS); 2876532Swyllys } else { 2886532Swyllys DIGESTUpdate(&ctxC, P, plaintext_len); 2896532Swyllys } 2906532Swyllys DIGESTFinal(DP, &ctxC); 2916532Swyllys } 2926532Swyllys 2936532Swyllys /* 22. Now make the output string */ 2946532Swyllys if (custom_rounds) { 2956532Swyllys (void) snprintf(ctbuffer, ctbufflen, 296*9557SWyllys.Ingersoll@Sun.COM "%s$rounds=%zu$", crypt_alg_magic, rounds); 297*9557SWyllys.Ingersoll@Sun.COM } else { 298*9557SWyllys.Ingersoll@Sun.COM (void) snprintf(ctbuffer, ctbufflen, 299*9557SWyllys.Ingersoll@Sun.COM "%s$", crypt_alg_magic); 3006532Swyllys } 3017314SWyllys.Ingersoll@Sun.COM (void) strncat(ctbuffer, (const char *)salt, salt_len); 3026532Swyllys (void) strlcat(ctbuffer, "$", ctbufflen); 303*9557SWyllys.Ingersoll@Sun.COM 3046532Swyllys p = ctbuffer + strlen(ctbuffer); 3056532Swyllys ctbufflen -= strlen(ctbuffer); 3066532Swyllys 3076532Swyllys #ifdef CRYPT_SHA256 3086532Swyllys b64_from_24bit(DP[ 0], DP[10], DP[20], 4); 3096532Swyllys b64_from_24bit(DP[21], DP[ 1], DP[11], 4); 3106532Swyllys b64_from_24bit(DP[12], DP[22], DP[ 2], 4); 3116532Swyllys b64_from_24bit(DP[ 3], DP[13], DP[23], 4); 3126532Swyllys b64_from_24bit(DP[24], DP[ 4], DP[14], 4); 3136532Swyllys b64_from_24bit(DP[15], DP[25], DP[ 5], 4); 3146532Swyllys b64_from_24bit(DP[ 6], DP[16], DP[26], 4); 3156532Swyllys b64_from_24bit(DP[27], DP[ 7], DP[17], 4); 3166532Swyllys b64_from_24bit(DP[18], DP[28], DP[ 8], 4); 3176532Swyllys b64_from_24bit(DP[ 9], DP[19], DP[29], 4); 3186532Swyllys b64_from_24bit(0, DP[31], DP[30], 3); 3196532Swyllys #elif CRYPT_SHA512 3206532Swyllys b64_from_24bit(DP[ 0], DP[21], DP[42], 4); 3216532Swyllys b64_from_24bit(DP[22], DP[43], DP[ 1], 4); 3226532Swyllys b64_from_24bit(DP[44], DP[ 2], DP[23], 4); 3236532Swyllys b64_from_24bit(DP[ 3], DP[24], DP[45], 4); 3246532Swyllys b64_from_24bit(DP[25], DP[46], DP[ 4], 4); 3256532Swyllys b64_from_24bit(DP[47], DP[ 5], DP[26], 4); 3266532Swyllys b64_from_24bit(DP[ 6], DP[27], DP[48], 4); 3276532Swyllys b64_from_24bit(DP[28], DP[49], DP[ 7], 4); 3286532Swyllys b64_from_24bit(DP[50], DP[ 8], DP[29], 4); 3296532Swyllys b64_from_24bit(DP[ 9], DP[30], DP[51], 4); 3306532Swyllys b64_from_24bit(DP[31], DP[52], DP[10], 4); 3316532Swyllys b64_from_24bit(DP[53], DP[11], DP[32], 4); 3326532Swyllys b64_from_24bit(DP[12], DP[33], DP[54], 4); 3336532Swyllys b64_from_24bit(DP[34], DP[55], DP[13], 4); 3346532Swyllys b64_from_24bit(DP[56], DP[14], DP[35], 4); 3356532Swyllys b64_from_24bit(DP[15], DP[36], DP[57], 4); 3366532Swyllys b64_from_24bit(DP[37], DP[58], DP[16], 4); 3376532Swyllys b64_from_24bit(DP[59], DP[17], DP[38], 4); 3386532Swyllys b64_from_24bit(DP[18], DP[39], DP[60], 4); 3396532Swyllys b64_from_24bit(DP[40], DP[61], DP[19], 4); 3406532Swyllys b64_from_24bit(DP[62], DP[20], DP[41], 4); 3416532Swyllys b64_from_24bit(0, 0, DP[63], 2); 3426532Swyllys #endif 3436532Swyllys *p = '\0'; 3446532Swyllys 3456532Swyllys (void) memset(A, 0, sizeof (A)); 3466532Swyllys (void) memset(B, 0, sizeof (B)); 3476532Swyllys (void) memset(DP, 0, sizeof (DP)); 3486532Swyllys (void) memset(DS, 0, sizeof (DS)); 3496532Swyllys 3506532Swyllys return (ctbuffer); 3516532Swyllys } 3526532Swyllys 3536532Swyllys char * 3546532Swyllys crypt_gensalt_impl(char *gsbuffer, 3556532Swyllys size_t gsbufflen, 3566532Swyllys const char *oldsalt, 3576532Swyllys const struct passwd *userinfo, 3586532Swyllys const char **params) 3596532Swyllys { 3606532Swyllys int fd; 3616532Swyllys int err; 3626532Swyllys ssize_t got; 3636532Swyllys uint64_t rndval; 364*9557SWyllys.Ingersoll@Sun.COM uint32_t confrounds = 0; 365*9557SWyllys.Ingersoll@Sun.COM uint32_t saltrounds; 366*9557SWyllys.Ingersoll@Sun.COM char rndstr[sizeof (rndval) + 1]; 367*9557SWyllys.Ingersoll@Sun.COM int i; 368*9557SWyllys.Ingersoll@Sun.COM 369*9557SWyllys.Ingersoll@Sun.COM for (i = 0; params != NULL && params[i] != NULL; i++) { 370*9557SWyllys.Ingersoll@Sun.COM if (strncmp(params[i], ROUNDS, ROUNDSLEN) == 0) { 371*9557SWyllys.Ingersoll@Sun.COM confrounds = getrounds(params[i]); 372*9557SWyllys.Ingersoll@Sun.COM } else { 373*9557SWyllys.Ingersoll@Sun.COM errno = EINVAL; 374*9557SWyllys.Ingersoll@Sun.COM return (NULL); 375*9557SWyllys.Ingersoll@Sun.COM } 376*9557SWyllys.Ingersoll@Sun.COM } 377*9557SWyllys.Ingersoll@Sun.COM 378*9557SWyllys.Ingersoll@Sun.COM /* 379*9557SWyllys.Ingersoll@Sun.COM * If the config file has a higher value for rounds= than what 380*9557SWyllys.Ingersoll@Sun.COM * was in the old salt use that, otherwise keep what was in the 381*9557SWyllys.Ingersoll@Sun.COM * old salt. 382*9557SWyllys.Ingersoll@Sun.COM */ 383*9557SWyllys.Ingersoll@Sun.COM saltrounds = getrounds(oldsalt); 384*9557SWyllys.Ingersoll@Sun.COM if (confrounds > saltrounds) { 385*9557SWyllys.Ingersoll@Sun.COM saltrounds = confrounds; 386*9557SWyllys.Ingersoll@Sun.COM } 3876532Swyllys 3886532Swyllys if ((fd = open("/dev/urandom", O_RDONLY)) == -1) { 3896532Swyllys return (NULL); 3906532Swyllys } 3916532Swyllys 3926532Swyllys got = read(fd, &rndval, sizeof (rndval)); 3936532Swyllys if (got < sizeof (rndval)) { 3946532Swyllys err = errno; 3956532Swyllys (void) close(fd); 3966532Swyllys errno = err; 3976532Swyllys return (NULL); 3986532Swyllys } 3996532Swyllys (void) close(fd); 4006532Swyllys 401*9557SWyllys.Ingersoll@Sun.COM to64((char *)&rndstr, rndval, sizeof (rndval)); 402*9557SWyllys.Ingersoll@Sun.COM rndstr[sizeof (rndstr) - 1] = 0; 403*9557SWyllys.Ingersoll@Sun.COM 404*9557SWyllys.Ingersoll@Sun.COM if (saltrounds > 0) { 405*9557SWyllys.Ingersoll@Sun.COM if (snprintf(gsbuffer, gsbufflen, 406*9557SWyllys.Ingersoll@Sun.COM "%s$rounds=%d$", 407*9557SWyllys.Ingersoll@Sun.COM crypt_alg_magic, saltrounds) >= gsbufflen) 408*9557SWyllys.Ingersoll@Sun.COM goto fail; 409*9557SWyllys.Ingersoll@Sun.COM } else { 410*9557SWyllys.Ingersoll@Sun.COM if (snprintf(gsbuffer, gsbufflen, 411*9557SWyllys.Ingersoll@Sun.COM "%s$", crypt_alg_magic) >= gsbufflen) 412*9557SWyllys.Ingersoll@Sun.COM goto fail; 413*9557SWyllys.Ingersoll@Sun.COM } 414*9557SWyllys.Ingersoll@Sun.COM if (strlcat(gsbuffer, rndstr, gsbufflen) >= gsbufflen) 415*9557SWyllys.Ingersoll@Sun.COM goto fail; 416*9557SWyllys.Ingersoll@Sun.COM if (strlcat(gsbuffer, "$", gsbufflen) >= gsbufflen) 417*9557SWyllys.Ingersoll@Sun.COM goto fail; 418*9557SWyllys.Ingersoll@Sun.COM 419*9557SWyllys.Ingersoll@Sun.COM return (gsbuffer); 420*9557SWyllys.Ingersoll@Sun.COM 421*9557SWyllys.Ingersoll@Sun.COM fail: 422*9557SWyllys.Ingersoll@Sun.COM (void) memset(gsbuffer, 0, gsbufflen); 4236532Swyllys return (gsbuffer); 4246532Swyllys } 425