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 54APR_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 71APR_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 87APR_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