* random.c (_gcry_register_random_progress): New.
[libgcrypt.git] / cipher / rndlinux.c
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 #if 0
37   #ifdef HAVE_LINUX_RANDOM_H
38     #include <sys/ioctl.h>
39     #include <asm/types.h>
40     #include <linux/random.h>
41   #endif
42 #endif
43 #include "types.h"
44 #include "g10lib.h"
45 #include "dynload.h"
46 #include "rand-internal.h"
47
48 static int open_device( const char *name, int minor );
49 static int gather_random( void (*add)(const void*, size_t, int), int requester,
50                                           size_t length, int level );
51
52 #if 0
53 #ifdef HAVE_DEV_RANDOM_IOCTL
54 static ulong
55 get_entropy_count( int fd )
56 {
57     ulong count;
58
59     if( ioctl( fd, RNDGETENTCNT, &count ) == -1 )
60         log_fatal("ioctl(RNDGETENTCNT) failed: %s\n", strerror(errno) );
61     return count;
62 }
63 #endif
64 #endif
65
66 /****************
67  * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists), ...)
68  */
69 static int
70 open_device( const char *name, int minor )
71 {
72     int fd;
73     struct stat sb;
74
75     fd = open( name, O_RDONLY );
76     if( fd == -1 )
77         log_fatal("can't open %s: %s\n", name, strerror(errno) );
78     if( fstat( fd, &sb ) )
79         log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
80     /* Don't check device type for better portability */
81     /*  if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
82           log_fatal("invalid random device!\n" ); */
83     return fd;
84 }
85
86
87 static int
88 gather_random( void (*add)(const void*, size_t, int), int requester,
89                                           size_t length, int level )
90 {
91     static int fd_urandom = -1;
92     static int fd_random = -1;
93     int fd;
94     int n;
95     int warn=0;
96     byte buffer[768];
97
98     if( level >= 2 ) {
99         if( fd_random == -1 )
100             fd_random = open_device( NAME_OF_DEV_RANDOM, 8 );
101         fd = fd_random;
102     }
103     else {
104         if( fd_urandom == -1 )
105             fd_urandom = open_device( NAME_OF_DEV_URANDOM, 9 );
106         fd = fd_urandom;
107     }
108
109   #if 0
110   #ifdef HAVE_DEV_RANDOM_IOCTL
111     log_info("entropy count of %d is %lu\n", fd, get_entropy_count(fd) );
112   #endif
113   #endif
114     while( length ) {
115         fd_set rfds;
116         struct timeval tv;
117         int rc;
118
119         FD_ZERO(&rfds);
120         FD_SET(fd, &rfds);
121         tv.tv_sec = 3;
122         tv.tv_usec = 0;
123         if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) ) {
124           if( !warn )
125             {
126 #ifndef IS_MODULE
127               _gcry_random_progress ("need_entropy", 'X', 0, (int)length);
128 #else
129               log_info (_("not enough random bytes available (need %d bytes)\n"),
130                         (int)length);
131
132               log_info (_("please do some other work to give the OS a chance to collect more entropy\n"));
133 #endif
134             }
135               warn = 1;
136             continue;
137         }
138         else if( rc == -1 ) {
139             log_error ("select() error: %s\n", strerror(errno));
140             continue;
141         }
142
143         do {
144             int nbytes = length < sizeof(buffer)? length : sizeof(buffer);
145             n = read(fd, buffer, nbytes );
146             if( n >= 0 && n > nbytes ) {
147                 log_error("bogus read from random device (n=%d)\n", n );
148                 n = nbytes;
149             }
150         } while( n == -1 && errno == EINTR );
151         if( n == -1 )
152             log_fatal("read error on random device: %s\n", strerror(errno));
153         (*add)( buffer, n, requester );
154         length -= n;
155     }
156     memset(buffer, 0, sizeof(buffer) );
157
158     return 0; /* success */
159 }
160
161
162
163 #ifndef IS_MODULE
164 static
165 #endif
166 const char * const gnupgext_version = "RNDLINUX ($Revision$)";
167
168 static struct {
169     int class;
170     int version;
171     void *func;
172 } func_table[] = {
173     { 40, 1, gather_random },
174 };
175
176
177
178 /****************
179  * Enumerate the names of the functions together with informations about
180  * this function. Set sequence to an integer with a initial value of 0 and
181  * do not change it.
182  * If what is 0 all kind of functions are returned.
183  * Return values: class := class of function:
184  *                         10 = message digest algorithm info function
185  *                         11 = integer with available md algorithms
186  *                         20 = cipher algorithm info function
187  *                         21 = integer with available cipher algorithms
188  *                         30 = public key algorithm info function
189  *                         31 = integer with available pubkey algorithms
190  *                         40 = get gather_random function
191  *                         41 = get fast_random_poll function
192  *                version = interface version of the function/pointer
193  *                          (currently this is 1 for all functions)
194  */
195
196 #ifndef IS_MODULE
197 static
198 #endif
199 void *
200 gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
201 {
202     void *ret;
203     int i = *sequence;
204
205     do {
206         if ( i >= DIM(func_table) || i < 0 ) {
207             return NULL;
208         }
209         *class = func_table[i].class;
210         *vers  = func_table[i].version;
211         ret = func_table[i].func;
212         i++;
213     } while ( what && what != *class );
214
215     *sequence = i;
216     return ret;
217 }
218
219 #ifndef IS_MODULE
220 void
221 _gcry_rndlinux_constructor(void)
222 {
223     _gcry_register_internal_cipher_extension( gnupgext_version,
224                                         gnupgext_enum_func );
225 }
226 #endif
227