New cofiguration for Unixwre and SCO,with slightly better granularity. Contributed...
[openssl.git] / crypto / rand / rand_egd.c
1 /* crypto/rand/rand_egd.c */
2 /* Written by Ulf Moeller and Lutz Jaenicke for the OpenSSL project. */
3 /* ====================================================================
4  * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer. 
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * 3. All advertising materials mentioning features or use of this
19  *    software must display the following acknowledgment:
20  *    "This product includes software developed by the OpenSSL Project
21  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
22  *
23  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
24  *    endorse or promote products derived from this software without
25  *    prior written permission. For written permission, please contact
26  *    openssl-core@openssl.org.
27  *
28  * 5. Products derived from this software may not be called "OpenSSL"
29  *    nor may "OpenSSL" appear in their names without prior written
30  *    permission of the OpenSSL Project.
31  *
32  * 6. Redistributions of any form whatsoever must retain the following
33  *    acknowledgment:
34  *    "This product includes software developed by the OpenSSL Project
35  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
36  *
37  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
38  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
40  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
43  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48  * OF THE POSSIBILITY OF SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This product includes cryptographic software written by Eric Young
52  * (eay@cryptsoft.com).  This product includes software written by Tim
53  * Hudson (tjh@cryptsoft.com).
54  *
55  */
56
57 #include <openssl/rand.h>
58
59 /*
60  * Query the EGD <URL: http://www.lothar.com/tech/crypto/>.
61  *
62  * This module supplies three routines:
63  *
64  * RAND_query_egd_bytes(path, buf, bytes)
65  *   will actually query "bytes" bytes of entropy form the egd-socket located
66  *   at path and will write them to buf (if supplied) or will directly feed
67  *   it to RAND_seed() if buf==NULL.
68  *   The number of bytes is not limited by the maximum chunk size of EGD,
69  *   which is 255 bytes. If more than 255 bytes are wanted, several chunks
70  *   of entropy bytes are requested. The connection is left open until the
71  *   query is competed.
72  *   RAND_query_egd_bytes() returns with
73  *     -1  if an error occured during connection or communication.
74  *     num the number of bytes read from the EGD socket. This number is either
75  *         the number of bytes requested or smaller, if the EGD pool is
76  *         drained and the daemon signals that the pool is empty.
77  *   This routine does not touch any RAND_status(). This is necessary, since
78  *   PRNG functions may call it during initialization.
79  *
80  * RAND_egd_bytes(path, bytes) will query "bytes" bytes and have them
81  *   used to seed the PRNG.
82  *   RAND_egd_bytes() is a wrapper for RAND_query_egd_bytes() with buf=NULL.
83  *   Unlike RAND_query_egd_bytes(), RAND_status() is used to test the
84  *   seed status so that the return value can reflect the seed state:
85  *     -1  if an error occured during connection or communication _or_
86  *         if the PRNG has still not received the required seeding.
87  *     num the number of bytes read from the EGD socket. This number is either
88  *         the number of bytes requested or smaller, if the EGD pool is
89  *         drained and the daemon signals that the pool is empty.
90  *
91  * RAND_egd(path) will query 255 bytes and use the bytes retreived to seed
92  *   the PRNG.
93  *   RAND_egd() is a wrapper for RAND_egd_bytes() with numbytes=255.
94  */
95
96 #if defined(OPENSSL_SYS_WIN32) || defined(VMS) || defined(__VMS)
97 int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
98         {
99         return(-1);
100         }
101 int RAND_egd(const char *path)
102         {
103         return(-1);
104         }
105
106 int RAND_egd_bytes(const char *path,int bytes)
107         {
108         return(-1);
109         }
110 #else
111 #include <openssl/opensslconf.h>
112 #include OPENSSL_UNISTD
113 #include <sys/types.h>
114 #include <sys/socket.h>
115 #ifndef NO_SYS_UN_H
116 #include <sys/un.h>
117 #else
118 struct  sockaddr_un {
119         short   sun_family;             /* AF_UNIX */
120         char    sun_path[108];          /* path name (gag) */
121 };
122 #endif /* NO_SYS_UN_H */
123 #include <string.h>
124 #include <errno.h>
125
126 #ifndef offsetof
127 #  define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
128 #endif
129
130 int RAND_query_egd_bytes(const char *path, unsigned char *buf, int bytes)
131         {
132         int ret = 0;
133         struct sockaddr_un addr;
134         int len, num, numbytes;
135         int fd = -1;
136         int success;
137         unsigned char egdbuf[2], tempbuf[255], *retrievebuf;
138
139         memset(&addr, 0, sizeof(addr));
140         addr.sun_family = AF_UNIX;
141         if (strlen(path) > sizeof(addr.sun_path))
142                 return (-1);
143         strcpy(addr.sun_path,path);
144         len = offsetof(struct sockaddr_un, sun_path) + strlen(path);
145         fd = socket(AF_UNIX, SOCK_STREAM, 0);
146         if (fd == -1) return (-1);
147         success = 0;
148         while (!success)
149             {
150             if (connect(fd, (struct sockaddr *)&addr, len) == 0)
151                success = 1;
152             else
153                 {
154                 switch (errno)
155                     {
156 #ifdef EINTR
157                     case EINTR:
158 #endif
159 #ifdef EAGAIN
160                     case EAGAIN:
161 #endif
162 #ifdef EINPROGRESS
163                     case EINPROGRESS:
164 #endif
165 #ifdef EALREADY
166                     case EALREADY:
167 #endif
168                         /* No error, try again */
169                         break;
170 #ifdef EISCONN
171                     case EISCONN:
172                         success = 1;
173                         break;
174 #endif
175                     default:
176                         goto err;       /* failure */
177                     }
178                 }
179             }
180
181         while(bytes > 0)
182             {
183             egdbuf[0] = 1;
184             egdbuf[1] = bytes < 255 ? bytes : 255;
185             numbytes = 0;
186             while (numbytes != 2)
187                 {
188                 num = write(fd, egdbuf + numbytes, 2 - numbytes);
189                 if (num >= 0)
190                     numbytes += num;
191                 else
192                     {
193                     switch (errno)
194                         {
195 #ifdef EINTR
196                         case EINTR:
197 #endif
198 #ifdef EAGAIN
199                         case EAGAIN:
200 #endif
201                             /* No error, try again */
202                             break;
203                         default:
204                             ret = -1;
205                             goto err;   /* failure */
206                         }
207                     }
208                 }
209             numbytes = 0;
210             while (numbytes != 1)
211                 {
212                 num = read(fd, egdbuf, 1);
213                 if (num >= 0)
214                     numbytes += num;
215                 else
216                     {
217                     switch (errno)
218                         {
219 #ifdef EINTR
220                         case EINTR:
221 #endif
222 #ifdef EAGAIN
223                         case EAGAIN:
224 #endif
225                             /* No error, try again */
226                             break;
227                         default:
228                             ret = -1;
229                             goto err;   /* failure */
230                         }
231                     }
232                 }
233             if(egdbuf[0] == 0)
234                 goto err;
235             if (buf)
236                 retrievebuf = buf + ret;
237             else
238                 retrievebuf = tempbuf;
239             numbytes = 0;
240             while (numbytes != egdbuf[0])
241                 {
242                 num = read(fd, retrievebuf + numbytes, egdbuf[0] - numbytes);
243                 if (num >= 0)
244                     numbytes += num;
245                 else
246                     {
247                     switch (errno)
248                         {
249 #ifdef EINTR
250                         case EINTR:
251 #endif
252 #ifdef EAGAIN
253                         case EAGAIN:
254 #endif
255                             /* No error, try again */
256                             break;
257                         default:
258                             ret = -1;
259                             goto err;   /* failure */
260                         }
261                     }
262                 }
263             ret += egdbuf[0];
264             bytes -= egdbuf[0];
265             if (!buf)
266                 RAND_seed(tempbuf, egdbuf[0]);
267             }
268  err:
269         if (fd != -1) close(fd);
270         return(ret);
271         }
272
273
274 int RAND_egd_bytes(const char *path, int bytes)
275         {
276         int num, ret = 0;
277
278         num = RAND_query_egd_bytes(path, NULL, bytes);
279         if (num < 1) goto err;
280         if (RAND_status() == 1)
281             ret = num;
282  err:
283         return(ret);
284         }
285
286
287 int RAND_egd(const char *path)
288         {
289         return (RAND_egd_bytes(path, 255));
290         }
291
292
293 #endif