1 /* $NetBSD: pw_gensalt.c,v 1.7 2009/01/18 12:15:27 lukem Exp $ */ 2 3 /* 4 * Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Niels Provos. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 * 32 * from OpenBSD: pwd_gensalt.c,v 1.9 1998/07/05 21:08:32 provos Exp 33 */ 34 35 #include <sys/cdefs.h> 36 #ifndef lint 37 __RCSID("$NetBSD: pw_gensalt.c,v 1.7 2009/01/18 12:15:27 lukem Exp $"); 38 #endif /* not lint */ 39 40 #include <sys/syslimits.h> 41 #include <sys/types.h> 42 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <limits.h> 47 #include <err.h> 48 #include <grp.h> 49 #include <pwd.h> 50 #include <util.h> 51 #include <time.h> 52 #include <errno.h> 53 54 #include "crypt.h" 55 56 57 static const struct pw_salt { 58 const char *name; 59 int (*gensalt)(char *, size_t, const char *); 60 } salts[] = { 61 { "old", __gensalt_old }, 62 { "new", __gensalt_new }, 63 { "newsalt", __gensalt_new }, 64 { "md5", __gensalt_md5 }, 65 { "sha1", __gensalt_sha1 }, 66 { "blowfish", __gensalt_blowfish }, 67 { NULL, NULL } 68 }; 69 70 static int 71 getnum(const char *str, size_t *num) 72 { 73 char *ep; 74 unsigned long rv; 75 76 if (str == NULL) { 77 *num = 0; 78 return 0; 79 } 80 81 rv = strtoul(str, &ep, 0); 82 83 if (str == ep || *ep) { 84 errno = EINVAL; 85 return -1; 86 } 87 88 if (errno == ERANGE && rv == ULONG_MAX) 89 return -1; 90 *num = (size_t)rv; 91 return 0; 92 } 93 94 int 95 /*ARGSUSED2*/ 96 __gensalt_old(char *salt, size_t saltsiz, const char *option) 97 { 98 if (saltsiz < 3) { 99 errno = ENOSPC; 100 return -1; 101 } 102 __crypt_to64(&salt[0], arc4random(), 2); 103 salt[2] = '\0'; 104 return 0; 105 } 106 107 int 108 /*ARGSUSED2*/ 109 __gensalt_new(char *salt, size_t saltsiz, const char* option) 110 { 111 size_t nrounds; 112 113 if (saltsiz < 10) { 114 errno = ENOSPC; 115 return -1; 116 } 117 118 if (getnum(option, &nrounds) == -1) 119 return -1; 120 121 /* Check rounds, 24 bit is max */ 122 if (nrounds < 7250) 123 nrounds = 7250; 124 else if (nrounds > 0xffffff) 125 nrounds = 0xffffff; 126 salt[0] = _PASSWORD_EFMT1; 127 __crypt_to64(&salt[1], (uint32_t)nrounds, 4); 128 __crypt_to64(&salt[5], arc4random(), 4); 129 salt[9] = '\0'; 130 return 0; 131 } 132 133 int 134 /*ARGSUSED2*/ 135 __gensalt_md5(char *salt, size_t saltsiz, const char *option) 136 { 137 if (saltsiz < 13) { /* $1$8salt$\0 */ 138 errno = ENOSPC; 139 return -1; 140 } 141 salt[0] = _PASSWORD_NONDES; 142 salt[1] = '1'; 143 salt[2] = '$'; 144 __crypt_to64(&salt[3], arc4random(), 4); 145 __crypt_to64(&salt[7], arc4random(), 4); 146 salt[11] = '$'; 147 salt[12] = '\0'; 148 return 0; 149 } 150 151 int 152 __gensalt_sha1(char *salt, size_t saltsiz, const char *option) 153 { 154 int n; 155 size_t nrounds; 156 157 if (getnum(option, &nrounds) == -1) 158 return -1; 159 n = snprintf(salt, saltsiz, "%s%u$", SHA1_MAGIC, 160 __crypt_sha1_iterations(nrounds)); 161 /* 162 * The salt can be up to 64 bytes, but 8 163 * is considered enough for now. 164 */ 165 if ((size_t)n + 9 >= saltsiz) 166 return 0; 167 __crypt_to64(&salt[n], arc4random(), 4); 168 __crypt_to64(&salt[n + 4], arc4random(), 4); 169 salt[n + 8] = '$'; 170 salt[n + 9] = '\0'; 171 return 0; 172 } 173 174 int 175 pw_gensalt(char *salt, size_t saltlen, const char *type, const char *option) 176 { 177 const struct pw_salt *sp; 178 179 for (sp = salts; sp->name; sp++) 180 if (strcmp(sp->name, type) == 0) 181 return (*sp->gensalt)(salt, saltlen, option); 182 183 errno = EINVAL; 184 return -1; 185 } 186