Diffstat (limited to 'pwmanager/libcrypt/cipher/rndlinux.c') (more/less context) (ignore whitespace changes)
-rw-r--r-- | pwmanager/libcrypt/cipher/rndlinux.c | 141 |
1 files changed, 141 insertions, 0 deletions
diff --git a/pwmanager/libcrypt/cipher/rndlinux.c b/pwmanager/libcrypt/cipher/rndlinux.c new file mode 100644 index 0000000..fc608bc --- a/dev/null +++ b/pwmanager/libcrypt/cipher/rndlinux.c | |||
@@ -0,0 +1,141 @@ | |||
1 | /* rndlinux.c - raw random number for OSes with /dev/random | ||
2 | * Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. | ||
3 | * | ||
4 | * This file is part of Libgcrypt. | ||
5 | * | ||
6 | * Libgcrypt is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU Lesser General Public License as | ||
8 | * published by the Free Software Foundation; either version 2.1 of | ||
9 | * the License, or (at your option) any later version. | ||
10 | * | ||
11 | * Libgcrypt is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU Lesser General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU Lesser General Public | ||
17 | * License along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
19 | */ | ||
20 | |||
21 | |||
22 | #include <config.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <assert.h> | ||
26 | #include <errno.h> | ||
27 | #include <sys/time.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <sys/stat.h> | ||
30 | #ifdef HAVE_GETTIMEOFDAY | ||
31 | # include <sys/times.h> | ||
32 | #endif | ||
33 | #include <string.h> | ||
34 | #include <unistd.h> | ||
35 | #include <fcntl.h> | ||
36 | #include "types.h" | ||
37 | #include "g10lib.h" | ||
38 | #include "rand-internal.h" | ||
39 | |||
40 | static int open_device( const char *name, int minor ); | ||
41 | int _gcry_rndlinux_gather_random (void (*add)(const void*, size_t, int), | ||
42 | int requester, | ||
43 | size_t length, int level ); | ||
44 | |||
45 | /* | ||
46 | * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)). | ||
47 | */ | ||
48 | static int | ||
49 | open_device( const char *name, int minor ) | ||
50 | { | ||
51 | int fd; | ||
52 | |||
53 | fd = open( name, O_RDONLY ); | ||
54 | if( fd == -1 ) | ||
55 | log_fatal ("can't open %s: %s\n", name, strerror(errno) ); | ||
56 | |||
57 | /* We used to do the follwing check, however it turned out that this | ||
58 | is not portable since more OSes provide a random device which is | ||
59 | sometimes implemented as anoteher device type. | ||
60 | |||
61 | struct stat sb; | ||
62 | |||
63 | if( fstat( fd, &sb ) ) | ||
64 | log_fatal("stat() off %s failed: %s\n", name, strerror(errno) ); | ||
65 | if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) ) | ||
66 | log_fatal("invalid random device!\n" ); | ||
67 | */ | ||
68 | return fd; | ||
69 | } | ||
70 | |||
71 | |||
72 | int | ||
73 | _gcry_rndlinux_gather_random (void (*add)(const void*, size_t, int), | ||
74 | int requester, | ||
75 | size_t length, int level ) | ||
76 | { | ||
77 | static int fd_urandom = -1; | ||
78 | static int fd_random = -1; | ||
79 | int fd; | ||
80 | int n; | ||
81 | int warn=0; | ||
82 | byte buffer[768]; | ||
83 | |||
84 | if( level >= 2 ) | ||
85 | { | ||
86 | if( fd_random == -1 ) | ||
87 | fd_random = open_device( NAME_OF_DEV_RANDOM, 8 ); | ||
88 | fd = fd_random; | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | if( fd_urandom == -1 ) | ||
93 | fd_urandom = open_device( NAME_OF_DEV_URANDOM, 9 ); | ||
94 | fd = fd_urandom; | ||
95 | } | ||
96 | |||
97 | while (length) | ||
98 | { | ||
99 | fd_set rfds; | ||
100 | struct timeval tv; | ||
101 | int rc; | ||
102 | |||
103 | FD_ZERO(&rfds); | ||
104 | FD_SET(fd, &rfds); | ||
105 | tv.tv_sec = 3; | ||
106 | tv.tv_usec = 0; | ||
107 | if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) | ||
108 | { | ||
109 | if( !warn ) | ||
110 | { | ||
111 | _gcry_random_progress ("need_entropy", 'X', 0, (int)length); | ||
112 | warn = 1; | ||
113 | } | ||
114 | continue; | ||
115 | } | ||
116 | else if( rc == -1 ) | ||
117 | { | ||
118 | log_error ("select() error: %s\n", strerror(errno)); | ||
119 | continue; | ||
120 | } | ||
121 | |||
122 | do | ||
123 | { | ||
124 | int nbytes = length < sizeof(buffer)? length : sizeof(buffer); | ||
125 | n = read(fd, buffer, nbytes ); | ||
126 | if( n >= 0 && n > nbytes ) | ||
127 | { | ||
128 | log_error("bogus read from random device (n=%d)\n", n ); | ||
129 | n = nbytes; | ||
130 | } | ||
131 | } | ||
132 | while( n == -1 && errno == EINTR ); | ||
133 | if( n == -1 ) | ||
134 | log_fatal("read error on random device: %s\n", strerror(errno)); | ||
135 | (*add)( buffer, n, requester ); | ||
136 | length -= n; | ||
137 | } | ||
138 | memset(buffer, 0, sizeof(buffer) ); | ||
139 | |||
140 | return 0; /* success */ | ||
141 | } | ||