Home | History | Annotate | Line # | Download | only in libcrypt
pw_gensalt.c revision 1.2
      1 /*	$NetBSD: pw_gensalt.c,v 1.2 2005/01/11 23:02:30 christos Exp $	*/
      2 
      3 /*
      4  * Copyright 1997 Niels Provos <provos (at) 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.2 2005/01/11 23:02:30 christos 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 #include <pwd.h>
     54 
     55 #include <crypt.h>
     56 
     57 
     58 static const struct pw_salt {
     59 	const char *name;
     60 	int (*gensalt)(char *, size_t, size_t);
     61 } salts[] = {
     62 	{ "old", __gensalt_old },
     63 	{ "new", __gensalt_new },
     64 	{ "newsalt", __gensalt_new },
     65 	{ "md5", __gensalt_md5 },
     66 	{ "sha1", __gensalt_sha1 },
     67 	{ "blowfish", __gensalt_blowfish },
     68 	{ NULL, NULL }
     69 };
     70 
     71 int
     72 __gensalt_old(char *salt, size_t saltsiz, size_t nrounds)
     73 {
     74 	if (saltsiz < 3) {
     75 		errno = ENOSPC;
     76 		return -1;
     77 	}
     78 	__crypt_to64(&salt[0], arc4random(), 2);
     79 	salt[2] = '\0';
     80 	return 0;
     81 }
     82 
     83 int
     84 __gensalt_new(char *salt, size_t saltsiz, size_t nrounds)
     85 {
     86 	if (saltsiz < 10) {
     87 		errno = ENOSPC;
     88 		return -1;
     89 	}
     90 	/* Check rounds, 24 bit is max */
     91 	if (nrounds < 7250)
     92 		nrounds = 7250;
     93 	else if (nrounds > 0xffffff)
     94 		nrounds = 0xffffff;
     95 	salt[0] = _PASSWORD_EFMT1;
     96 	__crypt_to64(&salt[1], (uint32_t)nrounds, 4);
     97 	__crypt_to64(&salt[5], arc4random(), 4);
     98 	salt[9] = '\0';
     99 	return 0;
    100 }
    101 
    102 int
    103 __gensalt_md5(char *salt, size_t saltsiz, size_t nrounds)
    104 {
    105 	if (saltsiz < 13) {  /* $1$8salt$\0 */
    106 		errno = ENOSPC;
    107 		return -1;
    108 	}
    109 	salt[0] = _PASSWORD_NONDES;
    110 	salt[1] = '1';
    111 	salt[2] = '$';
    112 	__crypt_to64(&salt[3], arc4random(), 4);
    113 	__crypt_to64(&salt[7], arc4random(), 4);
    114 	salt[11] = '$';
    115 	salt[12] = '\0';
    116 	return 0;
    117 }
    118 
    119 int
    120 __gensalt_sha1(char *salt, size_t saltsiz, size_t nrounds)
    121 {
    122 	int n;
    123 
    124 	n = snprintf(salt, saltsiz, "%s%u$", SHA1_MAGIC,
    125 	    __crypt_sha1_iterations(nrounds));
    126 	/*
    127 	 * The salt can be up to 64 bytes, but 8
    128 	 * is considered enough for now.
    129 	 */
    130 	if (n + 9 >= saltsiz)
    131 		return 0;
    132 	__crypt_to64(&salt[n], arc4random(), 4);
    133 	__crypt_to64(&salt[n + 4], arc4random(), 4);
    134 	salt[n + 8] = '$';
    135 	salt[n + 9] = '\0';
    136 	return 0;
    137 }
    138 
    139 int
    140 pw_gensalt(char *salt, size_t saltlen, const struct passwd *pwd, char type)
    141 {
    142 	char option[LINE_MAX], *next, *now, *cipher, *ep, grpkey[LINE_MAX];
    143 	unsigned long rounds = 0;
    144 	struct group *grp;
    145 	const struct pw_salt *sp;
    146 
    147 	switch (type) {
    148 	case 'y':
    149 	        cipher = "ypcipher";
    150 		break;
    151 	case 'l':
    152 	default:
    153 	        cipher = "localcipher";
    154 		break;
    155 	}
    156 
    157 	pw_getconf(option, sizeof(option), pwd->pw_name, cipher);
    158 
    159 	/* Try to find an entry for the group */
    160 	if (*option == '\0') {
    161 		if ((grp = getgrgid(pwd->pw_gid)) != NULL) {
    162 			snprintf(grpkey, sizeof(grpkey), ":%s", grp->gr_name);
    163 			pw_getconf(option, sizeof(option), grpkey, cipher);
    164 		}
    165 		if (*option == '\0')
    166 		        pw_getconf(option, sizeof(option), "default", cipher);
    167 	}
    168 
    169 	next = option;
    170 	now = strsep(&next, ",");
    171 	if (next) {
    172 		rounds = strtoul(next, &ep, 0);
    173 
    174 		if (next == ep || *ep) {
    175 			errno = EINVAL;
    176 			return -1;
    177 		}
    178 
    179 		if (errno == ERANGE && rounds == ULONG_MAX)
    180 			return -1;
    181 	}
    182 
    183 	for (sp = salts; sp->name; sp++)
    184 		if (strcmp(sp->name, now) == 0)
    185 			return (*sp->gensalt)(salt, saltlen, (size_t)rounds);
    186 
    187 	errno = EINVAL;
    188 	return -1;
    189 }
    190