pwhash.c revision 1.4 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