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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define APR_WANT_MEMFUNC
19 #include "apr_general.h"
21 #include "apr_arch_misc.h"
23 #if APR_HAVE_SYS_TYPES_H
24 #include <sys/types.h>
26 #if APR_HAVE_SYS_SOCKET_H
27 #include <sys/socket.h>
38 #if defined(HAVE_UUID_H)
40 #elif defined(HAVE_UUID_UUID_H)
41 #include <uuid/uuid.h>
42 #elif defined(HAVE_SYS_UUID_H)
46 #if defined(SYS_RANDOM)
47 #if defined(HAVE_SYS_RANDOM_H) && \
48 defined(HAVE_GETRANDOM)
50 #include <sys/random.h>
53 #elif defined(HAVE_SYS_SYSCALL_H) && \
54 defined(HAVE_LINUX_RANDOM_H) && \
55 defined(HAVE_DECL_SYS_GETRANDOM) && \
56 HAVE_DECL_SYS_GETRANDOM
62 #include <sys/syscall.h>
63 #include <linux/random.h>
64 #define getrandom(buf, buflen, flags) \
65 syscall(SYS_getrandom, (buf), (buflen), (flags))
68 #endif /* HAVE_SYS_RANDOM_H */
69 #endif /* SYS_RANDOM */
77 #if defined(HAVE_UUID_CREATE)
79 APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
89 memcpy(uuid_data, &g, sizeof(uuid_t));
94 #elif defined(HAVE_UUID_GENERATE)
96 APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
102 memcpy(uuid_data, g, sizeof(uuid_t));
108 #endif /* APR_HAS_OS_UUID */
112 APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf,
115 #if defined(HAVE_EGD)
116 /* use EGD-compatible socket daemon (such as EGD or PRNGd).
118 * 0x00 (get entropy level)
119 * 0xMM (msb) 0xmm 0xll 0xLL (lsb)
120 * 0x01 (read entropy nonblocking) 0xNN (bytes requested)
121 * 0xMM (bytes granted) MM bytes
122 * 0x02 (read entropy blocking) 0xNN (bytes desired)
124 * 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data)
126 * (no response - write only)
128 * 0xMM (length of PID string, not null-terminated) MM chars
130 static const char *egd_sockets[] = { EGD_DEFAULT_SOCKET, NULL };
131 const char **egdsockname = NULL;
133 int egd_socket, egd_path_len, rv, bad_errno;
134 struct sockaddr_un addr;
135 apr_socklen_t egd_addr_len;
136 apr_size_t resp_expected;
137 unsigned char req[2], resp[255];
138 unsigned char *curbuf = buf;
140 for (egdsockname = egd_sockets; *egdsockname && length > 0; egdsockname++) {
141 egd_path_len = strlen(*egdsockname);
143 if (egd_path_len > sizeof(addr.sun_path)) {
147 memset(&addr, 0, sizeof(struct sockaddr_un));
148 addr.sun_family = AF_UNIX;
149 memcpy(addr.sun_path, *egdsockname, egd_path_len);
150 egd_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) +
153 egd_socket = socket(PF_UNIX, SOCK_STREAM, 0);
155 if (egd_socket == -1) {
159 rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len);
166 /* EGD can only return 255 bytes of data at a time. Silly. */
169 req[0] = 2; /* We'll block for now. */
170 req[1] = length > 255 ? 255: length;
172 srv = write(egd_socket, req, 2);
175 shutdown(egd_socket, SHUT_RDWR);
181 shutdown(egd_socket, SHUT_RDWR);
186 resp_expected = req[1];
187 srv = read(egd_socket, resp, resp_expected);
190 shutdown(egd_socket, SHUT_RDWR);
195 memcpy(curbuf, resp, srv);
200 shutdown(egd_socket, SHUT_RDWR);
205 /* We must have iterated through the list of sockets,
206 * and no go. Return the errno.
211 #elif defined(SYS_RANDOM) && defined(USE_GETRANDOM)
216 rc = getrandom(buf, length, 0);
218 if (errno == EINTR) {
226 } while (length > 0);
228 #elif defined(SYS_RANDOM) && defined(HAVE_ARC4RANDOM_BUF)
230 arc4random_buf(buf, length);
232 #elif defined(DEV_RANDOM)
236 /* On BSD/OS 4.1, /dev/random gives out 8 bytes at a time, then
237 * gives EOF, so reading 'length' bytes may require opening the
238 * device several times. */
243 if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1)
247 rc = read(fd, buf, length);
248 } while (rc == -1 && errno == EINTR);
257 fd = -1; /* force open() again */
263 } while (length > 0);
269 static UCHAR randbyte();
272 for (idx=0; idx<length; idx++)
273 buf[idx] = randbyte();
275 #elif defined(HAVE_TRUERAND) /* use truerand */
277 extern int randbyte(void); /* from the truerand library */
280 /* this will increase the startup time of the server, unfortunately...
281 * (generating 20 bytes takes about 8 seconds)
283 for (idx=0; idx<length; idx++)
284 buf[idx] = (unsigned char) randbyte();
288 #error APR_HAS_RANDOM defined with no implementation
290 #endif /* DEV_RANDOM */
299 #include "randbyte_os2.inc"
302 #endif /* APR_HAS_RANDOM */