]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/apr/misc/unix/rand.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / apr / misc / unix / rand.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define APR_WANT_MEMFUNC
18 #include "apr_want.h"
19 #include "apr_general.h"
20
21 #include "apr_arch_misc.h"
22 #include <sys/stat.h>
23 #if APR_HAVE_SYS_TYPES_H
24 #include <sys/types.h>
25 #endif
26 #if APR_HAVE_SYS_SOCKET_H
27 #include <sys/socket.h>
28 #endif
29 #if APR_HAVE_FCNTL_H
30 #include <fcntl.h>
31 #endif
32 #if APR_HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35 #if APR_HAVE_SYS_UN_H
36 #include <sys/un.h>
37 #endif
38 #if defined(HAVE_UUID_H)
39 #include <uuid.h>
40 #elif defined(HAVE_UUID_UUID_H)
41 #include <uuid/uuid.h>
42 #elif defined(HAVE_SYS_UUID_H)
43 #include <sys/uuid.h>
44 #endif
45
46 #ifndef SHUT_RDWR
47 #define SHUT_RDWR 2
48 #endif
49
50 #if APR_HAS_OS_UUID
51
52 #if defined(HAVE_UUID_CREATE)
53
54 APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
55 {
56     uint32_t rv;
57     uuid_t g;
58
59     uuid_create(&g, &rv);
60
61     if (rv != uuid_s_ok)
62         return APR_EGENERAL;
63
64     memcpy(uuid_data, &g, sizeof(uuid_t));
65
66     return APR_SUCCESS;
67 }
68
69 #elif defined(HAVE_UUID_GENERATE)
70
71 APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
72 {
73     uuid_t g;
74
75     uuid_generate(g);
76
77     memcpy(uuid_data, g, sizeof(uuid_t));
78
79     return APR_SUCCESS;
80 }
81 #endif 
82
83 #endif /* APR_HAS_OS_UUID */
84
85 #if APR_HAS_RANDOM
86
87 APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf, 
88                                                     apr_size_t length)
89 {
90 #ifdef DEV_RANDOM
91
92     int fd = -1;
93
94     /* On BSD/OS 4.1, /dev/random gives out 8 bytes at a time, then
95      * gives EOF, so reading 'length' bytes may require opening the
96      * device several times. */
97     do {
98         apr_ssize_t rc;
99
100         if (fd == -1)
101             if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1)
102                 return errno;
103         
104         do {
105             rc = read(fd, buf, length);
106         } while (rc == -1 && errno == EINTR);
107
108         if (rc < 0) {
109             int errnum = errno;
110             close(fd);
111             return errnum;
112         }
113         else if (rc == 0) {
114             close(fd);
115             fd = -1; /* force open() again */
116         }
117         else {
118             buf += rc;
119             length -= rc;
120         }
121     } while (length > 0);
122     
123     close(fd);
124 #elif defined(OS2)
125     static UCHAR randbyte();
126     unsigned int idx;
127
128     for (idx=0; idx<length; idx++)
129         buf[idx] = randbyte();
130
131 #elif defined(HAVE_EGD)
132     /* use EGD-compatible socket daemon (such as EGD or PRNGd).
133      * message format:
134      * 0x00 (get entropy level)
135      *   0xMM (msb) 0xmm 0xll 0xLL (lsb)
136      * 0x01 (read entropy nonblocking) 0xNN (bytes requested)
137      *   0xMM (bytes granted) MM bytes
138      * 0x02 (read entropy blocking) 0xNN (bytes desired)
139      *   [block] NN bytes
140      * 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data) 
141      *      NN bytes
142      * (no response - write only) 
143      * 0x04 (report PID)
144      *   0xMM (length of PID string, not null-terminated) MM chars
145      */
146     static const char *egd_sockets[] = { EGD_DEFAULT_SOCKET, NULL };
147     const char **egdsockname = NULL;
148
149     int egd_socket, egd_path_len, rv, bad_errno;
150     struct sockaddr_un addr;
151     apr_socklen_t egd_addr_len;
152     apr_size_t resp_expected;
153     unsigned char req[2], resp[255];
154     unsigned char *curbuf = buf;
155
156     for (egdsockname = egd_sockets; *egdsockname && length > 0; egdsockname++) {
157         egd_path_len = strlen(*egdsockname);
158         
159         if (egd_path_len > sizeof(addr.sun_path)) {
160             return APR_EINVAL;
161         }
162
163         memset(&addr, 0, sizeof(struct sockaddr_un));
164         addr.sun_family = AF_UNIX;
165         memcpy(addr.sun_path, *egdsockname, egd_path_len);
166         egd_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) + 
167           egd_path_len; 
168
169         egd_socket = socket(PF_UNIX, SOCK_STREAM, 0);
170
171         if (egd_socket == -1) {
172             return errno;
173         }
174
175         rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len);
176
177         if (rv == -1) {
178             bad_errno = errno;
179             continue;
180         }
181
182         /* EGD can only return 255 bytes of data at a time.  Silly.  */ 
183         while (length > 0) {
184             apr_ssize_t srv;
185             req[0] = 2; /* We'll block for now. */
186             req[1] = length > 255 ? 255: length;
187
188             srv = write(egd_socket, req, 2);
189             if (srv == -1) {
190                 bad_errno = errno;
191                 shutdown(egd_socket, SHUT_RDWR);
192                 close(egd_socket);
193                 break;
194             }
195
196             if (srv != 2) {
197                 shutdown(egd_socket, SHUT_RDWR);
198                 close(egd_socket);
199                 return APR_EGENERAL;
200             }
201             
202             resp_expected = req[1];
203             srv = read(egd_socket, resp, resp_expected);
204             if (srv == -1) {
205                 bad_errno = errno;
206                 shutdown(egd_socket, SHUT_RDWR);
207                 close(egd_socket);
208                 return bad_errno;
209             }
210             
211             memcpy(curbuf, resp, srv);
212             curbuf += srv;
213             length -= srv;
214         }
215         
216         shutdown(egd_socket, SHUT_RDWR);
217         close(egd_socket);
218     }
219
220     if (length > 0) {
221         /* We must have iterated through the list of sockets,
222          * and no go. Return the errno.
223          */
224         return bad_errno;
225     }
226
227 #elif defined(HAVE_TRUERAND) /* use truerand */
228
229     extern int randbyte(void);  /* from the truerand library */
230     unsigned int idx;
231
232     /* this will increase the startup time of the server, unfortunately...
233      * (generating 20 bytes takes about 8 seconds)
234      */
235     for (idx=0; idx<length; idx++)
236         buf[idx] = (unsigned char) randbyte();
237
238 #endif  /* DEV_RANDOM */
239
240     return APR_SUCCESS;
241 }
242
243 #undef  STR
244 #undef  XSTR
245
246 #ifdef OS2
247 #include "randbyte_os2.inc"
248 #endif
249
250 #endif /* APR_HAS_RANDOM */