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 69usage(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 82static char * 83trim(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 99static void 100print_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 165int 166main(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