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
apr_os_uuid_get(unsigned char * uuid_data)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
apr_os_uuid_get(unsigned char * uuid_data)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
apr_generate_random_bytes(unsigned char * buf,apr_size_t length)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 */
251