1 /* $NetBSD: pwhash.c,v 1.4 2003/06/23 13:05:51 agc 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.4 2003/06/23 13:05:51 agc 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 <login_cap.h> 44 45 /* 46 * Very simple little program, for encrypting passwords from the command 47 * line. Useful for scripts and such. 48 */ 49 50 #define DO_MAKEKEY 0 51 #define DO_DES 1 52 #define DO_MD5 2 53 #define DO_BLF 3 54 55 static void 56 usage(void) 57 { 58 59 (void)fprintf(stderr, 60 "usage: %s [-b rounds] [-k] [-m] [-s salt] [-p | string]\n", 61 getprogname()); 62 exit(1); 63 } 64 65 static char * 66 trim(char *line) 67 { 68 char *ptr; 69 70 for (ptr = &line[strlen(line)-1]; ptr > line; ptr--) { 71 if (!isspace(*ptr)) 72 break; 73 } 74 ptr[1] = '\0'; 75 76 for (ptr = line; *ptr && isspace(*ptr); ptr++) 77 ; 78 79 return(ptr); 80 } 81 82 /* these are pulled from usr.bin/passwd/pwd_gensalt.c */ 83 int pwd_gensalt(char *, int, struct passwd *, login_cap_t *, char); 84 void to64(char *, int32_t, int n); 85 86 static void 87 print_passwd(char *string, int operation, void *extra) 88 { 89 char msalt[3], *salt; 90 struct passwd pwd; 91 login_cap_t *lc; 92 char buffer[_PASSWORD_LEN]; 93 94 switch(operation) { 95 case DO_MAKEKEY: 96 /* 97 * makekey mode: parse string into separate DES key and salt. 98 */ 99 if (strlen(string) != 10) { 100 /* To be compatible... */ 101 errx(1, "%s", strerror(EFTYPE)); 102 } 103 strcpy(msalt, &string[8]); 104 salt = msalt; 105 break; 106 107 case DO_MD5: 108 strcpy(buffer, "$1$"); 109 to64(&buffer[3], arc4random(), 4); 110 to64(&buffer[7], arc4random(), 4); 111 strcpy(buffer + 11, "$"); 112 salt = buffer; 113 break; 114 115 case DO_BLF: 116 strlcpy(buffer, bcrypt_gensalt(*(int *)extra), _PASSWORD_LEN); 117 salt = buffer; 118 break; 119 120 case DO_DES: 121 salt = extra; 122 break; 123 124 default: 125 pwd.pw_name = "default"; 126 if ((lc = login_getclass(NULL)) == NULL) 127 errx(1, "unable to get default login class."); 128 if (!pwd_gensalt(buffer, _PASSWORD_LEN, &pwd, lc, 'l')) 129 errx(1, "can't generate salt"); 130 salt = buffer; 131 break; 132 } 133 134 (void)fputs(crypt(string, salt), stdout); 135 } 136 137 int 138 main(int argc, char **argv) 139 { 140 int opt; 141 int operation = -1; 142 int prompt = 0; 143 int rounds; 144 void *extra; /* Store salt or number of rounds */ 145 146 setprogname(argv[0]); 147 148 if (strcmp(getprogname(), "makekey") == 0) 149 operation = DO_MAKEKEY; 150 151 while ((opt = getopt(argc, argv, "kmps:b:")) != -1) { 152 switch (opt) { 153 case 'k': /* Stdin/Stdout Unix crypt */ 154 if (operation != -1 || prompt) 155 usage(); 156 operation = DO_MAKEKEY; 157 break; 158 159 case 'm': /* MD5 password hash */ 160 if (operation != -1) 161 usage(); 162 operation = DO_MD5; 163 break; 164 165 case 'p': 166 if (operation == DO_MAKEKEY) 167 usage(); 168 prompt = 1; 169 break; 170 171 case 's': /* Unix crypt (DES) */ 172 if (operation != -1 || optarg[0] == '$') 173 usage(); 174 operation = DO_DES; 175 extra = optarg; 176 break; 177 178 case 'b': /* Blowfish password hash */ 179 if (operation != -1) 180 usage(); 181 operation = DO_BLF; 182 rounds = atoi(optarg); 183 extra = &rounds; 184 break; 185 186 default: 187 usage(); 188 } 189 } 190 191 if (((argc - optind) < 1) || operation == DO_MAKEKEY) { 192 char line[BUFSIZ], *string; 193 194 if (prompt) { 195 string = getpass("Enter string: "); 196 print_passwd(string, operation, extra); 197 (void)fputc('\n', stdout); 198 } else { 199 /* Encrypt stdin to stdout. */ 200 while (!feof(stdin) && 201 (fgets(line, sizeof(line), stdin) != NULL)) { 202 /* Kill the whitesapce. */ 203 string = trim(line); 204 if (*string == '\0') 205 continue; 206 207 print_passwd(string, operation, extra); 208 209 if (operation == DO_MAKEKEY) { 210 fflush(stdout); 211 break; 212 } 213 (void)fputc('\n', stdout); 214 } 215 } 216 } else { 217 char *string; 218 219 /* can't combine -p with a supplied string */ 220 if (prompt) 221 usage(); 222 223 /* Perhaps it isn't worth worrying about, but... */ 224 if ((string = strdup(argv[optind])) == NULL) 225 err(1, NULL); 226 /* Wipe the argument. */ 227 memset(argv[optind], 0, strlen(argv[optind])); 228 229 print_passwd(string, operation, extra); 230 231 (void)fputc('\n', stdout); 232 233 /* Wipe our copy, before we free it. */ 234 memset(string, 0, strlen(string)); 235 free(string); 236 } 237 exit(0); 238 } 239