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