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