1251875Speter/* Licensed to the Apache Software Foundation (ASF) under one or more
2251875Speter * contributor license agreements.  See the NOTICE file distributed with
3251875Speter * this work for additional information regarding copyright ownership.
4251875Speter * The ASF licenses this file to You under the Apache License, Version 2.0
5251875Speter * (the "License"); you may not use this file except in compliance with
6251875Speter * the License.  You may obtain a copy of the License at
7251875Speter *
8251875Speter *     http://www.apache.org/licenses/LICENSE-2.0
9251875Speter *
10251875Speter * Unless required by applicable law or agreed to in writing, software
11251875Speter * distributed under the License is distributed on an "AS IS" BASIS,
12251875Speter * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13251875Speter * See the License for the specific language governing permissions and
14251875Speter * limitations under the License.
15251875Speter */
16251875Speter
17251875Speter#define APR_WANT_MEMFUNC
18251875Speter#include "apr_want.h"
19251875Speter#include "apr_general.h"
20251875Speter
21251875Speter#include "apr_arch_misc.h"
22251875Speter#include <sys/stat.h>
23251875Speter#if APR_HAVE_SYS_TYPES_H
24251875Speter#include <sys/types.h>
25251875Speter#endif
26251875Speter#if APR_HAVE_SYS_SOCKET_H
27251875Speter#include <sys/socket.h>
28251875Speter#endif
29251875Speter#if APR_HAVE_FCNTL_H
30251875Speter#include <fcntl.h>
31251875Speter#endif
32251875Speter#if APR_HAVE_UNISTD_H
33251875Speter#include <unistd.h>
34251875Speter#endif
35251875Speter#if APR_HAVE_SYS_UN_H
36251875Speter#include <sys/un.h>
37251875Speter#endif
38251875Speter#if defined(HAVE_UUID_H)
39251875Speter#include <uuid.h>
40251875Speter#elif defined(HAVE_UUID_UUID_H)
41251875Speter#include <uuid/uuid.h>
42251875Speter#elif defined(HAVE_SYS_UUID_H)
43251875Speter#include <sys/uuid.h>
44251875Speter#endif
45251875Speter
46251875Speter#ifndef SHUT_RDWR
47251875Speter#define SHUT_RDWR 2
48251875Speter#endif
49251875Speter
50251875Speter#if APR_HAS_OS_UUID
51251875Speter
52251875Speter#if defined(HAVE_UUID_CREATE)
53251875Speter
54251875SpeterAPR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
55251875Speter{
56251875Speter    uint32_t rv;
57251875Speter    uuid_t g;
58251875Speter
59251875Speter    uuid_create(&g, &rv);
60251875Speter
61251875Speter    if (rv != uuid_s_ok)
62251875Speter        return APR_EGENERAL;
63251875Speter
64251875Speter    memcpy(uuid_data, &g, sizeof(uuid_t));
65251875Speter
66251875Speter    return APR_SUCCESS;
67251875Speter}
68251875Speter
69251875Speter#elif defined(HAVE_UUID_GENERATE)
70251875Speter
71251875SpeterAPR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
72251875Speter{
73251875Speter    uuid_t g;
74251875Speter
75251875Speter    uuid_generate(g);
76251875Speter
77251875Speter    memcpy(uuid_data, g, sizeof(uuid_t));
78251875Speter
79251875Speter    return APR_SUCCESS;
80251875Speter}
81251875Speter#endif
82251875Speter
83251875Speter#endif /* APR_HAS_OS_UUID */
84251875Speter
85251875Speter#if APR_HAS_RANDOM
86251875Speter
87251875SpeterAPR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf,
88251875Speter                                                    apr_size_t length)
89251875Speter{
90251875Speter#ifdef DEV_RANDOM
91251875Speter
92251875Speter    int fd = -1;
93251875Speter
94251875Speter    /* On BSD/OS 4.1, /dev/random gives out 8 bytes at a time, then
95251875Speter     * gives EOF, so reading 'length' bytes may require opening the
96251875Speter     * device several times. */
97251875Speter    do {
98251875Speter        apr_ssize_t rc;
99251875Speter
100251875Speter        if (fd == -1)
101251875Speter            if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1)
102251875Speter                return errno;
103251875Speter
104251875Speter        do {
105251875Speter            rc = read(fd, buf, length);
106251875Speter        } while (rc == -1 && errno == EINTR);
107251875Speter
108251875Speter        if (rc < 0) {
109251875Speter            int errnum = errno;
110251875Speter            close(fd);
111251875Speter            return errnum;
112251875Speter        }
113251875Speter        else if (rc == 0) {
114251875Speter            close(fd);
115251875Speter            fd = -1; /* force open() again */
116251875Speter        }
117251875Speter        else {
118251875Speter            buf += rc;
119251875Speter            length -= rc;
120251875Speter        }
121251875Speter    } while (length > 0);
122251875Speter
123251875Speter    close(fd);
124251875Speter#elif defined(OS2)
125251875Speter    static UCHAR randbyte();
126251875Speter    unsigned int idx;
127251875Speter
128251875Speter    for (idx=0; idx<length; idx++)
129251875Speter	buf[idx] = randbyte();
130251875Speter
131251875Speter#elif defined(HAVE_EGD)
132251875Speter    /* use EGD-compatible socket daemon (such as EGD or PRNGd).
133251875Speter     * message format:
134251875Speter     * 0x00 (get entropy level)
135251875Speter     *   0xMM (msb) 0xmm 0xll 0xLL (lsb)
136251875Speter     * 0x01 (read entropy nonblocking) 0xNN (bytes requested)
137251875Speter     *   0xMM (bytes granted) MM bytes
138251875Speter     * 0x02 (read entropy blocking) 0xNN (bytes desired)
139251875Speter     *   [block] NN bytes
140251875Speter     * 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data)
141251875Speter     *      NN bytes
142251875Speter     * (no response - write only)
143251875Speter     * 0x04 (report PID)
144251875Speter     *   0xMM (length of PID string, not null-terminated) MM chars
145251875Speter     */
146251875Speter    static const char *egd_sockets[] = { EGD_DEFAULT_SOCKET, NULL };
147251875Speter    const char **egdsockname = NULL;
148251875Speter
149251875Speter    int egd_socket, egd_path_len, rv, bad_errno;
150251875Speter    struct sockaddr_un addr;
151251875Speter    apr_socklen_t egd_addr_len;
152251875Speter    apr_size_t resp_expected;
153251875Speter    unsigned char req[2], resp[255];
154251875Speter    unsigned char *curbuf = buf;
155251875Speter
156251875Speter    for (egdsockname = egd_sockets; *egdsockname && length > 0; egdsockname++) {
157251875Speter        egd_path_len = strlen(*egdsockname);
158251875Speter
159251875Speter        if (egd_path_len > sizeof(addr.sun_path)) {
160251875Speter            return APR_EINVAL;
161251875Speter        }
162251875Speter
163251875Speter        memset(&addr, 0, sizeof(struct sockaddr_un));
164251875Speter        addr.sun_family = AF_UNIX;
165251875Speter        memcpy(addr.sun_path, *egdsockname, egd_path_len);
166251875Speter        egd_addr_len = APR_OFFSETOF(struct sockaddr_un, sun_path) +
167251875Speter          egd_path_len;
168251875Speter
169251875Speter        egd_socket = socket(PF_UNIX, SOCK_STREAM, 0);
170251875Speter
171251875Speter        if (egd_socket == -1) {
172251875Speter            return errno;
173251875Speter        }
174251875Speter
175251875Speter        rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len);
176251875Speter
177251875Speter        if (rv == -1) {
178251875Speter            bad_errno = errno;
179251875Speter            continue;
180251875Speter        }
181251875Speter
182251875Speter        /* EGD can only return 255 bytes of data at a time.  Silly.  */
183251875Speter        while (length > 0) {
184251875Speter            apr_ssize_t srv;
185251875Speter            req[0] = 2; /* We'll block for now. */
186251875Speter            req[1] = length > 255 ? 255: length;
187251875Speter
188251875Speter            srv = write(egd_socket, req, 2);
189251875Speter            if (srv == -1) {
190251875Speter                bad_errno = errno;
191251875Speter                shutdown(egd_socket, SHUT_RDWR);
192251875Speter                close(egd_socket);
193251875Speter                break;
194251875Speter            }
195251875Speter
196251875Speter            if (srv != 2) {
197251875Speter                shutdown(egd_socket, SHUT_RDWR);
198251875Speter                close(egd_socket);
199251875Speter                return APR_EGENERAL;
200251875Speter            }
201251875Speter
202251875Speter            resp_expected = req[1];
203251875Speter            srv = read(egd_socket, resp, resp_expected);
204251875Speter            if (srv == -1) {
205251875Speter                bad_errno = errno;
206251875Speter                shutdown(egd_socket, SHUT_RDWR);
207251875Speter                close(egd_socket);
208251875Speter                return bad_errno;
209251875Speter            }
210251875Speter
211251875Speter            memcpy(curbuf, resp, srv);
212251875Speter            curbuf += srv;
213251875Speter            length -= srv;
214251875Speter        }
215251875Speter
216251875Speter        shutdown(egd_socket, SHUT_RDWR);
217251875Speter        close(egd_socket);
218251875Speter    }
219251875Speter
220251875Speter    if (length > 0) {
221251875Speter        /* We must have iterated through the list of sockets,
222251875Speter         * and no go. Return the errno.
223251875Speter         */
224251875Speter        return bad_errno;
225251875Speter    }
226251875Speter
227251875Speter#elif defined(HAVE_TRUERAND) /* use truerand */
228251875Speter
229251875Speter    extern int randbyte(void);	/* from the truerand library */
230251875Speter    unsigned int idx;
231251875Speter
232251875Speter    /* this will increase the startup time of the server, unfortunately...
233251875Speter     * (generating 20 bytes takes about 8 seconds)
234251875Speter     */
235251875Speter    for (idx=0; idx<length; idx++)
236251875Speter	buf[idx] = (unsigned char) randbyte();
237251875Speter
238251875Speter#endif	/* DEV_RANDOM */
239251875Speter
240251875Speter    return APR_SUCCESS;
241251875Speter}
242251875Speter
243251875Speter#undef	STR
244251875Speter#undef	XSTR
245251875Speter
246251875Speter#ifdef OS2
247251875Speter#include "randbyte_os2.inc"
248251875Speter#endif
249251875Speter
250251875Speter#endif /* APR_HAS_RANDOM */
251