]> jfr.im git - solanum.git/blob - tools/mkpasswd.c
authd/provider: fix misordering in macro
[solanum.git] / tools / mkpasswd.c
1 /* simple password generator by Nelson Minar (minar@reed.edu)
2 * copyright 1991, all rights reserved.
3 * You can use this code as long as my name stays with it.
4 *
5 * md5 patch by W. Campbell <wcampbel@botbay.net>
6 * Modernization, getopt, etc for the Hybrid IRCD team
7 * by W. Campbell
8 *
9 * /dev/random for salt generation added by
10 * Aaron Sethman <androsyn@ratbox.org>
11 */
12 #include <stdio.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include <time.h>
16 #include <unistd.h>
17 #include <fcntl.h>
18 #include "rb_lib.h"
19 #ifndef __MINGW32__
20 #include <pwd.h>
21 #endif
22
23 #define FLAG_MD5 0x00000001
24 #define FLAG_SALT 0x00000002
25 #define FLAG_PASS 0x00000004
26 #define FLAG_LENGTH 0x00000008
27 #define FLAG_BLOWFISH 0x00000010
28 #define FLAG_ROUNDS 0x00000020
29 #define FLAG_SHA256 0x00000040
30 #define FLAG_SHA512 0x00000080
31
32
33 static char *make_md5_salt(int);
34 static char *make_md5_salt_para(char *);
35 static char *make_sha256_salt(int);
36 static char *make_sha256_salt_para(char *);
37 static char *make_sha512_salt(int);
38 static char *make_sha512_salt_para(char *);
39 static char *make_bf_salt(int, int);
40 static char *make_bf_salt_para(int, char *);
41 static char *generate_random_salt(char *, int);
42 static char *generate_poor_salt(char *, int);
43
44 static void full_usage(void);
45 static void brief_usage(void);
46
47 static char saltChars[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
48 /* 0 .. 63, ascii - 64 */
49
50 #ifdef __MINGW32__
51 #include <conio.h>
52 #ifdef PASS_MAX
53 #undef PASS_MAX
54 #endif
55 #define PASS_MAX 256
56 static char getpassbuf[PASS_MAX + 1];
57
58 static char *
59 getpass(const char *prompt)
60 {
61 int c;
62 int i = 0;
63
64 memset(getpassbuf, 0, sizeof(getpassbuf));
65 fputs(prompt, stderr);
66 for(;;)
67 {
68 c = _getch();
69 if(c == '\r')
70 {
71 getpassbuf[i] = '\0';
72 break;
73 }
74 else if(i < PASS_MAX)
75 {
76 getpassbuf[i++] = c;
77 }
78 }
79 fputs("\r\n", stderr);
80
81 return getpassbuf;
82 }
83 #endif
84
85
86 int
87 main(int argc, char *argv[])
88 {
89 char *plaintext = NULL;
90 int c;
91 char *saltpara = NULL;
92 char *salt;
93 char *hashed;
94 int flag = 0;
95 int length = 0; /* Not Set */
96 int rounds = 0; /* Not set, since blowfish needs 4 by default, a side effect
97 * of this being the encryption type parameter must be
98 * specified before the rounds parameter.
99 */
100
101 while((c = getopt(argc, argv, "xymbr:h?l:s:p:")) != -1)
102 {
103 switch (c)
104 {
105 case 'm':
106 flag |= FLAG_MD5;
107 break;
108 case 'b':
109 flag |= FLAG_BLOWFISH;
110 rounds = 4;
111 break;
112 case 'l':
113 flag |= FLAG_LENGTH;
114 length = atoi(optarg);
115 break;
116 case 'r':
117 flag |= FLAG_ROUNDS;
118 rounds = atoi(optarg);
119 break;
120 case 's':
121 flag |= FLAG_SALT;
122 saltpara = optarg;
123 break;
124 case 'p':
125 flag |= FLAG_PASS;
126 plaintext = optarg;
127 break;
128 case 'x':
129 flag |= FLAG_SHA256;
130 break;
131 case 'y':
132 flag |= FLAG_SHA512;
133 break;
134 case 'h':
135 full_usage();
136 /* NOT REACHED */
137 break;
138 case '?':
139 brief_usage();
140 /* NOT REACHED */
141 break;
142 default:
143 printf("Invalid Option: -%c\n", c);
144 break;
145 }
146 }
147
148 if(flag & FLAG_MD5)
149 {
150 if(length == 0)
151 length = 8;
152 if(flag & FLAG_SALT)
153 salt = make_md5_salt_para(saltpara);
154 else
155 salt = make_md5_salt(length);
156 }
157 else if(flag & FLAG_BLOWFISH)
158 {
159 if(length == 0)
160 length = 22;
161 if(flag & FLAG_SALT)
162 salt = make_bf_salt_para(rounds, saltpara);
163 else
164 salt = make_bf_salt(rounds, length);
165 }
166 else if(flag & FLAG_SHA256)
167 {
168 if(length == 0)
169 length = 16;
170 if(flag & FLAG_SALT)
171 salt = make_sha256_salt_para(saltpara);
172 else
173 salt = make_sha256_salt(length);
174 }
175 else
176 {
177 if(length == 0)
178 length = 16;
179 if(flag & FLAG_SALT)
180 salt = make_sha512_salt_para(saltpara);
181 else
182 salt = make_sha512_salt(length);
183 }
184
185 if(flag & FLAG_PASS)
186 {
187 if(!plaintext)
188 {
189 fprintf(stderr, "Please enter a valid password\n");
190 return 1;
191 }
192
193 hashed = rb_crypt(plaintext, salt);
194 }
195 else
196 {
197 hashed = strdup(rb_crypt(getpass("plaintext: "), salt));
198 plaintext = getpass("again: ");
199
200 if (strcmp(rb_crypt(plaintext, salt), hashed) != 0)
201 {
202 fprintf(stderr, "Passwords do not match\n");
203 return 1;
204 }
205 }
206
207 printf("%s\n", hashed);
208 return 0;
209 }
210
211 char *
212 make_md5_salt_para(char *saltpara)
213 {
214 static char salt[21];
215 if(saltpara && (strlen(saltpara) <= 16))
216 {
217 /* sprintf used because of portability requirements, the length
218 ** is checked above, so it should not be too much of a concern
219 */
220 sprintf(salt, "$1$%s$", saltpara);
221 return salt;
222 }
223 printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
224 exit(1);
225
226 /* NOT REACHED */
227 return NULL;
228 }
229
230 char *
231 make_md5_salt(int length)
232 {
233 static char salt[21];
234 if(length > 16)
235 {
236 printf("MD5 salt length too long\n");
237 exit(0);
238 }
239 salt[0] = '$';
240 salt[1] = '1';
241 salt[2] = '$';
242 generate_random_salt(&salt[3], length);
243 salt[length + 3] = '$';
244 salt[length + 4] = '\0';
245 return salt;
246 }
247
248 char *
249 make_sha256_salt_para(char *saltpara)
250 {
251 static char salt[21];
252 if(saltpara && (strlen(saltpara) <= 16))
253 {
254 /* sprintf used because of portability requirements, the length
255 ** is checked above, so it should not be too much of a concern
256 */
257 sprintf(salt, "$5$%s$", saltpara);
258 return salt;
259 }
260 printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
261 exit(1);
262
263 /* NOT REACHED */
264 return NULL;
265 }
266
267 char *
268 make_sha512_salt_para(char *saltpara)
269 {
270 static char salt[21];
271 if(saltpara && (strlen(saltpara) <= 16))
272 {
273 /* sprintf used because of portability requirements, the length
274 ** is checked above, so it should not be too much of a concern
275 */
276 sprintf(salt, "$6$%s$", saltpara);
277 return salt;
278 }
279 printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
280 exit(1);
281
282 /* NOT REACHED */
283 return NULL;
284 }
285
286
287 char *
288 make_sha256_salt(int length)
289 {
290 static char salt[21];
291 if(length > 16)
292 {
293 printf("SHA256 salt length too long\n");
294 exit(0);
295 }
296 salt[0] = '$';
297 salt[1] = '5';
298 salt[2] = '$';
299 generate_random_salt(&salt[3], length);
300 salt[length + 3] = '$';
301 salt[length + 4] = '\0';
302 return salt;
303 }
304
305 char *
306 make_sha512_salt(int length)
307 {
308 static char salt[21];
309 if(length > 16)
310 {
311 printf("SHA512 salt length too long\n");
312 exit(0);
313 }
314 salt[0] = '$';
315 salt[1] = '6';
316 salt[2] = '$';
317 generate_random_salt(&salt[3], length);
318 salt[length + 3] = '$';
319 salt[length + 4] = '\0';
320 return salt;
321 }
322
323 char *
324 make_bf_salt_para(int rounds, char *saltpara)
325 {
326 static char salt[31];
327 char tbuf[3];
328 if(saltpara && (strlen(saltpara) <= 22))
329 {
330 /* sprintf used because of portability requirements, the length
331 ** is checked above, so it should not be too much of a concern
332 */
333 sprintf(tbuf, "%02d", rounds);
334 sprintf(salt, "$2a$%s$%s$", tbuf, saltpara);
335 return salt;
336 }
337 printf("Invalid Salt, please use up to 22 random alphanumeric characters\n");
338 exit(1);
339
340 /* NOT REACHED */
341 return NULL;
342 }
343
344 char *
345 make_bf_salt(int rounds, int length)
346 {
347 static char salt[31];
348 char tbuf[3];
349 if(length > 22)
350 {
351 printf("Blowfish salt length too long\n");
352 exit(0);
353 }
354 sprintf(tbuf, "%02d", rounds);
355 sprintf(salt, "$2a$%s$", tbuf);
356 generate_random_salt(&salt[7], length);
357 salt[length + 7] = '$';
358 salt[length + 8] = '\0';
359 return salt;
360 }
361
362 char *
363 generate_poor_salt(char *salt, int length)
364 {
365 int i;
366 srand(time(NULL));
367 for(i = 0; i < length; i++)
368 {
369 salt[i] = saltChars[rand() % 64];
370 }
371 return (salt);
372 }
373
374 char *
375 generate_random_salt(char *salt, int length)
376 {
377 char *buf;
378 int fd, i;
379 if((fd = open("/dev/random", O_RDONLY)) < 0)
380 {
381 return (generate_poor_salt(salt, length));
382 }
383 buf = calloc(1, length);
384 if(read(fd, buf, length) != length)
385 {
386 free(buf);
387 return (generate_poor_salt(salt, length));
388 }
389
390 for(i = 0; i < length; i++)
391 {
392 salt[i] = saltChars[abs(buf[i]) % 64];
393 }
394 free(buf);
395 return (salt);
396 }
397
398 void
399 full_usage()
400 {
401 printf("mkpasswd [-m|-b|-x|-y] [-l saltlength] [-r rounds] [-s salt] [-p plaintext]\n");
402 printf("-x Generate a SHA256 password\n");
403 printf("-y Generate a SHA512 password\n");
404 printf("-m Generate an MD5 password\n");
405 printf("-b Generate a Blowfish password\n");
406 printf("-l Specify a length for a random MD5 or Blowfish salt\n");
407 printf("-r Specify a number of rounds for a Blowfish password\n");
408 printf(" Default 4, no more than 6 recommended\n");
409 printf("-s Specify a salt, up to 16 for MD5, SHA256, and SHA512\n");
410 printf(" up to 22 for Blowfish\n");
411 printf("-p Specify a plaintext password to use\n");
412 printf("Example: mkpasswd -m -s 3dr -p test\n");
413 exit(0);
414 }
415
416 void
417 brief_usage()
418 {
419 printf("mkpasswd - password hash generator\n");
420 printf(" SHA512: mkpasswd [-y] [-l saltlength] [-s salt] [-p plaintext]\n");
421 printf(" SHA256: mkpasswd -x [-l saltlength] [-s salt] [-p plaintext]\n");
422 printf(" MD5: mkpasswd -m [-l saltlength] [-s salt] [-p plaintext]\n");
423 printf("Blowfish: mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n");
424 printf(" [-p plaintext]\n");
425 printf("Use -h for full usage\n");
426 exit(0);
427 }