Home | History | Annotate | Line # | Download | only in pwhash
      1 /*	$NetBSD: pwhash.c,v 1.16 2019/10/21 02:36:48 jhigh Exp $	*/
      2 /*	$OpenBSD: encrypt.c,v 1.16 2002/02/16 21:27:45 millert Exp $	*/
      3 
      4 /*
      5  * Copyright (c) 1996, Jason Downs.  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  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
     17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
     20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 #include <sys/cdefs.h>
     29 
     30 #ifndef lint
     31 __RCSID("$NetBSD: pwhash.c,v 1.16 2019/10/21 02:36:48 jhigh Exp $");
     32 #endif
     33 
     34 #include <sys/types.h>
     35 #include <ctype.h>
     36 #include <err.h>
     37 #include <errno.h>
     38 #include <pwd.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <unistd.h>
     43 #include <limits.h>
     44 #include <login_cap.h>
     45 #include <util.h>
     46 
     47 /*
     48  * Very simple little program, for encrypting passwords from the command
     49  * line.  Useful for scripts and such.
     50  */
     51 
     52 #define DO_MAKEKEY 0
     53 #define DO_DES     1
     54 #define DO_MD5     2
     55 #define DO_BLF     3
     56 #define DO_SHA1	   4
     57 
     58 #ifdef HAVE_ARGON2
     59 #define DO_ARGON2  5
     60 /*
     61  * Argon2 variant may be specified in /etc/passwd.conf
     62  * If not found, default to ARGON2_DEFAULT_VARIANT_STR
     63  * acceptable values are: argon2i, argon2d, argon2id
     64  */
     65 #define ARGON2_DEFAULT_VARIANT_STR	"argon2id"
     66 #endif /* HAVE_ARGON2 */
     67 
     68 __dead static void
     69 usage(void)
     70 {
     71 
     72 	(void)fprintf(stderr,
     73 #ifdef HAVE_ARGON2
     74 	    "Usage: %s [-km] [-A variant[,params]] [-b rounds] [-S rounds] [-s salt] [-p | string]\n",
     75 #else
     76 	    "Usage: %s [-km] [-b rounds] [-S rounds] [-s salt] [-p | string]\n",
     77 #endif /* HAVE_ARGON2 */
     78 	    getprogname());
     79 	exit(1);
     80 }
     81 
     82 static char *
     83 trim(char *line)
     84 {
     85 	char *ptr;
     86 
     87 	for (ptr = &line[strlen(line) - 1]; ptr > line; ptr--) {
     88 		if (!isspace((unsigned char)*ptr))
     89 			break;
     90 	}
     91 	ptr[1] = '\0';
     92 
     93 	for (ptr = line; *ptr && isspace((unsigned char)*ptr); ptr++)
     94 		continue;
     95 
     96 	return ptr;
     97 }
     98 
     99 static void
    100 print_passwd(char *string, int operation, const char *extra)
    101 {
    102 	char buf[_PASSWORD_LEN];
    103 	char option[LINE_MAX], *key, *opt;
    104 	int error = 0;
    105 	const char *salt = buf;
    106 
    107 	switch(operation) {
    108 	case DO_MAKEKEY:
    109 		/*
    110 		 * makekey mode: parse string into separate DES key and salt.
    111 		 */
    112 		if (strlen(string) != 10) {
    113 			/* To be compatible... */
    114 			error = EFTYPE;
    115 			break;
    116 		}
    117 		salt = &string[8];
    118 		break;
    119 
    120 	case DO_MD5:
    121 		error = pw_gensalt(buf, _PASSWORD_LEN, "md5", extra);
    122 		break;
    123 
    124 	case DO_SHA1:
    125 		error = pw_gensalt(buf, _PASSWORD_LEN, "sha1", extra);
    126 		break;
    127 
    128 	case DO_BLF:
    129 		error = pw_gensalt(buf, _PASSWORD_LEN, "blowfish", extra);
    130 		break;
    131 
    132 	case DO_DES:
    133 		salt = extra;
    134 		break;
    135 
    136 #ifdef HAVE_ARGON2
    137 	case DO_ARGON2:
    138 		/* pwhash -A <variant>[,param]* */
    139 		/* param
    140 		 *    m=<m_cost>
    141 		 *    t=<t_cost>
    142 		 *    p=<threads>
    143 		 */
    144 		snprintf(option, sizeof(option), "%s", extra);
    145 		opt = option;
    146 		key = strsep(&opt, ",");
    147 		error = pw_gensalt(buf, _PASSWORD_LEN, key, opt);
    148 		break;
    149 #endif /* HAVE_ARGON2 */
    150 
    151 	default:
    152 		pw_getconf(option, sizeof(option), "default", "localcipher");
    153 		opt = option;
    154 		key = strsep(&opt, ",");
    155 		error = pw_gensalt(buf, _PASSWORD_LEN, key, opt);
    156 		break;
    157 	}
    158 
    159 	if (error)
    160 		err(1, "Cannot generate salt");
    161 
    162 	(void)fputs(crypt(string, salt), stdout);
    163 }
    164 
    165 int
    166 main(int argc, char **argv)
    167 {
    168 	int opt;
    169 	int operation = -1;
    170 	int prompt = 0;
    171 	const char *extra = NULL;	/* Store salt or number of rounds */
    172 
    173 	setprogname(argv[0]);
    174 
    175 	if (strcmp(getprogname(), "makekey") == 0)
    176 		operation = DO_MAKEKEY;
    177 
    178 #ifdef HAVE_ARGON2
    179 	while ((opt = getopt(argc, argv, "kmpS:s:b:A:")) != -1) {
    180 #else
    181 	while ((opt = getopt(argc, argv, "kmpS:s:b:")) != -1) {
    182 #endif /* HAVE_ARGON2 */
    183 		switch (opt) {
    184 		case 'k':                       /* Stdin/Stdout Unix crypt */
    185 			if (operation != -1 || prompt)
    186 				usage();
    187 			operation = DO_MAKEKEY;
    188 			break;
    189 
    190 		case 'm':                       /* MD5 password hash */
    191 			if (operation != -1)
    192 				usage();
    193 			operation = DO_MD5;
    194 			extra = NULL;
    195 			break;
    196 
    197 		case 'p':
    198 			if (operation == DO_MAKEKEY)
    199 				usage();
    200 			prompt = 1;
    201 			break;
    202 
    203 		case 'S':                       /* SHA1 password hash */
    204 			if (operation != -1)
    205 				usage();
    206 			operation = DO_SHA1;
    207 			extra = optarg;
    208 			break;
    209 
    210 		case 's':                       /* Unix crypt (DES) */
    211 			if (operation != -1 || optarg[0] == '$')
    212 				usage();
    213 			operation = DO_DES;
    214 			extra = optarg;
    215 			break;
    216 
    217 		case 'b':                       /* Blowfish password hash */
    218 			if (operation != -1)
    219 				usage();
    220 			operation = DO_BLF;
    221 			extra = optarg;
    222 			break;
    223 
    224 #ifdef HAVE_ARGON2
    225 		case 'A':                       /* Argon2 password hash */
    226 			if (operation != -1)
    227 				usage();
    228 			operation = DO_ARGON2;
    229 			extra = optarg;
    230 			break;
    231 #endif /* HAVE_ARGON2 */
    232 
    233 		default:
    234 			usage();
    235 		}
    236 	}
    237 
    238 	if (((argc - optind) < 1) || operation == DO_MAKEKEY) {
    239 		char line[LINE_MAX], *string;
    240 
    241 		if (prompt) {
    242 			string = getpass("Enter string: ");
    243 			print_passwd(string, operation, extra);
    244 			(void)fputc('\n', stdout);
    245 		} else {
    246 			/* Encrypt stdin to stdout. */
    247 			while (!feof(stdin) &&
    248 			    (fgets(line, sizeof(line), stdin) != NULL)) {
    249 				/* Kill the whitesapce. */
    250 				string = trim(line);
    251 				if (*string == '\0')
    252 					continue;
    253 
    254 				print_passwd(string, operation, extra);
    255 
    256 				if (operation == DO_MAKEKEY) {
    257 					(void)fflush(stdout);
    258 					break;
    259 				}
    260 				(void)fputc('\n', stdout);
    261 			}
    262 		}
    263 	} else {
    264 		char *string;
    265 
    266 		/* can't combine -p with a supplied string */
    267 		if (prompt)
    268 			usage();
    269 
    270 		/* Perhaps it isn't worth worrying about, but... */
    271 		if ((string = strdup(argv[optind])) == NULL)
    272 			err(1, NULL);
    273 		/* Wipe the argument. */
    274 		(void)memset(argv[optind], 0, strlen(argv[optind]));
    275 
    276 		print_passwd(string, operation, extra);
    277 
    278 		(void)fputc('\n', stdout);
    279 
    280 		/* Wipe our copy, before we free it. */
    281 		(void)memset(string, 0, strlen(string));
    282 		free(string);
    283 	}
    284 	return 0;
    285 }
    286