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