]> jfr.im git - solanum.git/blame - tools/mkpasswd.c
chmode: stop processing when too many modes
[solanum.git] / tools / mkpasswd.c
CommitLineData
212380e3 1/* simple password generator by Nelson Minar (minar@reed.edu)
8522eb3b
EM
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 */
212380e3
AC
12#include <stdio.h>
13#include <string.h>
14#include <stdlib.h>
15#include <time.h>
16#include <unistd.h>
17#include <fcntl.h>
fe037171 18#include "rb_lib.h"
f1d07f6b
JT
19#ifndef __MINGW32__
20#include <pwd.h>
21#endif
212380e3 22
f1d07f6b 23#define FLAG_MD5 0x00000001
8522eb3b
EM
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
212380e3
AC
33static char *make_md5_salt(int);
34static char *make_md5_salt_para(char *);
f1d07f6b
JT
35static char *make_sha256_salt(int);
36static char *make_sha256_salt_para(char *);
37static char *make_sha512_salt(int);
38static char *make_sha512_salt_para(char *);
212380e3
AC
39static char *make_bf_salt(int, int);
40static char *make_bf_salt_para(int, char *);
212380e3
AC
41static char *generate_random_salt(char *, int);
42static char *generate_poor_salt(char *, int);
43
2cad5415
AJ
44static void full_usage(void) __attribute__((noreturn));
45static void brief_usage(void) __attribute__((noreturn));
212380e3 46
f1d07f6b 47static char saltChars[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
212380e3
AC
48 /* 0 .. 63, ascii - 64 */
49
f1d07f6b
JT
50#ifdef __MINGW32__
51#include <conio.h>
52#ifdef PASS_MAX
53#undef PASS_MAX
54#endif
55#define PASS_MAX 256
56static char getpassbuf[PASS_MAX + 1];
57
58static char *
59getpass(const char *prompt)
212380e3 60{
f1d07f6b
JT
61 int c;
62 int i = 0;
63
29c92cf9 64 memset(getpassbuf, 0, sizeof(getpassbuf));
f1d07f6b
JT
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;
212380e3 82}
f1d07f6b
JT
83#endif
84
212380e3 85
f1d07f6b
JT
86int
87main(int argc, char *argv[])
212380e3 88{
f1d07f6b
JT
89 char *plaintext = NULL;
90 int c;
91 char *saltpara = NULL;
92 char *salt;
6002ccec 93 char *hashed, *hashed2;
f1d07f6b
JT
94 int flag = 0;
95 int length = 0; /* Not Set */
8522eb3b
EM
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.
f1d07f6b
JT
99 */
100
8522eb3b 101 while((c = getopt(argc, argv, "xymbr:h?l:s:p:")) != -1)
f1d07f6b
JT
102 {
103 switch (c)
104 {
105 case 'm':
106 flag |= FLAG_MD5;
107 break;
f1d07f6b
JT
108 case 'b':
109 flag |= FLAG_BLOWFISH;
110 rounds = 4;
111 break;
f1d07f6b
JT
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
7600b65f
EM
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)
f1d07f6b
JT
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 }
920cb1dc
AC
175 else
176 {
177 if(length == 0)
7600b65f 178 length = 16;
920cb1dc 179 if(flag & FLAG_SALT)
7600b65f 180 salt = make_sha512_salt_para(saltpara);
920cb1dc 181 else
7600b65f 182 salt = make_sha512_salt(length);
920cb1dc 183 }
f1d07f6b
JT
184
185 if(flag & FLAG_PASS)
186 {
187 if(!plaintext)
011e38be
AI
188 {
189 fprintf(stderr, "Please enter a valid password\n");
190 return 1;
191 }
192
193 hashed = rb_crypt(plaintext, salt);
f1d07f6b
JT
194 }
195 else
196 {
6002ccec
AJ
197 plaintext = getpass("plaintext: ");
198 hashed = rb_crypt(plaintext, salt);
199 if (!hashed)
200 {
201 fprintf(stderr, "rb_crypt() failed\n");
202 return 1;
203 }
204 hashed = strdup(hashed);
205
011e38be 206 plaintext = getpass("again: ");
6002ccec
AJ
207 hashed2 = rb_crypt(plaintext, salt);
208 if (!hashed2)
209 {
210 fprintf(stderr, "rb_crypt() failed\n");
211 return 1;
212 }
011e38be 213
6002ccec 214 if (strcmp(hashed, hashed2) != 0)
011e38be
AI
215 {
216 fprintf(stderr, "Passwords do not match\n");
217 return 1;
218 }
f1d07f6b
JT
219 }
220
011e38be 221 printf("%s\n", hashed);
f1d07f6b 222 return 0;
212380e3
AC
223}
224
f1d07f6b
JT
225char *
226make_md5_salt_para(char *saltpara)
212380e3 227{
f1d07f6b
JT
228 static char salt[21];
229 if(saltpara && (strlen(saltpara) <= 16))
230 {
231 /* sprintf used because of portability requirements, the length
232 ** is checked above, so it should not be too much of a concern
233 */
234 sprintf(salt, "$1$%s$", saltpara);
235 return salt;
236 }
237 printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
238 exit(1);
239
240 /* NOT REACHED */
241 return NULL;
212380e3
AC
242}
243
f1d07f6b
JT
244char *
245make_md5_salt(int length)
212380e3 246{
f1d07f6b
JT
247 static char salt[21];
248 if(length > 16)
249 {
250 printf("MD5 salt length too long\n");
251 exit(0);
252 }
253 salt[0] = '$';
254 salt[1] = '1';
255 salt[2] = '$';
256 generate_random_salt(&salt[3], length);
257 salt[length + 3] = '$';
258 salt[length + 4] = '\0';
259 return salt;
212380e3
AC
260}
261
f1d07f6b
JT
262char *
263make_sha256_salt_para(char *saltpara)
212380e3 264{
f1d07f6b
JT
265 static char salt[21];
266 if(saltpara && (strlen(saltpara) <= 16))
267 {
268 /* sprintf used because of portability requirements, the length
269 ** is checked above, so it should not be too much of a concern
270 */
271 sprintf(salt, "$5$%s$", saltpara);
272 return salt;
273 }
274 printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
275 exit(1);
276
277 /* NOT REACHED */
278 return NULL;
212380e3
AC
279}
280
f1d07f6b
JT
281char *
282make_sha512_salt_para(char *saltpara)
212380e3 283{
f1d07f6b
JT
284 static char salt[21];
285 if(saltpara && (strlen(saltpara) <= 16))
286 {
287 /* sprintf used because of portability requirements, the length
288 ** is checked above, so it should not be too much of a concern
289 */
290 sprintf(salt, "$6$%s$", saltpara);
291 return salt;
292 }
293 printf("Invalid Salt, please use up to 16 random alphanumeric characters\n");
294 exit(1);
295
296 /* NOT REACHED */
297 return NULL;
212380e3
AC
298}
299
f1d07f6b
JT
300
301char *
302make_sha256_salt(int length)
212380e3 303{
f1d07f6b
JT
304 static char salt[21];
305 if(length > 16)
306 {
307 printf("SHA256 salt length too long\n");
308 exit(0);
309 }
310 salt[0] = '$';
311 salt[1] = '5';
312 salt[2] = '$';
313 generate_random_salt(&salt[3], length);
314 salt[length + 3] = '$';
315 salt[length + 4] = '\0';
316 return salt;
317}
318
319char *
320make_sha512_salt(int length)
321{
322 static char salt[21];
323 if(length > 16)
324 {
325 printf("SHA512 salt length too long\n");
326 exit(0);
327 }
328 salt[0] = '$';
329 salt[1] = '6';
330 salt[2] = '$';
331 generate_random_salt(&salt[3], length);
332 salt[length + 3] = '$';
333 salt[length + 4] = '\0';
334 return salt;
335}
336
337char *
338make_bf_salt_para(int rounds, char *saltpara)
339{
340 static char salt[31];
341 char tbuf[3];
342 if(saltpara && (strlen(saltpara) <= 22))
343 {
344 /* sprintf used because of portability requirements, the length
345 ** is checked above, so it should not be too much of a concern
346 */
347 sprintf(tbuf, "%02d", rounds);
348 sprintf(salt, "$2a$%s$%s$", tbuf, saltpara);
349 return salt;
350 }
351 printf("Invalid Salt, please use up to 22 random alphanumeric characters\n");
352 exit(1);
353
354 /* NOT REACHED */
355 return NULL;
356}
357
358char *
359make_bf_salt(int rounds, int length)
360{
361 static char salt[31];
362 char tbuf[3];
363 if(length > 22)
364 {
69b2e745 365 printf("Blowfish salt length too long\n");
f1d07f6b
JT
366 exit(0);
367 }
368 sprintf(tbuf, "%02d", rounds);
369 sprintf(salt, "$2a$%s$", tbuf);
370 generate_random_salt(&salt[7], length);
371 salt[length + 7] = '$';
372 salt[length + 8] = '\0';
373 return salt;
374}
375
376char *
377generate_poor_salt(char *salt, int length)
378{
379 int i;
380 srand(time(NULL));
381 for(i = 0; i < length; i++)
382 {
383 salt[i] = saltChars[rand() % 64];
384 }
385 return (salt);
386}
387
388char *
389generate_random_salt(char *salt, int length)
390{
391 char *buf;
392 int fd, i;
393 if((fd = open("/dev/random", O_RDONLY)) < 0)
394 {
395 return (generate_poor_salt(salt, length));
396 }
397 buf = calloc(1, length);
398 if(read(fd, buf, length) != length)
399 {
400 free(buf);
401 return (generate_poor_salt(salt, length));
402 }
403
404 for(i = 0; i < length; i++)
405 {
406 salt[i] = saltChars[abs(buf[i]) % 64];
407 }
408 free(buf);
409 return (salt);
212380e3
AC
410}
411
f1d07f6b
JT
412void
413full_usage()
212380e3 414{
8522eb3b 415 printf("mkpasswd [-m|-b|-x|-y] [-l saltlength] [-r rounds] [-s salt] [-p plaintext]\n");
f1d07f6b
JT
416 printf("-x Generate a SHA256 password\n");
417 printf("-y Generate a SHA512 password\n");
418 printf("-m Generate an MD5 password\n");
69b2e745 419 printf("-b Generate a Blowfish password\n");
69b2e745 420 printf("-l Specify a length for a random MD5 or Blowfish salt\n");
8522eb3b
EM
421 printf("-r Specify a number of rounds for a Blowfish password\n");
422 printf(" Default 4, no more than 6 recommended\n");
423 printf("-s Specify a salt, up to 16 for MD5, SHA256, and SHA512\n");
424 printf(" up to 22 for Blowfish\n");
f1d07f6b
JT
425 printf("-p Specify a plaintext password to use\n");
426 printf("Example: mkpasswd -m -s 3dr -p test\n");
427 exit(0);
212380e3
AC
428}
429
f1d07f6b
JT
430void
431brief_usage()
212380e3 432{
f1d07f6b 433 printf("mkpasswd - password hash generator\n");
8522eb3b
EM
434 printf(" SHA512: mkpasswd [-y] [-l saltlength] [-s salt] [-p plaintext]\n");
435 printf(" SHA256: mkpasswd -x [-l saltlength] [-s salt] [-p plaintext]\n");
436 printf(" MD5: mkpasswd -m [-l saltlength] [-s salt] [-p plaintext]\n");
437 printf("Blowfish: mkpasswd -b [-r rounds] [-l saltlength] [-s salt]\n");
438 printf(" [-p plaintext]\n");
f1d07f6b
JT
439 printf("Use -h for full usage\n");
440 exit(0);
212380e3 441}