documented fix
[gnutls.git] / lib / nettle / egd.c
blobb1886d40408ef11b8ce5aef699f0c0f8bdb30dbd
1 /* rndegd.c - interface to the EGD
2 * Copyright (C) 1999, 2000, 2002, 2003, 2010 Free Software Foundation, Inc.
4 * This file is part of Libgcrypt.
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.
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.
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
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <errno.h>
25 #include <sys/time.h>
26 #include <sys/stat.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include "egd.h"
34 #include <gnutls_errors.h>
36 #ifndef offsetof
37 #define offsetof(type, member) ((size_t) &((type *)0)->member)
38 #endif
40 static int egd_socket = -1;
42 static int
43 do_write (int fd, void *buf, size_t nbytes)
45 size_t nleft = nbytes;
46 int nwritten;
48 while (nleft > 0)
50 nwritten = write (fd, buf, nleft);
51 if (nwritten < 0)
53 if (errno == EINTR)
54 continue;
55 return -1;
57 nleft -= nwritten;
58 buf = (char *) buf + nwritten;
60 return 0;
63 static int
64 do_read (int fd, void *buf, size_t nbytes)
66 int n, nread = 0;
72 n = read (fd, (char *) buf + nread, nbytes);
74 while (n == -1 && errno == EINTR);
75 if (n == -1)
76 return nread ? nread : -1;
77 if (n == 0)
78 return -1;
79 nread += n;
80 nbytes -= n;
82 while (nread < nbytes);
83 return nread;
86 static const char *egd_names[] = {
87 "/var/run/egd-pool",
88 "/dev/egd-pool",
89 "/etc/egd-pool",
90 "/etc/entropy",
91 "/var/run/entropy",
92 "/dev/entropy",
93 NULL
96 static const char *
97 find_egd_name (void)
99 int i = 0;
100 struct stat st;
104 if (stat (egd_names[i], &st) != 0)
105 continue;
107 if (st.st_mode & S_IFSOCK)
108 { /* found */
109 return egd_names[i];
113 while (egd_names[++i] != NULL);
115 return NULL;
118 /* Connect to the EGD and return the file descriptor. Return -1 on
119 error. With NOFAIL set to true, silently fail and return the
120 error, otherwise print an error message and die. */
122 _rndegd_connect_socket (void)
124 int fd;
125 const char *name;
126 struct sockaddr_un addr;
127 int addr_len;
129 if (egd_socket != -1)
131 close (egd_socket);
132 egd_socket = -1;
135 name = find_egd_name ();
137 if (strlen (name) + 1 >= sizeof addr.sun_path)
139 _gnutls_debug_log ("EGD socketname is too long\n");
140 return -1;
143 memset (&addr, 0, sizeof addr);
144 addr.sun_family = AF_LOCAL;
145 strcpy (addr.sun_path, name);
146 addr_len = (offsetof (struct sockaddr_un, sun_path)
147 + strlen (addr.sun_path));
149 fd = socket (AF_LOCAL, SOCK_STREAM, 0);
150 if (fd == -1)
152 _gnutls_debug_log ("can't create unix domain socket: %s\n",
153 strerror (errno));
154 return -1;
156 else if (connect (fd, (struct sockaddr *) &addr, addr_len) == -1)
158 _gnutls_debug_log ("can't connect to EGD socket `%s': %s\n",
159 name, strerror (errno));
160 close (fd);
161 fd = -1;
164 if (fd != -1)
165 egd_socket = fd;
166 return fd;
169 /****************
170 * Note: We always use the highest level.
171 * To boost the performance we may want to add some
172 * additional code for level 1
174 * Using a level of 0 should never block and better add nothing
175 * to the pool. So this is just a dummy for EGD.
178 _rndegd_read (int *fd, void *_output, size_t _length)
180 int n;
181 uint8_t buffer[256 + 2];
182 int nbytes;
183 int do_restart = 0;
184 unsigned char *output = _output;
185 size_t length = _length;
187 if (!length)
188 return 0;
191 restart:
192 if (*fd == -1 || do_restart)
193 *fd = _rndegd_connect_socket ();
195 do_restart = 0;
197 nbytes = length < 255 ? length : 255;
198 /* First time we do it with a non blocking request */
199 buffer[0] = 1; /* non blocking */
200 buffer[1] = nbytes;
202 if (do_write (*fd, buffer, 2) == -1)
203 _gnutls_debug_log ("can't write to the EGD: %s\n", strerror (errno));
205 n = do_read (*fd, buffer, 1);
206 if (n == -1)
208 _gnutls_debug_log ("read error on EGD: %s\n", strerror (errno));
209 do_restart = 1;
210 goto restart;
213 n = buffer[0];
214 if (n)
216 n = do_read (*fd, buffer, n);
217 if (n == -1)
219 _gnutls_debug_log ("read error on EGD: %s\n", strerror (errno));
220 do_restart = 1;
221 goto restart;
224 if (n > length)
226 _gnutls_debug_log ("read error on EGD: returned more bytes!\n");
227 n = length;
230 memcpy (output, buffer, n);
231 output += n;
232 length -= n;
235 while (length)
237 nbytes = length < 255 ? length : 255;
239 buffer[0] = 2; /* blocking */
240 buffer[1] = nbytes;
241 if (do_write (*fd, buffer, 2) == -1)
242 _gnutls_debug_log ("can't write to the EGD: %s\n", strerror (errno));
243 n = do_read (*fd, buffer, nbytes);
244 if (n == -1)
246 _gnutls_debug_log ("read error on EGD: %s\n", strerror (errno));
247 do_restart = 1;
248 goto restart;
251 if (n > length)
253 _gnutls_debug_log ("read error on EGD: returned more bytes!\n");
254 n = length;
257 memcpy (output, buffer, n);
258 output += n;
259 length -= n;
262 return _length; /* success */