Coverage Report

Created: 2023-03-26 06:28

/src/httpd/srclib/apr/misc/unix/rand.c
Line
Count
Source (jump to first uncovered line)
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
#if defined(SYS_RANDOM)
47
#if defined(HAVE_SYS_RANDOM_H) && \
48
    defined(HAVE_GETRANDOM)
49
50
#include <sys/random.h>
51
#define USE_GETRANDOM
52
53
#elif defined(HAVE_SYS_SYSCALL_H) && \
54
      defined(HAVE_LINUX_RANDOM_H) && \
55
      defined(HAVE_DECL_SYS_GETRANDOM) && \
56
      HAVE_DECL_SYS_GETRANDOM
57
58
#ifndef _GNU_SOURCE
59
#define _GNU_SOURCE
60
#endif
61
#include <unistd.h>
62
#include <sys/syscall.h>
63
#include <linux/random.h>
64
#define getrandom(buf, buflen, flags) \
65
    syscall(SYS_getrandom, (buf), (buflen), (flags))
66
#define USE_GETRANDOM
67
68
#endif /* HAVE_SYS_RANDOM_H */
69
#endif /* SYS_RANDOM */
70
71
#ifndef SHUT_RDWR
72
#define SHUT_RDWR 2
73
#endif
74
75
#if APR_HAS_OS_UUID
76
77
#if defined(HAVE_UUID_CREATE)
78
79
APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
80
{
81
    uint32_t rv;
82
    uuid_t g;
83
84
    uuid_create(&g, &rv);
85
86
    if (rv != uuid_s_ok)
87
        return APR_EGENERAL;
88
89
    memcpy(uuid_data, &g, sizeof(uuid_t));
90
91
    return APR_SUCCESS;
92
}
93
94
#elif defined(HAVE_UUID_GENERATE)
95
96
APR_DECLARE(apr_status_t) apr_os_uuid_get(unsigned char *uuid_data)
97
0
{
98
0
    uuid_t g;
99
100
0
    uuid_generate(g);
101
102
0
    memcpy(uuid_data, g, sizeof(uuid_t));
103
104
0
    return APR_SUCCESS;
105
0
}
106
#endif
107
108
#endif /* APR_HAS_OS_UUID */
109
110
#if APR_HAS_RANDOM
111
112
APR_DECLARE(apr_status_t) apr_generate_random_bytes(unsigned char *buf,
113
                                                    apr_size_t length)
114
0
{
115
#if defined(HAVE_EGD)
116
    /* use EGD-compatible socket daemon (such as EGD or PRNGd).
117
     * message format:
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)
123
     *   [block] NN bytes
124
     * 0x03 (write entropy) 0xMM 0xLL (bits of entropy) 0xNN (bytes of data)
125
     *      NN bytes
126
     * (no response - write only)
127
     * 0x04 (report PID)
128
     *   0xMM (length of PID string, not null-terminated) MM chars
129
     */
130
    static const char *egd_sockets[] = { EGD_DEFAULT_SOCKET, NULL };
131
    const char **egdsockname = NULL;
132
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;
139
140
    for (egdsockname = egd_sockets; *egdsockname && length > 0; egdsockname++) {
141
        egd_path_len = strlen(*egdsockname);
142
143
        if (egd_path_len > sizeof(addr.sun_path)) {
144
            return APR_EINVAL;
145
        }
146
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) +
151
          egd_path_len;
152
153
        egd_socket = socket(PF_UNIX, SOCK_STREAM, 0);
154
155
        if (egd_socket == -1) {
156
            return errno;
157
        }
158
159
        rv = connect(egd_socket, (struct sockaddr*)&addr, egd_addr_len);
160
161
        if (rv == -1) {
162
            bad_errno = errno;
163
            continue;
164
        }
165
166
        /* EGD can only return 255 bytes of data at a time.  Silly.  */
167
        while (length > 0) {
168
            apr_ssize_t srv;
169
            req[0] = 2; /* We'll block for now. */
170
            req[1] = length > 255 ? 255: length;
171
172
            srv = write(egd_socket, req, 2);
173
            if (srv == -1) {
174
                bad_errno = errno;
175
                shutdown(egd_socket, SHUT_RDWR);
176
                close(egd_socket);
177
                break;
178
            }
179
180
            if (srv != 2) {
181
                shutdown(egd_socket, SHUT_RDWR);
182
                close(egd_socket);
183
                return APR_EGENERAL;
184
            }
185
186
            resp_expected = req[1];
187
            srv = read(egd_socket, resp, resp_expected);
188
            if (srv == -1) {
189
                bad_errno = errno;
190
                shutdown(egd_socket, SHUT_RDWR);
191
                close(egd_socket);
192
                return bad_errno;
193
            }
194
195
            memcpy(curbuf, resp, srv);
196
            curbuf += srv;
197
            length -= srv;
198
        }
199
200
        shutdown(egd_socket, SHUT_RDWR);
201
        close(egd_socket);
202
    }
203
204
    if (length > 0) {
205
        /* We must have iterated through the list of sockets,
206
         * and no go. Return the errno.
207
         */
208
        return bad_errno;
209
    }
210
211
#elif defined(SYS_RANDOM) && defined(USE_GETRANDOM)
212
213
0
    do {
214
0
        int rc;
215
216
0
        rc = getrandom(buf, length, 0);
217
0
        if (rc == -1) {
218
0
            if (errno == EINTR) {
219
0
                continue;
220
0
            }
221
0
            return errno;
222
0
        }
223
224
0
        buf += rc;
225
0
        length -= rc;
226
0
    } while (length > 0);
227
228
#elif defined(SYS_RANDOM) && defined(HAVE_ARC4RANDOM_BUF)
229
230
    arc4random_buf(buf, length);
231
232
#elif defined(DEV_RANDOM)
233
234
    int fd = -1;
235
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. */
239
    do {
240
        apr_ssize_t rc;
241
242
        if (fd == -1)
243
            if ((fd = open(DEV_RANDOM, O_RDONLY)) == -1)
244
                return errno;
245
246
        do {
247
            rc = read(fd, buf, length);
248
        } while (rc == -1 && errno == EINTR);
249
250
        if (rc < 0) {
251
            int errnum = errno;
252
            close(fd);
253
            return errnum;
254
        }
255
        else if (rc == 0) {
256
            close(fd);
257
            fd = -1; /* force open() again */
258
        }
259
        else {
260
            buf += rc;
261
            length -= rc;
262
        }
263
    } while (length > 0);
264
265
    close(fd);
266
267
#elif defined(OS2)
268
269
    static UCHAR randbyte();
270
    unsigned int idx;
271
272
    for (idx=0; idx<length; idx++)
273
  buf[idx] = randbyte();
274
275
#elif defined(HAVE_TRUERAND) /* use truerand */
276
277
    extern int randbyte(void);  /* from the truerand library */
278
    unsigned int idx;
279
280
    /* this will increase the startup time of the server, unfortunately...
281
     * (generating 20 bytes takes about 8 seconds)
282
     */
283
    for (idx=0; idx<length; idx++)
284
  buf[idx] = (unsigned char) randbyte();
285
286
#else
287
288
#error APR_HAS_RANDOM defined with no implementation
289
290
#endif  /* DEV_RANDOM */
291
292
0
    return APR_SUCCESS;
293
0
}
294
295
#undef  STR
296
#undef  XSTR
297
298
#ifdef OS2
299
#include "randbyte_os2.inc"
300
#endif
301
302
#endif /* APR_HAS_RANDOM */