10b0ecb56SDag-Erling Smørgrav /*
2402783abSDag-Erling Smørgrav * Copyright (c) 2000-2002 by Solar Designer. See LICENSE.
30b0ecb56SDag-Erling Smørgrav */
40b0ecb56SDag-Erling Smørgrav
50b0ecb56SDag-Erling Smørgrav #include <stdio.h>
60b0ecb56SDag-Erling Smørgrav #include <string.h>
70b0ecb56SDag-Erling Smørgrav #include <unistd.h>
80b0ecb56SDag-Erling Smørgrav #include <errno.h>
90b0ecb56SDag-Erling Smørgrav #include <fcntl.h>
100b0ecb56SDag-Erling Smørgrav
110b0ecb56SDag-Erling Smørgrav #include "passwdqc.h"
120b0ecb56SDag-Erling Smørgrav
130b0ecb56SDag-Erling Smørgrav #define SEPARATORS "_,.;:-!&"
140b0ecb56SDag-Erling Smørgrav
read_loop(int fd,char * buffer,int count)150b0ecb56SDag-Erling Smørgrav static int read_loop(int fd, char *buffer, int count)
160b0ecb56SDag-Erling Smørgrav {
170b0ecb56SDag-Erling Smørgrav int offset, block;
180b0ecb56SDag-Erling Smørgrav
190b0ecb56SDag-Erling Smørgrav offset = 0;
200b0ecb56SDag-Erling Smørgrav while (count > 0) {
210b0ecb56SDag-Erling Smørgrav block = read(fd, &buffer[offset], count);
220b0ecb56SDag-Erling Smørgrav
230b0ecb56SDag-Erling Smørgrav if (block < 0) {
240b0ecb56SDag-Erling Smørgrav if (errno == EINTR) continue;
250b0ecb56SDag-Erling Smørgrav return block;
260b0ecb56SDag-Erling Smørgrav }
270b0ecb56SDag-Erling Smørgrav if (!block) return offset;
280b0ecb56SDag-Erling Smørgrav
290b0ecb56SDag-Erling Smørgrav offset += block;
300b0ecb56SDag-Erling Smørgrav count -= block;
310b0ecb56SDag-Erling Smørgrav }
320b0ecb56SDag-Erling Smørgrav
330b0ecb56SDag-Erling Smørgrav return offset;
340b0ecb56SDag-Erling Smørgrav }
350b0ecb56SDag-Erling Smørgrav
_passwdqc_random(passwdqc_params_t * params)360b0ecb56SDag-Erling Smørgrav char *_passwdqc_random(passwdqc_params_t *params)
370b0ecb56SDag-Erling Smørgrav {
380b0ecb56SDag-Erling Smørgrav static char output[0x100];
390b0ecb56SDag-Erling Smørgrav int bits;
40402783abSDag-Erling Smørgrav int use_separators, count, i;
41402783abSDag-Erling Smørgrav unsigned int length;
420b0ecb56SDag-Erling Smørgrav char *start, *end;
430b0ecb56SDag-Erling Smørgrav int fd;
440b0ecb56SDag-Erling Smørgrav unsigned char bytes[2];
450b0ecb56SDag-Erling Smørgrav
460b0ecb56SDag-Erling Smørgrav if (!(bits = params->random_bits))
470b0ecb56SDag-Erling Smørgrav return NULL;
480b0ecb56SDag-Erling Smørgrav
490b0ecb56SDag-Erling Smørgrav count = 1 + ((bits - 12) + 14) / 15;
500b0ecb56SDag-Erling Smørgrav use_separators = ((bits + 11) / 12 != count);
510b0ecb56SDag-Erling Smørgrav
520b0ecb56SDag-Erling Smørgrav length = count * 7 - 1;
53402783abSDag-Erling Smørgrav if (length >= sizeof(output) || (int)length > params->max)
54402783abSDag-Erling Smørgrav return NULL;
550b0ecb56SDag-Erling Smørgrav
560b0ecb56SDag-Erling Smørgrav if ((fd = open("/dev/urandom", O_RDONLY)) < 0) return NULL;
570b0ecb56SDag-Erling Smørgrav
580b0ecb56SDag-Erling Smørgrav length = 0;
590b0ecb56SDag-Erling Smørgrav do {
600b0ecb56SDag-Erling Smørgrav if (read_loop(fd, bytes, sizeof(bytes)) != sizeof(bytes)) {
610b0ecb56SDag-Erling Smørgrav close(fd);
620b0ecb56SDag-Erling Smørgrav return NULL;
630b0ecb56SDag-Erling Smørgrav }
640b0ecb56SDag-Erling Smørgrav
65402783abSDag-Erling Smørgrav i = (((int)bytes[1] & 0x0f) << 8) | (int)bytes[0];
66402783abSDag-Erling Smørgrav start = _passwdqc_wordset_4k[i];
670b0ecb56SDag-Erling Smørgrav end = memchr(start, '\0', 6);
680b0ecb56SDag-Erling Smørgrav if (!end) end = start + 6;
690b0ecb56SDag-Erling Smørgrav if (length + (end - start) >= sizeof(output) - 1) {
700b0ecb56SDag-Erling Smørgrav close(fd);
710b0ecb56SDag-Erling Smørgrav return NULL;
720b0ecb56SDag-Erling Smørgrav }
730b0ecb56SDag-Erling Smørgrav memcpy(&output[length], start, end - start);
740b0ecb56SDag-Erling Smørgrav length += end - start;
750b0ecb56SDag-Erling Smørgrav bits -= 12;
760b0ecb56SDag-Erling Smørgrav
770b0ecb56SDag-Erling Smørgrav if (use_separators && bits > 3) {
78402783abSDag-Erling Smørgrav i = ((int)bytes[1] & 0x70) >> 4;
79402783abSDag-Erling Smørgrav output[length++] = SEPARATORS[i];
800b0ecb56SDag-Erling Smørgrav bits -= 3;
810b0ecb56SDag-Erling Smørgrav } else
820b0ecb56SDag-Erling Smørgrav if (bits > 0)
830b0ecb56SDag-Erling Smørgrav output[length++] = ' ';
840b0ecb56SDag-Erling Smørgrav } while (bits > 0);
850b0ecb56SDag-Erling Smørgrav
860b0ecb56SDag-Erling Smørgrav memset(bytes, 0, sizeof(bytes));
870b0ecb56SDag-Erling Smørgrav output[length] = '\0';
880b0ecb56SDag-Erling Smørgrav
890b0ecb56SDag-Erling Smørgrav close(fd);
900b0ecb56SDag-Erling Smørgrav
910b0ecb56SDag-Erling Smørgrav return output;
920b0ecb56SDag-Erling Smørgrav }
93