21ea8c4ba33f6e33f13b34b79a564b08a885a719
[libgcrypt.git] / random / rndlinux.c
1 /* rndlinux.c  -  raw random number for OSes with /dev/random
2  * Copyright (C) 1998, 2001, 2002, 2003, 2007,
3  *               2009  Free Software Foundation, Inc.
4  *
5  * This file is part of Libgcrypt.
6  *
7  * Libgcrypt is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation; either version 2.1 of
10  * the License, or (at your option) any later version.
11  *
12  * Libgcrypt is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <errno.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #ifdef HAVE_GETTIMEOFDAY
30 # include <sys/times.h>
31 #endif
32 #include <string.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include "types.h"
36 #include "g10lib.h"
37 #include "rand-internal.h"
38
39 static int open_device (const char *name, int retry);
40
41
42 static int
43 set_cloexec_flag (int fd)
44 {
45   int oldflags;
46
47   oldflags= fcntl (fd, F_GETFD, 0);
48   if (oldflags < 0)
49     return oldflags;
50   oldflags |= FD_CLOEXEC;
51   return fcntl (fd, F_SETFD, oldflags);
52 }
53
54
55
56 /*
57  * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it
58  * exists)).  If RETRY is true, the function does not terminate with
59  * a fatal error but retries until it is able to reopen the device.
60  */
61 static int
62 open_device (const char *name, int retry)
63 {
64   int fd;
65
66   if (retry)
67     _gcry_random_progress ("open_dev_random", 'X', 1, 0);
68  again:
69   fd = open (name, O_RDONLY);
70   if (fd == -1 && retry)
71     {
72       struct timeval tv;
73
74       tv.tv_sec = 5;
75       tv.tv_usec = 0;
76       _gcry_random_progress ("wait_dev_random", 'X', 0, (int)tv.tv_sec);
77       select (0, NULL, NULL, NULL, &tv);
78       goto again;
79     }
80   if (fd == -1)
81     log_fatal ("can't open %s: %s\n", name, strerror(errno) );
82
83   if (set_cloexec_flag (fd))
84     log_error ("error setting FD_CLOEXEC on fd %d: %s\n",
85                fd, strerror (errno));
86
87   /* We used to do the following check, however it turned out that this
88      is not portable since more OSes provide a random device which is
89      sometimes implemented as another device type.
90
91      struct stat sb;
92
93      if( fstat( fd, &sb ) )
94         log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
95      if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
96         log_fatal("invalid random device!\n" );
97   */
98   return fd;
99 }
100
101
102 /* Note that the caller needs to make sure that this function is only
103    called by one thread at a time.  The function returns 0 on success
104    or true on failure (in which case the caller will signal a fatal
105    error).  */
106 int
107 _gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
108                                           enum random_origins),
109                               enum random_origins origin,
110                               size_t length, int level )
111 {
112   static int fd_urandom = -1;
113   static int fd_random = -1;
114   static unsigned char ever_opened;
115   int fd;
116   int n;
117   byte buffer[768];
118   size_t n_hw;
119   size_t want = length;
120   size_t last_so_far = 0;
121   int any_need_entropy = 0;
122   int delay;
123
124   if (!add)
125     {
126       /* Special mode to close the descriptors.  */
127       if (fd_random != -1)
128         {
129           close (fd_random);
130           fd_random = -1;
131         }
132       if (fd_urandom != -1)
133         {
134           close (fd_urandom);
135           fd_urandom = -1;
136         }
137       return 0;
138     }
139
140
141   /* First read from a hardware source.  However let it account only
142      for up to 50% of the requested bytes.  */
143   n_hw = _gcry_rndhw_poll_slow (add, origin);
144   if (n_hw > length/2)
145     n_hw = length/2;
146   if (length > 1)
147     length -= n_hw;
148
149   /* Open the requested device.  The first time a device is to be
150      opened we fail with a fatal error if the device does not exists.
151      In case the device has ever been closed, further open requests
152      will however retry indefinitely.  The rationale for this behaviour is
153      that we always require the device to be existent but want a more
154      graceful behaviour if the rarely needed close operation has been
155      used and the device needs to be re-opened later. */
156   if (level >= 2)
157     {
158       if (fd_random == -1)
159         {
160           fd_random = open_device (NAME_OF_DEV_RANDOM, (ever_opened & 1));
161           ever_opened |= 1;
162         }
163       fd = fd_random;
164     }
165   else
166     {
167       if (fd_urandom == -1)
168         {
169           fd_urandom = open_device (NAME_OF_DEV_URANDOM, (ever_opened & 2));
170           ever_opened |= 2;
171         }
172       fd = fd_urandom;
173     }
174
175   /* Enter the read loop.  */
176   delay = 0;  /* Start with 0 seconds so that we do no block on the
177                  first iteration and in turn call the progress function
178                  before blocking.  To give the OS a better chance to
179                  return with something we will actually use 100ms. */
180   while (length)
181     {
182       fd_set rfds;
183       struct timeval tv;
184       int rc;
185
186       /* If the system has no limit on the number of file descriptors
187          and we encounter an fd which is larger than the fd_set size,
188          we don't use the select at all.  The select code is only used
189          to emit progress messages.  A better solution would be to
190          fall back to poll() if available.  */
191 #ifdef FD_SETSIZE
192       if (fd < FD_SETSIZE)
193 #endif
194         {
195           FD_ZERO(&rfds);
196           FD_SET(fd, &rfds);
197           tv.tv_sec = delay;
198           tv.tv_usec = delay? 0 : 100000;
199           if ( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) )
200             {
201               if (!any_need_entropy || last_so_far != (want - length) )
202                 {
203                   last_so_far = want - length;
204                   _gcry_random_progress ("need_entropy", 'X',
205                                          (int)last_so_far, (int)want);
206                   any_need_entropy = 1;
207                 }
208               delay = 3; /* Use 3 seconds henceforth.  */
209               continue;
210             }
211           else if( rc == -1 )
212             {
213               log_error ("select() error: %s\n", strerror(errno));
214               if (!delay)
215                 delay = 1; /* Use 1 second if we encounter an error before
216                               we have ever blocked.  */
217               continue;
218             }
219         }
220
221       do
222         {
223           int nbytes = length < sizeof(buffer)? length : sizeof(buffer);
224           n = read(fd, buffer, nbytes );
225           if( n >= 0 && n > nbytes )
226             {
227               log_error("bogus read from random device (n=%d)\n", n );
228               n = nbytes;
229             }
230         }
231       while( n == -1 && errno == EINTR );
232       if ( n == -1 )
233         log_fatal("read error on random device: %s\n", strerror(errno));
234       (*add)( buffer, n, origin );
235       length -= n;
236     }
237   memset(buffer, 0, sizeof(buffer) );
238
239   if (any_need_entropy)
240     _gcry_random_progress ("need_entropy", 'X', (int)want, (int)want);
241
242   return 0; /* success */
243 }