1 /* 2 * Copyright (c) 2000-2002 by Solar Designer. See LICENSE. 3 */ 4 5 #include <stdio.h> 6 #include <string.h> 7 #include <unistd.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 11 #include "passwdqc.h" 12 13 #define SEPARATORS "_,.;:-!&" 14 15 static int read_loop(int fd, char *buffer, int count) 16 { 17 int offset, block; 18 19 offset = 0; 20 while (count > 0) { 21 block = read(fd, &buffer[offset], count); 22 23 if (block < 0) { 24 if (errno == EINTR) continue; 25 return block; 26 } 27 if (!block) return offset; 28 29 offset += block; 30 count -= block; 31 } 32 33 return offset; 34 } 35 36 char *_passwdqc_random(passwdqc_params_t *params) 37 { 38 static char output[0x100]; 39 int bits; 40 int use_separators, count, i; 41 unsigned int length; 42 char *start, *end; 43 int fd; 44 unsigned char bytes[2]; 45 46 if (!(bits = params->random_bits)) 47 return NULL; 48 49 count = 1 + ((bits - 12) + 14) / 15; 50 use_separators = ((bits + 11) / 12 != count); 51 52 length = count * 7 - 1; 53 if (length >= sizeof(output) || (int)length > params->max) 54 return NULL; 55 56 if ((fd = open("/dev/urandom", O_RDONLY)) < 0) return NULL; 57 58 length = 0; 59 do { 60 if (read_loop(fd, bytes, sizeof(bytes)) != sizeof(bytes)) { 61 close(fd); 62 return NULL; 63 } 64 65 i = (((int)bytes[1] & 0x0f) << 8) | (int)bytes[0]; 66 start = _passwdqc_wordset_4k[i]; 67 end = memchr(start, '\0', 6); 68 if (!end) end = start + 6; 69 if (length + (end - start) >= sizeof(output) - 1) { 70 close(fd); 71 return NULL; 72 } 73 memcpy(&output[length], start, end - start); 74 length += end - start; 75 bits -= 12; 76 77 if (use_separators && bits > 3) { 78 i = ((int)bytes[1] & 0x70) >> 4; 79 output[length++] = SEPARATORS[i]; 80 bits -= 3; 81 } else 82 if (bits > 0) 83 output[length++] = ' '; 84 } while (bits > 0); 85 86 memset(bytes, 0, sizeof(bytes)); 87 output[length] = '\0'; 88 89 close(fd); 90 91 return output; 92 } 93